call, apply, bind這三個改變this指向的函數經常被用到,無論是開發(fā)還是面試。了解其實現原理,是一名合格的前端程序員必備技能。
- 如果還不知道call, apply, bind的基本用法,請先自行百度
動手需知
在自行實現這幾個方法前,你得知道幾個基本的知識點:
- arguments是什么?
借用MDN的說法:arguments對象是所有(非箭頭)函數中都可用的局部變量。你可以使用arguments對象在函數中引用函數的參數。此對象包含傳遞給函數的每個參數 - slice的用法:slice(index)代表從下標index開始截取數組。(其他用法自行查詢去)
那么接下來就是見證奇跡的時刻了。
call的實現
call的關鍵兩點: 1、改變上下文指向; 2、傳入多個參數。
Function.propoType.myCall = function(content){
// call方法只能是方法才能調用
if(typeof this !== "function"){
throw new TypeError("Error");
}
// 如果沒有指定上下文,默認是全局對象window
// 不要寫成this.window。當this指向發(fā)生變化,可能找不到全局對象window
content = content || window;
let fn = Symbol(content); // 避免屬性重復
let args = [...arguments].slice(1)
//改變this指向
content[fn] = this; //給content添加一個方法 指向this
let result = content[fn](...args); //傳入參數
delete content[fn]; // 刪除fn 方法,一個中間變量用完刪除
return result;
}
apply 的實現
apply的關鍵兩點:1、改變上下文指向; 2、傳入參數數組。
在實現原理上基本和call差不多,主要是參數的區(qū)別。
Function.propoType.myApply = function(content){
// apply方法只能是方法才能調用
if(typeof this !== "function"){
throw new TypeError("Error");
}
// 如果沒有指定上下文,默認是全局對象window
// 不要寫成this.window。當this指向發(fā)生變化,可能找不到全局對象window
content = content || window;
let fn = Symbol(content); // 避免屬性重復
let args = [...arguments][1]; // 記住傳入的是數組?。?!
//改變this指向
content[fn] = this; //給content添加一個方法 指向this
let result ;
if(args){
result = content[fn](...args); //傳入參數
}else{
result = content[fn](); //傳入參數
}
delete content[fn]; // 刪除fn 方法,一個中間變量用完刪除
return result;
}
bind 的實現
bind 的關鍵幾點:1、改變上下文指向;2、傳入多個參數;3、返回的是函數的方法名,不會立即執(zhí)行。
Function.propoType.myBind = function(content){
self = this;
// bind方法只能是方法才能調用
if(typeof this !== "function"){
throw new TypeError("Error");
}
// 可以支持柯里化傳參,保存參數
args = [...arguments].slice(1);
function Fn (){
// 考慮需要綁定的函數可能是構造函數,this不會被綁定,但是參數仍然會傳遞。
if(this instanceof Fn){
return self(...args.concat(...arguments));//構造函數直接傳參
}else{
return self.apply(content,args.concat(...arguments));// apply傳的是數組
}
}
return Fn;
}
執(zhí)行:
let Person = {
name: 'Tom',
say(x, y) {
//console.log(this)
console.log(`我叫${this.name}${x}${y}`)
}
}
Person1 = {
name: 'Tom1'
}
Person.say.myCall(Person1, ' call你干嘛', ' 哈哈哈');
Person.say.myApply(Person1, [' apply你干嘛', ' 哈哈哈',]);
Person.say.myBind(Person1, ' bind你干嘛', ' 哈哈哈kk')()
執(zhí)行結果:

結果
結果完美呈現,以上便是call, apply, bind的簡單實現。