jsのthisのまとめ
3781 ワード
thisの指向問題についてはjsの中で非常に重要な問題である.今日はこの問題をまとめて、thisに対する自分の理解を深めます.まず、thisの指向性の問題は、thisが常に呼び出されたオブジェクトを指していること、すなわち、このthisが誰を指しているかは関数宣言の位置とは関係なく、呼び出された位置だけに関係していることを一言でまとめることができます.これはthisを判断する大まかな原則であり、具体的な小原則は優先度によって大きく以下の点に分けられる.
一.優先度:newバインド>明示バインド>暗黙バインド>デフォルトバインド
一.優先度:newバインド>明示バインド>暗黙バインド>デフォルトバインド
1.newバインド
new方式は最も優先度の高い呼び出し方式であり、つまりnew方式が現れて関数を呼び出す限り、thisはnew呼び出し関数が新しく作成されたオブジェクトを指すに違いない.function() thisTo(a){
this.a=a;
}
var data=new thisTo(2); // new
console.log(data.a); //2
2.明示的なバインド
表示バインドとは、call()メソッドとapply()メソッドによる関数の呼び出しであり、この影響の優先度はnewバインドに次ぐ.function thisTo(){
console.log(this.a);
}
var data={
a:2
};
thisTo.call(data)); //2
3.暗黙的バインド
暗黙的バインドとは、オブジェクトのプロパティを追加してthisが存在する関数を呼び出すことです.この方法の優先度は、バインドが表示された後です.function thisTo(){
console.log(this.a);
}
var data={
a:2,
foo:thisTo // this
};
data.foo(); //2
4.デフォルトのバインド
デフォルトバインドとは、上記の3つのバインドルールが一致しない場合に使用されるバインドルールであり、デフォルトバインドはthisのデフォルトをグローバルオブジェクトにバインドし、優先度が最も低いバインドルールです.function thisTo(){
console.log(this.a);
}
var a=2; //a
thisTo(); //2
二.このバインドの特殊な状況
1.暗黙的な損失
暗黙的なバインドを行う場合、リファレンス割り当てまたはパラメータ転送操作を1回行うと、thisが失われ、最後にthisがグローバルオブジェクトにバインドされます.
1.1参照割付損失function thisTo(){
console.log(this.a);
}
var data={
a:2,
foo:thisTo // this
};
var a=3;//
var newData=data.foo; //
newData(); // 3
原理:newDataは実際にfoo関数自体を参照しているため、dataオブジェクトとは何の関係もなく、dataオブジェクトは中間ブリッジにすぎません.newDataは、それ自体がa属性を持たないオブジェクトであり、自然と最終的にはaをグローバルオブジェクトにバインドするしかありません.
1.2パラメータの紛失function thisTo(){
console.log(this.a);
}
var data={
a:2,
foo:thisTo // this
};
var a=3;//
setTimeout(data.foo,100);// 3
原理:settimeout(fn,delay){fn();}実際にfnはパラメータ伝達の参照(fn=data.foo)であり、参照損失の原理と同じである.
1.3 Function.prototype.bind()暗黙的な損失の問題を解決するために、ES 5はbindメソッドを提供し、bind()はハードコーディングの新しい関数を返し、パラメータをthisのコンテキストに設定し、元の関数を呼び出す.function thisTo(){
console.log(this.a);
}
var data={
a:2
};
var a=3;
var bar=thisTo.bind(data);
console.log(bar()); //2
2.間接参照
間接参照とは、オブジェクトを定義するメソッドが別のオブジェクトが存在するメソッドを参照することであり、この場合、thisはデフォルトのバインドされます.function thisTo(){
console.log(this.a);
}
var data={
a:2,
foo:thisTo
};
var newData={
a:3
}
var a=4;
data.foo(); //2
(newData.foo=data.foo)() //4
原理:newData.foo=data.fooの戻り値はターゲット関数の参照であるため、呼び出された位置は実際にはfoo()であり、以前の暗黙的な損失で述べた原則に基づいて、ここではデフォルトのバインドが適用されます.
3.ES 6矢印関数
ES 6の矢印関数はthisでは特殊な改良であり,矢印関数は従来のthisメカニズムに取って代わる文法的役割ドメインを用いているため,矢印関数は上記のthis優先度の原則を用いることができず,矢印関数では外層の父親の役割ドメインに基づいてthisの指向問題を決定することに注意している.function thisTo(){
setTimeout(function(){
console.log(this.a);
},100);
}
var obj={
a:2
}
var a=3;
thisTo.call(obj); //3
矢印関数を使用せずに暗黙的に失われ、最後のthisはデフォルトでグローバル役割ドメインにバインドされ、3が出力されます.function thisTo(){
setTimeout(()=>{
console.log(this.a);
},100);
}
var obj={
a:2
}
var a=3;
thisTo.call(obj); //2
矢印関数を使用すると、暗黙的な損失は発生しません.thisは外層の親役割ドメインthisTO()にバインドされ、thisToの呼び出し元はobjオブジェクトなので、最後のthisはobjオブジェクトに、2を出力します.
同じ出力を矢印関数で実現しない場合は、次のようにします.function thisTo(){
var self=this; // this
setTimeout(function(){
console.log(self.a); // self this
},100);
}
var obj={
a:2
}
var a=3;
thisTo.call(obj); //2
三.まとめ:
このバインドメカニズムは、この関数の直接呼び出し位置を見つけ、バインドされた4つのルールを適用し、複数のルールを満たす場合、優先度の高低に応じて最終的なバインドルールを決定することです.さらに、いくつかの特殊なケース、特にES 6の矢印関数に注意します.
四.参考書:
あなたの知らないJavaScript上巻
function() thisTo(a){
this.a=a;
}
var data=new thisTo(2); // new
console.log(data.a); //2
function thisTo(){
console.log(this.a);
}
var data={
a:2
};
thisTo.call(data)); //2
function thisTo(){
console.log(this.a);
}
var data={
a:2,
foo:thisTo // this
};
data.foo(); //2
function thisTo(){
console.log(this.a);
}
var a=2; //a
thisTo(); //2
1.暗黙的な損失
暗黙的なバインドを行う場合、リファレンス割り当てまたはパラメータ転送操作を1回行うと、thisが失われ、最後にthisがグローバルオブジェクトにバインドされます.
1.1参照割付損失
function thisTo(){
console.log(this.a);
}
var data={
a:2,
foo:thisTo // this
};
var a=3;//
var newData=data.foo; //
newData(); // 3
原理:newDataは実際にfoo関数自体を参照しているため、dataオブジェクトとは何の関係もなく、dataオブジェクトは中間ブリッジにすぎません.newDataは、それ自体がa属性を持たないオブジェクトであり、自然と最終的にはaをグローバルオブジェクトにバインドするしかありません.
1.2パラメータの紛失
function thisTo(){
console.log(this.a);
}
var data={
a:2,
foo:thisTo // this
};
var a=3;//
setTimeout(data.foo,100);// 3
原理:settimeout(fn,delay){fn();}実際にfnはパラメータ伝達の参照(fn=data.foo)であり、参照損失の原理と同じである.
1.3 Function.prototype.bind()暗黙的な損失の問題を解決するために、ES 5はbindメソッドを提供し、bind()はハードコーディングの新しい関数を返し、パラメータをthisのコンテキストに設定し、元の関数を呼び出す.
function thisTo(){
console.log(this.a);
}
var data={
a:2
};
var a=3;
var bar=thisTo.bind(data);
console.log(bar()); //2
2.間接参照
間接参照とは、オブジェクトを定義するメソッドが別のオブジェクトが存在するメソッドを参照することであり、この場合、thisはデフォルトのバインドされます.
function thisTo(){
console.log(this.a);
}
var data={
a:2,
foo:thisTo
};
var newData={
a:3
}
var a=4;
data.foo(); //2
(newData.foo=data.foo)() //4
原理:newData.foo=data.fooの戻り値はターゲット関数の参照であるため、呼び出された位置は実際にはfoo()であり、以前の暗黙的な損失で述べた原則に基づいて、ここではデフォルトのバインドが適用されます.
3.ES 6矢印関数
ES 6の矢印関数はthisでは特殊な改良であり,矢印関数は従来のthisメカニズムに取って代わる文法的役割ドメインを用いているため,矢印関数は上記のthis優先度の原則を用いることができず,矢印関数では外層の父親の役割ドメインに基づいてthisの指向問題を決定することに注意している.
function thisTo(){
setTimeout(function(){
console.log(this.a);
},100);
}
var obj={
a:2
}
var a=3;
thisTo.call(obj); //3
矢印関数を使用せずに暗黙的に失われ、最後のthisはデフォルトでグローバル役割ドメインにバインドされ、3が出力されます.
function thisTo(){
setTimeout(()=>{
console.log(this.a);
},100);
}
var obj={
a:2
}
var a=3;
thisTo.call(obj); //2
矢印関数を使用すると、暗黙的な損失は発生しません.thisは外層の親役割ドメインthisTO()にバインドされ、thisToの呼び出し元はobjオブジェクトなので、最後のthisはobjオブジェクトに、2を出力します.
同じ出力を矢印関数で実現しない場合は、次のようにします.
function thisTo(){
var self=this; // this
setTimeout(function(){
console.log(self.a); // self this
},100);
}
var obj={
a:2
}
var a=3;
thisTo.call(obj); //2
三.まとめ:
このバインドメカニズムは、この関数の直接呼び出し位置を見つけ、バインドされた4つのルールを適用し、複数のルールを満たす場合、優先度の高低に応じて最終的なバインドルールを決定することです.さらに、いくつかの特殊なケース、特にES 6の矢印関数に注意します.
四.参考書:
あなたの知らないJavaScript上巻
あなたの知らないJavaScript上巻