JavaScript自我實現系列(2):call,apply,bind

大眾美男典範發表於2018-12-03

call, apply, bind

call

使用:

// 1. 定義一個女孩叫x
var x = {
    // 她的身高是170
    height: 170,
    // 她有一雙高跟鞋,作用是讓她長高10釐米
    highShoes: function(){
        this.height += 10
    }
}
// x穿上高跟鞋
x.highShoes()
// 於是身高變成了180
console.log(x.height) // 180

// 2. 定義一個帥哥叫q
var q = {
    // 他的身高是160,...
    height: 160
}
// q也想增高一下
// q.highShoes() // 但是報錯了:Uncaught TypeError: q.highShoes is not a function
// 因為q沒有高跟鞋

// 3. q借用x的高跟鞋
x.highShoes.call(q)
// 我也長高啦!
console.log(q.height) // 170

// 這裡的this就是指高跟鞋的擁有者,即x女孩
// 如果不透過call改變this的指向,這個高跟鞋的擁有者永遠是x
// q透過call借來了x的高跟鞋
複製程式碼

所以,call的作用就是:

高跟鞋搬運工

改變this的指向

apply, bind的作用同上。

apply, bind

和call的區別:

// 定義一個主人翁
var x = {}

// 定義一個化妝函式
function makeUp(color, style) {
    // 塗什麼顏色的口紅
    this.lips = color
    // 留什麼樣式的髮型
    this.hair = style
}

// 用call:
makeUp.call(x, 'red', 'longHair')

// 用apply:
makeUp.apply(x, ['red', 'longHair'])

// 用bind:
makeUp.bind(x, 'red', 'longHair')()
複製程式碼

第一個引數為null時:

makeUp.call(null, 'yellow', 'shortHair')
// 非嚴格模式下,第一個引數是null,this指向的window
console.log(window.lips, window.hair) // "yellow", "shortHair"
複製程式碼

自我實現

實現一個call函式:

/*
*  call的工作原理就是
*  將一個函式的this指向某個上下文,從而使這個上下文可以呼叫這個函式。
*  
*  函式就像某個工具,
*  call要完成的就是一個借用的過程。
*  
*  一曲《借我》送給大家。
*/ 

Function.prototype.lendMe = function (borrower) {
    // 1. 誰借?預設是window借。
    var borrower = borrower || window
    // 2. 借啥?哪個函式呼叫的lendMe,lendMe的this就是這個函式。
    // 當把這個函式賦值給borrower的方法時,就已經借到了。
    borrower.tool = this
    // 獲得傳給函式的引數
    var args = [...arguments].slice(1)
    // 3. 借用。前面是借,現在是用。
    var result = borrower.tool(...args)
    // 4. 出來借總是要還的。
    delete borrower.tool
    // 5. 用完的東西給你。
    return result
}
複製程式碼

apply和call幾乎一樣:

Function.prototype.myApply = function (borrower) {
    var borrower = borrower || window
    borrower.tool = this
    // 第二個引數是一個陣列
    var arg = arguments[1] || []
    var result = borrower.tool(...arg)
    delete borrower.tool
    return result
}
複製程式碼

實現一個bind函式:

/*
*  這裡對bind函式的實現,
*  就是利用閉包,返回了一個準備透過apply的方式執行的函式。
*/
Function.prototype.myBind = function (borrower) {
    if(typeof this !== 'function'){
        throw new TypeError('Error')
    }
    var tool = this
    var args = [...arguments].slice(1)
    return function() {
        return tool.apply(borrower, args.concat(...arguments))
    }
}
複製程式碼

JavaScript自我實現系列 點選檢視

相關文章