前言
先說明每個方法如何使用
- 三個方法都是為了改變方法執行的 this 指向
- call、apply是呼叫後改變 this 立即執行
- bind 是返回一個改變 this 執行的函式,在實際呼叫時確定 this 並執行
call 使用
function add (a, b) {
console.log(this + a + b)
}
add.call(1, 2, 3)
複製程式碼
- 需要實現執行 add 函式時改變其 this 指向,如果直接執行 add(2, 3)則 this 指向為 window,確定 this 指向就看誰呼叫了函式,那麼需要實現 1.add(2, 3),this則為1
- 而 1 是 number 基本型別不會有方法,所以當傳入的this不是物件型別就先將 this 包裝為物件,然後為 this 新增函式(要改變 this 指向的函式),接著執行 this.f(params) 呼叫時就改變了原函式的 this 指向
call 實現
將要執行的函式新增到this
屬性上,然後呼叫 this.f(...params),即實現了f的this執行為傳入的 this的呼叫
Function.prototype.call = function(thisValue, ...params) {
if (typeof thisValue !== 'object') {
thisValue = new Object(thisValue)
}
let context = this
thisValue.f = context
// 定義為不可列舉
Object.defineProperty(thisValue, 'f', {
enumerable: false,
get () {
return context
}
})
thisValue.f(...params)
// 刪除為 this 臨時新增的函式
delete thisValue.f
}
複製程式碼
apply 使用
function add (a, b) {
console.log(this + a + b)
}
add.apply(1, [2, 3])
複製程式碼
apply 實現
Function.prototype.apply = function (thisValue, params) {
if (thisValue !== 'object') {
thisValue = new Object(thisValue)
}
let context = this
thisValue.f = context
Object.defineProperty(thisValue, 'f', {
enumerable: false,
get () {
return context
}
})
thisValue.f(...params)
delete thisValue.f
}
複製程式碼
bind 使用
function add (a, b, c) {
console.log(this)
console.log(a, b)
console.log(c)
}
let add2 = add.bind({ value: 1 }) // 返回一個改變 this 指向的函式
add2(2, 3) // 真實執行
複製程式碼
返回一個改變 this 執行的函式
bind 實現
將要執行的函式新增到this
的屬性上, 然後返回一個可接受引數的函式,該函式內部執行 this.f(arg1.concat(arg2))
,執行函式,引數為繫結時的引數concat
執行時的引數
Function.prototype.bind = function(thisValue, ...args) {
if (typeof thisValue !== 'object') {
thisValue = new Object(thisValue)
}
let context = this
thisValue.f = context
Object.defineProperty(thisValue, 'f', {
enumerable: false,
get () {
return context
}
})
return function (...args2) {
thisValue.f(...args.concat(args2))
}
}
複製程式碼
✿✿ヽ(°▽°)ノ✿ 完成啦