this解析

6299 ワード

thisの指摘の問題もJavaScriptの難点の一つです.面接でよく聞く質問です.thisの指摘する問題に対して、とてもぼんやりしています.彼を指しているはずなのに、なぜまた彼を指していますか?だから、この方面の知識を勉強して、整理してみました.皆さんを助けてください.
なぜthisを使うのですか?
まずコードを見ます.
function identify(){
    return this.name.toUpperCase()
}
function speak(){
    var greeting = '  ,  '+identify.call(this)
    console.log(greeting)
}

var me ={
    name:'kyle'
}

var you ={
    name:"reader"
}
identify.call(me) 
identify.call(you) 
                  
speak.call(me) //?    ,  KYLE
speak.call(you) //?   ,  READER
上記のコードは、それぞれのコンテキストオブジェクトmeとyouから、identify関数とspeak関数を使用して、thisを使用しないと、明示的にコンテキストオブジェクトをパラメータとして伝えられます.
function identify(context){
    return context.name.toUpperCase()
}
function speak(context){
    var greeting = '  ,  '+identify(context)
    console.log(greeting)
}

var me ={
    name:'kyle'
}

var you ={
    name:"reader"
}
identify(me)
identify(you) 
                  
speak(me) 
speak(you)
このように、上のように簡潔にしたくないです.相手を伝えます.
thisを知る
thisを見たばかりの時は、この関数自体、あるいは関数の作用域を指すと思っていましたが、実はそうではないことが分かりました.
function foo(num){
    console.log('foo'+ num)
    this.count ++ 
}
foo.count = 0


var i;
for(i = 0;i<10;i++){
    if(i>5){
        foo.call(foo,i)
    }
}
console.log(foo.count) //4      this   foo    foo   count  ++
関数のスコープを指しませんでした.
var a = 3
function foo() {
    var a = 2;
    bar.call(foo);
}
function bar() {
    console.log( this.a );
}
foo(); // undefined
私たちは非常に重要な点を覚えておきたいです.thisは実行中にバインディングされています.定義された時にバインディングされていません.thisのバインディングは関数宣言の位置と関係がありません.主に関数の呼び方によって決められています.
バインディング規則
1.標準バインディング
独立関数が正常に起動されると、修飾なしの呼び出しが行われます.
//       
var a = 3
function foo(){
    console.log(this.a) //a
}
foo() 
この場合、this.aは大域変数aに解析され、this指向は大域オブジェクトである.
//      
var a = 3
function foo(){
    "use strict" 
    console.log(this.a) //TypeError
}
foo()
厳密なモードでは、thisがグローバルオブジェクトに向けられないように結合されているのはundefinedです.
2.陰式バインディング
呼び出し位置にコンテキストオブジェクトがあるかどうか
function foo(){
    console.log(this.a)
}
var obj = {
    a:2,
    foo:foo
}
obj.foo() //2
呼び出し位置は、Objコンテキストオブジェクトを使用して関数を参照します.fooが呼び出しられたとき、彼の足場は、Objオブジェクトを指しています.暗黙的なバインディングのルールは、このコンテキストオブジェクトにthisを指します.だからis.aはobj.aと同じです.
function foo(){
    console.log(this.a)
}
var obj = {
    a:2,
    foo:foo
}
var obj2 = {
    a:3,
    obj:obj
}
obj2.obj.foo() //2 
多層呼び出しの場合は、最後の層だけが関数の呼び出し位置に影響を及ぼします.例えば、上のこのthisバインディングのですか?objではなく、obj 2です.
注意
暗黙的なバインディングは陰的に失われます.バインディングされたオブジェクトは失われます.最後にデフォルトのバインディングを適用します.
var a = 3;
function foo(){
    console.log(this.a);
}
var obj = {
    a:2,
    foo:foo
}
var bar = obj.foo
bar() //3
barはObj.fooの一つの引用であり、彼が引用したのはfoo関数自体であり、このときbarは修飾なしの関数であり、デフォルトのバインディングを適用するために呼び出します.
var a = 3;
function foo(){
    console.log(this.a);
}
var obj = {
    a:2,
    foo:foo
}
setTimeout( obj.foo, 100 ) //3
setTimeout(function(fn){
    fn()
},100,obj.foo) //3
パラメータ伝達も一种の暗黙的な賦課であり、コールバック関数がthisを失うことは非常に一般的である.
3.明示的なバインディング
暗黙的に結合するときは、オブジェクトの内部に関数を指す属性を含む必要があります.属性間接参照関数を通じて、このthis間接暗黙的な式をこのオブジェクトに結びつけます.オブジェクトの内部に関数の参照を含めたくないなら、あるオブジェクトに関数を強制的に呼び出したいなら、この関数をオブジェクトの原型に結び付けられます.また、対象の内部に関数を含めなくてもいいですよね?もっといい方法は、関数のcall()apply()bind()を使うことができます.
function foo(){
    console.log(this.a)
}

