call、bind、apply都是Function原型上的方法,用於改變this的指向
自定義函數
js中的call、bind、apply是用c++代碼實現的,我們這裏使用js代碼做一個模式,沒有把所有的邊界情況考慮進來,僅做一個簡單的實現,三個函數在使用的時候有一些需要注意的地方,在定義的時候需要把這些情況考慮進去
- 當傳入的值是基本數據類型時,call、apply、bind方法會將它轉變成引用數據類型,如傳入的字符串變成了 String 類型,通過Object()可以做這一轉換
- 當沒有傳遞需要改變的this指向時,函數的this指向window(非嚴格模式下)
- 當傳遞的this指向為null、undefined時, 函數的this指向window(非嚴格模式下)
call的實現
定義call函數需要注意
- 第一個參數接收改變後的this指向,從第二個參數開始接收函數執行所需要的參數
實現代碼如下
Function.prototype.iCall = function (thisArg, ...args) {
// 1.獲取執行函數
var fn = this
// 2.將函數綁定到傳遞的對象上
thisArg = thisArg || thisArg.toString() ? Object(thisArg) : window
thisArg.fn = fn
var result = thisArg.fn(...args)
// 3.刪除傳遞對象的fn函數
delete thisArg.fn
// 4.返回結果
return result
}
function foo(...args) {
console.log('綁定的this為:', this)
console.log('傳遞的參數為:', args)
}
var user = {
name: 'alice'
}
// 將foo函數this指向改為user,並傳遞參數1,2,3
foo.iCall(user, 1, 2, 3)
執行結果為
apply的實現
定義apply函數需注意
- 第一個參數接收改變後的this指向,第二個參數接收函數執行所需要的參數組成的【數組】
實現代碼如下
Function.prototype.iApply = function(thisArg, args){
// 1.獲取執行函數
var fn = this
// 2.將函數綁定到傳遞的對象上
thisArg = thisArg || thisArg.toString() ? Object(thisArg) : window
thisArg.fn = fn
var result = thisArg.fn(...args)
// 3.刪除傳遞對象的fn函數
delete thisArg.fn
// 4.返回結果
return result
}
function foo(...args){
console.log('綁定的this為:', this)
console.log('傳遞的參數為:', args)
}
var str = "hello js"
var arr = ['a', 'b', 'c']
foo.iApply(str, arr)
執行結果如下
bind的實現
定義bind函數需注意
- 第一個參數接收改變後的this指向,第二個參數接收函數執行所需要的參數
- bind函數不會立即調用函數,而是返回一個新的函數,新函數仍然可以繼續傳遞參數
Function.prototype.iBind = function (thisArg, ...args) {
// 1.獲取執行函數
var fn = this
// 2.將函數綁定到傳遞的對象上
thisArg = thisArg || thisArg.toString() ? Object(thisArg) : window
thisArg.fn = fn
return function (...params) {
// 3.獲取函數執行的結果
var result = thisArg.fn(...args, ...params)
// 4.刪除傳遞對象的fn函數
delete thisArg.fn
// 5.返回結果
return result
}
}
function foo(...args) {
console.log('綁定的this為:', this)
console.log('傳遞的參數為:', args)
}
var num = 0
var fn = foo.iBind(num, 20, 40)
fn(30, 50)
執行結果如下
以上就是call、bind、apply的實現方法,代碼量不多,但是需要對this的指向比較瞭解,關於this指向也可以看看我其他的博文~