call, apply, bind這三個改變this指向的函數常常被用到,不管是開發仍是面試。瞭解其實現原理,是一名合格的前端程序員必備技能。前端
在自行實現這幾個方法前,你得知道幾個基本的知識點:程序員
call的關鍵兩點: 一、改變上下文指向; 二、傳入多個參數。面試
Function.protoType.myCall = function(content){
// call方法只能是方法才能調用
if(typeof this !== "function"){
throw new TypeError("Error");
}
// 若是沒有指定上下文,默認是全局對象window
// 不要寫成this.window。當this指向發生變化,可能找不到全局對象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的關鍵兩點:一、改變上下文指向; 二、傳入參數數組。 在實現原理上基本和call差很少,主要是參數的區別。數組
Function.protoType.myApply = function(content){
// apply方法只能是方法才能調用
if(typeof this !== "function"){
throw new TypeError("Error");
}
// 若是沒有指定上下文,默認是全局對象window
// 不要寫成this.window。當this指向發生變化,可能找不到全局對象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 的關鍵幾點:一、改變上下文指向;二、傳入多個參數;三、返回的是函數的方法名,不會當即執行。bash
Function.protoType.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;
}
複製代碼
執行:app
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')()
複製代碼
執行結果: 函數
結果完美呈現,以上即是call, apply, bind的簡單實現。