call apply bind 區(qū)別
這三個(gè)都是Function中自帶的三個(gè)方法,都是可以改變this指向的,在Function.prototype上 可以打印看一下
console.dir(Function.prototype); //你會(huì)看的這三個(gè)屬性以及arguments,toString等屬性
call,apply的特點(diǎn)
- 如果傳入的是值類型 this指向?qū)?yīng)類型的構(gòu)造函數(shù)創(chuàng)建的實(shí)例
- 如果傳入的是對(duì)象 this指向?qū)ο蟊旧?/li>
- 如果傳入 undefined 或者 null this為空對(duì)象
call apply bind 用法
let name = "張三";
let Person = {
name: "法外狂徒",
age: 18,
};
function say(lag) {
console.log(this);
console.log(`my name is ${this.name},my age is ${this.age},我說${lag}`);
}
say("I love you"); //此時(shí)會(huì)打印Window my name is 張三,my age is undefined,我說I love you;此時(shí)this指的是window可以獲取到全局變量name
//call
say.call(Person , "I love you"); //my name is 法外狂徒,my age is 18,我說I love you, 此時(shí)函數(shù)中this就指向了Person
//apply
say.apply(Person, ["I love you"]); //my name is 法外狂徒,my age is 18,我說I love you 和call除了參數(shù)傳數(shù)組外沒什么不同
//bind
say.bind(Person, "I love you")(); //my name is 法外狂徒,my age is 18,我說I love you;bind返回的是一個(gè)函數(shù),需要執(zhí)行
實(shí)現(xiàn)call
在Function原型上加上自己的方法myCall;具體細(xì)節(jié)在注釋
Function.prototype.myCall = function (ctx, args) {
ctx = ctx ? Object(ctx) : window;
args = args || [];
const key = Symbol(); //創(chuàng)建一個(gè)獨(dú)一無二的key以免覆蓋原有屬性
ctx[key] = this; //將this賦值到傳入對(duì)象ctx的某一個(gè)屬性上;this指的是函數(shù),結(jié)合上下文這里this就是say函數(shù)
const result = ctx[key](...args); //將入?yún)⒔鈽?gòu)傳入;并用result接收返回值
delete ctx[key]; //用完后將此屬性刪除;不然每次call這個(gè)對(duì)象都會(huì)加個(gè)屬性
return result; //返回函數(shù)返回值
};
//執(zhí)行myCall
say.myCall(Person, ["I love you"]); //my name is 法外狂徒,my age is 18,我說I love you
實(shí)現(xiàn)apply
apply和call只是傳參區(qū)別,稍微修改下即可;直接復(fù)制過來
Function.prototype.myApply = function (ctx, ...args) {
ctx = ctx ? Object(ctx) : window;
args = args || [];
const key = Symbol(); //創(chuàng)建一個(gè)獨(dú)一無二的key以免覆蓋原有屬性
ctx[key] = this; //將this賦值到傳入對(duì)象ctx的某一個(gè)屬性上;this指的是函數(shù),結(jié)合上下文這里this就是say函數(shù)
const result = ctx[key](...args); //將入?yún)⒔鈽?gòu)傳入;并用result接收返回值
delete ctx[key]; //用完后將此屬性刪除;不然沒吃call這個(gè)對(duì)象都會(huì)加個(gè)屬性
return result; //返回函數(shù)返回值
};
//執(zhí)行myApply
say.myApply(Person, "I love you"); //my name is 法外狂徒,my age is 18,我說I love you
實(shí)現(xiàn)bind
bind 是返回一個(gè)函數(shù)
Function.prototype.myBind = function (ctx, ...args) {
ctx = ctx ? Object(ctx) : window;
args = args || [];
const _this =this
return function (...rest) {
const key = Symbol(); //創(chuàng)建一個(gè)獨(dú)一無二的key以免覆蓋原有屬性
console.log(this)//這里的this指向window,因?yàn)榉祷氐氖且粋€(gè)函數(shù),this永遠(yuǎn)指向最后調(diào)用它的那個(gè)對(duì)象,最終調(diào)用這個(gè)函數(shù)的是window
ctx[key] = _this; //將this賦值到傳入對(duì)象ctx的某一個(gè)屬性上;this指的是函數(shù),結(jié)合上下文這里this就是say函數(shù)
const result = ctx[key](...args,...rest); //將入?yún)⒔鈽?gòu)傳入;并用result接收返回值
delete ctx[key]; //用完后將此屬性刪除;不然沒吃call這個(gè)對(duì)象都會(huì)加個(gè)屬性
return result; //返回函數(shù)返回值
};
};
//執(zhí)行myBind
say.myBind(Person, "I love you 1")(); //my name is 法外狂徒,my age is 18,我說I love you