1. call模擬實(shí)現(xiàn)
借用MDN一句話: call() 方法調(diào)用一個(gè)函數(shù), 其具有一個(gè)指定的this值和分別地提供的參數(shù)(參數(shù)的列表)秀姐。
//舉個(gè)例子eg:
var a = "window";
var obj = {a: "obj"};
function getA(b){
console.log(this.a)
console.log(b);
}
getA.call(null, "2"); //window 2 在嚴(yán)格模式下面 會(huì)打印undefined
getA.call(obj, 2); //obj 2
可以看出:
1. 函數(shù)getA中this的指向變了
2. 函數(shù)getA自動(dòng)執(zhí)行了
3. 第二個(gè)參數(shù)之后是傳入的參數(shù)
//代碼實(shí)現(xiàn)
Function.prototype.myCall = function(context){
context = context || window;
context.fn = this;
var args = []; //call 第二個(gè)參數(shù)之后是傳入的值
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
var result = eval('context.fn(' + args +')'); //使用eval執(zhí)行函數(shù)
delete context.fn;
return result;
}
備注:eval 函數(shù)可計(jì)算某個(gè)字符串契吉,并執(zhí)行其中的的 JavaScript 代碼工三。eval 函數(shù)如果傳參是數(shù)組旺拉, 則會(huì)把數(shù)組轉(zhuǎn)換成字符串
var a = [1,2,3];
eval("console.log(" + a + ")") ;// 1 2 3
//es6 實(shí)現(xiàn)
Function.prototype.myCall2 = function(context){
context = context || window;
context.fn = this;
var args = Array.from(arguments).slice(1, arguments.length); //call 第二個(gè)參數(shù)之后是傳入的值
context.fn(...args);
delete context.fn;
return result;
}
2. apply模擬實(shí)現(xiàn)
apply與call實(shí)現(xiàn)方式類似恤磷,唯一區(qū)別就是參數(shù)不同娘锁,apply接受數(shù)組
Function.prototype.myApply = function(context, arr){
context = context || window;
context.fn = this;
var result ;
if(!arr){
result = context.fn();
}else{
result = context.fn(arr)
}
delete context.fn;
return result;
}
3. bind模擬實(shí)現(xiàn)
bind() 方法會(huì)創(chuàng)建一個(gè)新函數(shù)比肄。當(dāng)這個(gè)新函數(shù)被調(diào)用時(shí)忿磅,bind() 的第一個(gè)參數(shù)將作為它運(yùn)行時(shí)的 this痊焊,之后的一序列參數(shù)將會(huì)在傳遞的實(shí)參前傳入作為它的參數(shù)盏袄。(MDN)
Function.prototype.myBind = function(context){
if(typeof this !== "function"){
return new Error("xxx");
}
var self = this;
//緩存bind時(shí)候傳入的參數(shù)
var args = Array.prototype.slice.call(arguments, 1);
var F = function(){};
var fBound = function () {
//獲取新的參數(shù)
var bindArgs = Array.prototype.slice.call(arguments);
//判斷是否是new忿峻,如果是new 則返回這個(gè)實(shí)例
return self.apply(this instanceof F ? this : context, args.concat(bindArgs));
}
//使用架橋函數(shù) 過濾掉原來函數(shù)this上面的值
F.prototype = this.prototype;
fBound.prototype = new F();
return fBound;
}