學(xué)習(xí)分析call , apply , bind 源碼散罕,及分析分歇。。
在學(xué)習(xí)call欧漱,apply职抡,bind 這三個(gè)API時(shí),他們對(duì)context的指向有修改误甚。
那么就帶著一個(gè)疑問(wèn)來(lái)學(xué)習(xí)這代碼吧8克Α(需要有JS 原型基礎(chǔ))。
我們先實(shí)現(xiàn)下call 能做什么靶草。
function say(){
console.log('my name is ' + this.name + ' , it is ' + this.age);
}
var me = {
name: 'LiaoXiang',
age: 12
}
say(); //my name is , it is undefined
say.call(me); //my name is LiaoXiang , it is 12
看上面的方法蹄胰,我們來(lái)思考一下 是不是在me 這個(gè)方法中擁有say 這個(gè)方法就能實(shí)現(xiàn)?
var me = {
name: 'liaoxiang',
age: 12,
say(){
console.log('my name is ' + this.name + ' , it is ' + this.age);
}
}
me.say(); // my name is liaoxiang , it is 12
根據(jù)上面的思想奕翔,我們是需要在上面注入一個(gè)方法這樣就解決了我們想要處理的問(wèn)題裕寨。
//先實(shí)現(xiàn)這個(gè)
Object.prototype.myCall = function(context){
context = context || window ; // 沒(méi)傳指向window
context.fun = this; // this 指向的是調(diào)用myCall的函數(shù)
/**
*這里如果不刪除context.fun 那么在調(diào)用的時(shí)候永久性的放入的函數(shù)中加入了一個(gè)方法(浪費(fèi)內(nèi)存);
*解決 delete context.fun
**/
var result = context.fun();
delete context.fun ;
return result;
}
say.myCall(me); //my name is LiaoXiang , it is 12 this指向完成!
call apply 的后面的參數(shù)怎么用忘記了 想不忙著寫(xiě)派继,先實(shí)現(xiàn)bind方法宾袜!
已知bind 方法直接改變一個(gè)方法的this 指向
Function.prototype.myBind = function(context){
if(typeof this === 'function'){ //this 調(diào)用myBind的對(duì)象
throw new TypeError(this + 'is function');
}
var self = this;
return self.myCall(context)
}
下面我們是先call和apply 的參數(shù)方法。 從上面的myCall 我們可以聯(lián)想到apply 的指向方法是完全一樣的驾窟,只是在參數(shù)的處理不一樣庆猫,call(obj,arg1,arg2.....), apply(obj,[ ]) 第二個(gè)參數(shù)接受的一個(gè)數(shù)組绅络。
例如: 求一個(gè)數(shù)組中的最大值
Math.max.apply(null, [6,4,8,3,9]);
apply 和 call的用法基本完全一致月培,不過(guò)他們接受的參數(shù)不一樣嘁字。
Object.prototype.myCall = function(context){
context = context || window;
context.fn = this;
let args = Array.from(arguments).slice(1);
let result = context.fn(...args);
delete context.fn;
return result;
}
Object.prototype.myApply = function(context){
context = context || window;
context.fn = this;
if(arguments[1] instanceof Array){
throw new TypeError(arguments[1] + 'is Array');
}else{
let result = context.fn(arguments[1]);
delete context.fn;
return result;
}
}