call, apply, bind這三個改變this指向的函數(shù)經(jīng)常被用到瑰排,無論是開發(fā)還是面試贯要。了解其實現(xiàn)原理,是一名合格的前端程序員必備技能椭住。
- 如果還不知道call, apply, bind的基本用法崇渗,請先自行百度
動手需知
在自行實現(xiàn)這幾個方法前,你得知道幾個基本的知識點:
- arguments是什么京郑?
借用MDN的說法:arguments對象是所有(非箭頭)函數(shù)中都可用的局部變量宅广。你可以使用arguments對象在函數(shù)中引用函數(shù)的參數(shù)。此對象包含傳遞給函數(shù)的每個參數(shù) - slice的用法:slice(index)代表從下標index開始截取數(shù)組些举。(其他用法自行查詢?nèi)ィ?br> 那么接下來就是見證奇跡的時刻了跟狱。
call的實現(xiàn)
call的關鍵兩點: 1、改變上下文指向户魏; 2驶臊、傳入多個參數(shù)挪挤。
Function.propoType.myCall = function(content){
// call方法只能是方法才能調(diào)用
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); //傳入?yún)?shù)
delete content[fn]; // 刪除fn 方法,一個中間變量用完刪除
return result;
}
apply 的實現(xiàn)
apply的關鍵兩點:1笤休、改變上下文指向尖飞; 2、傳入?yún)?shù)數(shù)組店雅。
在實現(xiàn)原理上基本和call差不多政基,主要是參數(shù)的區(qū)別。
Function.propoType.myApply = function(content){
// apply方法只能是方法才能調(diào)用
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]; // 記住傳入的是數(shù)組G戏堋<鼋 !
//改變this指向
content[fn] = this; //給content添加一個方法 指向this
let result ;
if(args){
result = content[fn](...args); //傳入?yún)?shù)
}else{
result = content[fn](); //傳入?yún)?shù)
}
delete content[fn]; // 刪除fn 方法琳袄,一個中間變量用完刪除
return result;
}
bind 的實現(xiàn)
bind 的關鍵幾點:1江场、改變上下文指向;2窖逗、傳入多個參數(shù)址否;3、返回的是函數(shù)的方法名碎紊,不會立即執(zhí)行佑附。
Function.propoType.myBind = function(content){
self = this;
// bind方法只能是方法才能調(diào)用
if(typeof this !== "function"){
throw new TypeError("Error");
}
// 可以支持柯里化傳參,保存參數(shù)
args = [...arguments].slice(1);
function Fn (){
// 考慮需要綁定的函數(shù)可能是構(gòu)造函數(shù)仗考,this不會被綁定音同,但是參數(shù)仍然會傳遞。
if(this instanceof Fn){
return self(...args.concat(...arguments));//構(gòu)造函數(shù)直接傳參
}else{
return self.apply(content,args.concat(...arguments));// apply傳的是數(shù)組
}
}
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í)行結(jié)果:
結(jié)果
結(jié)果完美呈現(xiàn)秃嗜,以上便是call, apply, bind的簡單實現(xiàn)权均。