バインド、呼び出し、適用がすべてこのポイントを変更するために使用されることはわかっていますが、なぜこのポイントを変更するのですか?次の例を参照してください。
var name="lucy";
let obj={
name:"martin",
say:function () {
console.log(this.name);
}
};
obj.say(); //martin,this指向obj对象
setTimeout(obj.say,0); //lucy,this指向window对象
通常の状況では、sayメソッドのthisはそれを呼び出したobjオブジェクトを指し、タイマーsetTimeoutのsayメソッドのthisは(ブラウザーの)ウィンドウオブジェクトを指していることがわかります。これは、 sayメソッドはinにありますタイマーはコールバック関数として実行されるため、メインスタックに戻って実行すると、グローバル実行コンテキストの環境で実行されますが、sayメソッドのこれがobjを指している必要があります。オブジェクトなので、この点を変更する必要があります。
- 適用方法
applyは2つのパラメーターを受け入れます。最初のパラメーターはこれへのポインターであり、2番目のパラメーターは関数によって受け入れられ、配列の形式で渡されるパラメーターです。最初のパラメーターがnullまたは未定義の場合、デフォルトでウィンドウを指します。 (ブラウザ内)applyメソッドを使用してこのポイントを変更した直後に元の関数が実行され、このメソッドは一時的にこのポイントを1回だけ変更します。
毎日の使用:このポイントを変更します
例:
コールバック関数はこれを以下にバインドします。
var name="martin";
var obj={
name:"lucy",
say:function(year,place){
console.log(this.name+" is "+year+" born from "+place);
}
};
var say=obj.say;
setTimeout(function(){
say.apply(obj,["1996","China"])
} ,0); //lucy is 1996 born from China,this改变指向了obj
say("1996","China") //martin is 1996 born from China,this指向window,说明apply只是临时改变一次this指向
ヒント:パラメーターの受け渡し方法を変更する
例:
配列の最大値を見つけます。
var arr=[1,10,5,8,3];
console.log(Math.max.apply(null, arr)); //10
Math.max関数のパラメーターは、次のようなパラメーターリストです。Math.max(1,10,5,8,3)が渡されるため、配列をパラメーターとして直接使用することはできませんが、適用します。メソッドは配列を使用できます。配列の最大値を直接見つけるために、パラメーターはリストパラメーターに変換されて渡されます。
- メソッドを呼び出す
callメソッドの最初のパラメーターもこれのポイントであり、後で渡されるのはパラメーターリストです(パラメーターの受け渡しと適用の違いに注意してください)。パラメータがnullまたは未定義の場合、(ブラウザ内の)ウィンドウを指します。applyと同様に、callはこのポイントを一時的に変更するだけで、すぐに実行します。
例:
var arr=[1,10,5,8,3];
console.log(Math.max.call(null,arr[0],arr[1],arr[2],arr[3],arr[4])); //10
Acceptはパラメータリストとして渡され、applyはパラメータ配列として渡されます。
- バインドメソッド
bindメソッドはcallと非常によく似ています。最初のパラメーターもこれのポイントであり、後で渡されるパラメーターリストもパラメーターリストです(ただし、このパラメーターリストは複数回渡すことができ、callはすべてのパラメーターを渡す必要があります一度に)、しかしこれを変更しますポインティング直後には実行されませんが、このポイントを永続的に変更する関数を返します。
例:
var arr=[1,10,5,8,12];
var max=Math.max.bind(null,arr[0],arr[1],arr[2],arr[3])
console.log(max(arr[4])); //12,分两次传参
bindメソッドはパラメーターを複数回渡すことができ、最後にすべてのパラメーターが相互に接続されて関数に入れられ、関数の実行時に実行されることがわかります。
bindメソッドを実装します(インタビューの質問):
シンプルバージョン
Function.prototype.bind=function () {
var _this=this;
var context=arguments[0];
var arg=[].slice.call(arguments,1);
return function(){
arg=[].concat.apply(arg,arguments);
_this.apply(context,arg);
}
};
完璧なバージョン
//实现bind方法
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {
},
fBound = function() {
// this instanceof fBound === true时,说明返回的fBound被当做new的构造函数调用
return fToBind.apply(this instanceof fBound
? this
: oThis,
// 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的
aArgs.concat(Array.prototype.slice.call(arguments)));
};
// 维护原型关系
if (this.prototype) {
// 当执行Function.prototype.bind()时, this为Function.prototype
// this.prototype(即Function.prototype.prototype)为undefined
fNOP.prototype = this.prototype;
}
// 下行的代码使fBound.prototype是fNOP的实例,因此
// 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例
fBound.prototype = new fNOP();
return fBound;
};
var arr=[1,11,5,8,12];
var max=Math.max.bind(null,arr[0],arr[1],arr[2],arr[3]);
console.log(max(arr[4])); //12
適用、呼び出し、バインドの違い
- 3つすべてが、関数のthisオブジェクトを変更できます。
- 3つの最初のパラメーターは、これが指すオブジェクトです。そのようなパラメーターがない場合、またはパラメーターが未定義またはnullの場合、デフォルトでグローバルウィンドウを指します。
- 3つすべてがパラメーターを渡すことができますが、applyは配列であり、callはパラメーターリストであり、applyとcallは一度にパラメーターを渡され、bindは複数のパスに分割できます。
- bindは、これをバインドした後に戻る関数であり、後で呼び出すのに便利です。applyとcallはすぐに実行されます。