var obj = {
    a:2
}
foo.call(obj) //2
foo.apply(obj) //2
最初のパラメータが入力された場合、結合対象として文字列ブール数字などのオリジナルのタイプがオブジェクトの形に変換されます.new String()new Number()
ハードバインディング
Function.prototype.bind()
function foo(){
    console.log(this.a)
}

var obj = {
    a:2
}
var obj2 = {
    a:3
}
var bar = foo.bind(obj)  //                     this    
bar.call(obj2) //2        
いくつかのappi方法は、任意のパラメータcontextを提供します.その役割は、bindのように、指定されたthisを使用して、array.forEach(fn、context)…
4.newバインディング
newを使って関数を呼び出すと、以下の操作が行われます.1つの新しいオブジェクトを作成します.2.この新しいオブジェクトはプロトタイプのリンクを実行します.3.新しいオブジェクトは関数で呼び出されたthis 4にバインドされます.他のオブジェクトに戻らないと、関数は自動的にこのオブジェクトに戻ります.
function Foo(a){
    this.a = a
}
var bar = new Foo(2)
console.log(bar.a) //2
newを使ってFoo関数を呼び出します.新しいオブジェクトを作成し、Foo呼び出しのthisに結びつけて返します.
優先度
関数に修飾がない場合は単独で起動するとデフォルトのバインディングがトリガされますので、デフォルトのバインディングは優先度が一番低いです.
三つのルールが残っていますが、どれが一番優先度が高いですか?
バインディングと暗黙的バインディングの比較を表示します.
function foo(){
    console.log(this.a)
}
var obj1 = {
    a:1,
    foo:foo
}

var obj2 = {
    a:2,
    foo:foo
}
obj1.foo() //1
obj2.foo() //2

obj1.foo.call(obj2) //2
obj2.foo.call(obj1) //1
バインディングの優先度を表示しますか?
newバインディングと暗黙的バインディングの比較
function foo(arg){
    this.a = arg
}

var obj1 ={
    foo:foo
}
var obj2 ={}

obj1.foo(2)
console.log(obj1.a) //2

var bar = new obj1.foo(4)
console.log(obj1.a) //2
console.log(bar.a) //4
newバインディングの優先度は陰的バインディングよりも高いことが見られます.
newバインディングと表示バインディングの比較
newはcall applyと一緒に使えません.new foo.cal(obj)を通して、ハードバインディングを試してみます.
        
function foo(arg){
    this.a = arg
}
var obj1 ={}
var bar = foo.bind(obj1)
bar(3)
console.log(obj1.a) //3

var baz = new bar(4)
console.log(baz.a) //4
console.log(obj1.a) //3
new呼び出しbarは、ハードバインディング時の関数のthis newの優先度が高い点を修正しました.
したがって、以下の優先順位規則に基づいて判断することができます.
1.関数がnewで呼び出されたかどうかは、新しいオブジェクトvar bar=new Foo()2.関数がcall appyでバインディングまたはbindハードバインディングを表示します.もしそうであれば、thisは指定されたオブジェクトfoo.call(obj)3を指します.関数は、あるコンテキストで暗黙的バインディングを呼び出しますか?thisバインディングのコンテキストオブジェクトであれば、バインディングが失われた問題に注意してください.すべてがデフォルトのバインディング非厳密モードでバインディングされていない場合、グローバルオブジェクトの厳密モードでバインディングされているのはundefinedです.
バインディング例外
1.nullとundefinedをcall applyパラメータとしてthisバインディングオブジェクトとして使用する場合、これらの値は無視されます.デフォルトのバインディングです.
var a =3
function foo(){
    console.log(this.a) //3
}
foo.call(null)
2.矢印関数
function foo(){
    return ()=>{
        console.log(this.a)
    }
}
var obj1 = {
    a:3
}
var obj2 = {
    a:4
}
var bar = foo.call(obj1)
bar.call(obj2) //3  this    obj1    obj2!!!
一つ見ています
function foo(){
    setTimeout(()=>{
        console.log(this.a) //2
    },100)
}
var obj = {
    a:2
}
foo.call(obj)
矢印関数はthisバインディングの4つの規則を使用しないで、外層作用領域によってthisを決定します.外層作用領域のthisバインディングは何ですか?彼のthisとは何ですか?