每個(gè)函數(shù)都有2個(gè)繼承而來(lái)的方法:apply call
作用:在特定作用域中調(diào)用函數(shù)(擴(kuò)充函數(shù)賴(lài)以運(yùn)行的作用域)溃睹,設(shè)置函數(shù)體內(nèi)this對(duì)象的值
好處:對(duì)象不需要與方法有任何耦合關(guān)系
call
接收多個(gè)參數(shù),第一個(gè)為函數(shù)上下文this胰坟,后邊參數(shù)為函數(shù)本身的參數(shù)(call參數(shù)必須逐個(gè)列舉)
call實(shí)現(xiàn):在傳入的對(duì)象上添加這么一個(gè)方法因篇,為了保持對(duì)象,執(zhí)行完后再把這個(gè)方法刪除
call模擬步驟可分為:
第一步:將函數(shù)設(shè)為傳入對(duì)象的屬性
第二步:執(zhí)行該函數(shù)
第三步:刪除該函數(shù)
Function.prototype.call= function(obj, ...arg){
????obj.fn = this;?//此處this是指調(diào)用call的function
????let result = obj.fn(...arg);
????delete obj.fn;
????return result;
}
需注意:指定傳入的this不一定是該函數(shù)執(zhí)行時(shí)真正的this笔横。如果這個(gè)函數(shù)處于非嚴(yán)格模式竞滓,則指定為null和undefined的this值會(huì)自動(dòng)指向全局對(duì)象(瀏覽器中就是window對(duì)象);值為原始值(數(shù)字吹缔,字符串商佑,布爾值)的this會(huì)指向該原始值的自動(dòng)包裝對(duì)象。
Function.prototype.mycall=function(thisArg,...args){
// your code here
thisArg=thisArg ?? window;// thisArg can be null or undefined
thisArg=Object(thisArg);// transform primitive value
let func=Symbol();// create a unique property?
thisArg[func]=this;// assign the function to a unique method created on the context
let res=thisArg[func](...args)// call the method with passed args
delete thisArg[func];// delete this unique method so as to not cause any side effects
return res;
}
apply(運(yùn)行函數(shù)的作用域厢塘,參數(shù)數(shù)組)
argsArray: 一個(gè)數(shù)組或者類(lèi)數(shù)組對(duì)象莉御,其中的數(shù)組元素將作為單獨(dú)的參數(shù)傳給fun函數(shù)。如果該參數(shù)的值為null或undefined俗冻,則表示不需要傳入任何參數(shù)礁叔。從ECMAScript5開(kāi)始可以使用類(lèi)數(shù)組對(duì)象。
Function.prototype.apply = function(obj=window, arr){
? ? obj[fn] = this;
????let result = obj[fn](...arr);
????delete obj[fn];
????return result;
}
Calling?f.bind(someObject)?creates a new function with the same body and scope as?f, but the value of?this?is permanently bound to the first argument of?bind, regardless of how the function is being called.
function f() {
? return this.a;
}
const g = f.bind({ a: "azerty" });
console.log(g()); // azerty
const h = g.bind({ a: "yoo" }); // bind only works once!
console.log(h()); // azerty
const o = { a: 37, f, g, h };
console.log(o.a, o.f(), o.g(), o.h()); // 37 37 azerty azerty
bind:第一個(gè)參數(shù)是函數(shù)上下文迄薄,返回值是一個(gè)函數(shù)的實(shí)例(不會(huì)立即執(zhí)行)琅关,該函數(shù)實(shí)例的this值會(huì)被永久綁定到傳給bind函數(shù)的上下文。
https://www.smashingmagazine.com/2014/01/understanding-javascript-function-prototype-bind/
Function.prototype.bind=function(obj,...args1){
? ? const fn=this讥蔽;
????return function F(...args2){
????????if(fn instanceof F){return new fn(...args1,...args2)} //判斷是否用于構(gòu)造函數(shù)
????????return fn.apply(obj涣易,args1.concat(args2));
????}
}
區(qū)別總結(jié):
當(dāng)使用一個(gè)函數(shù)需要改變this指向的時(shí)候才會(huì)用到call,apply,bind
如果要傳遞的參數(shù)不多冶伞,則可以使用fn.call(thisObj, arg1, arg2 ...)
如果要傳遞的參數(shù)很多新症,則可以用數(shù)組將參數(shù)整理好調(diào)用fn.apply(thisObj, [arg1, arg2 ...])
如果想生成一個(gè)新的函數(shù)長(zhǎng)期綁定某個(gè)函數(shù)給某個(gè)對(duì)象使用,則可以使用:
const newFn = fn.bind(thisObj);
newFn(arg1, arg2...)
注意:綁定函數(shù)(bind函數(shù)返回的新函數(shù))不可以再通過(guò)apply和call改變其this指向响禽,即當(dāng)綁定函數(shù)調(diào)用apply和call改變其this指向時(shí)徒爹,并不能達(dá)到預(yù)期效果荚醒。