JavaScriptにおけるthisの最終理解(2)

4204 ワード

前のページでは、各関数のthisは呼び出し時に結合されていることを知りましたが、関数の呼び出し位置(すなわち関数の呼び出し方法)には完全に決まりました.
1.呼び出し先
thisのバインディングプロセスを理解する前に、まず呼出位置を理解する必要があります.呼び出し位置は、ステートメントの位置ではなく関数がコード内で呼び出される位置です.
関数の呼び出し位置を見つけるために最も重要なのは、コールスタックを分析することです.私たちが関心を持っているコール位置は、現在実行中の関数の前の呼び出しにあります.
function baz() {
    //      :baz
    //  ,            
    console.log("baz");
    bar(); //bar
    //  ,       baz 
    console.log("bar")
    foo(); 
}

function foo() {
    //      baz->bar->foo
    //  ,       bar 
    console.log("foo")
}
baz() //
2.バインディングルール
呼び出し位置はどのようにしてオブジェクトをバインディングするかを決めますか?まず、私たちは呼び出し位置を見つけて、次の4つの規則に従って適用します.まずこのいくつかの規則を理解します.
(1)標準バインディング
まず、最もよく使われる関数の呼び出しの種類を紹介します.独立関数の呼び出しです.この規則は他の規則を適用できないという暗黙のルールと見なすことができます.
function foo() {
    console.log(this.a)
}
var a = 2;
foo(); //2
上のコードでは、グローバル環境で変数aを宣言していますが、aはグローバルオブジェクトの同名属性です.foo()を呼び出すと、this.aはグローバル変数aに解析される.関数が呼び出されたときには、thisのデフォルトのバインディングが適用されますので、thisはグローバルオブジェクトを指します.コードでは、foo()は、直接に修飾なしの関数参照を使用して呼び出されるので、デフォルトのバインディングのみが使用されます.
厳密なモードを使用すると、グローバルオブジェクトはデフォルトのバインディングを使用できなくなりますので、thisはundefinedにバインドされます.
(2)陰的バインディング
もう一つの考慮すべきルールは、呼び出し位置にコンテキストオブジェクトがあるかどうか、またはあるオブジェクトに所有されているかどうか、または含まれているかどうかである.
function foo() {
    console.log(this.a)
}
var obj = {
    a: 2,
    foo: foo
}
obj.foo(); //2
まず注意したいのは、foo()の宣言方式と、その後どのように参照属性としてobjに追加されるかである.しかし、直接objで定義しても、先に定義してから参照属性に追加しても、この関数は厳密にはobjオブジェクトには含まれません.
呼び出し位置は、関数を参照するためにobjコンテキストを使用しますので、関数が呼び出されたときに、objオブジェクトが「所有」または「含まれる」と言ってもいいです.
foo()が呼出されると、その時点は確かにobjオブジェクトを指します.関数がコンテキストオブジェクトを参照すると、このコンテキストオブジェクトに関数呼び出し中のthisをバインドします.foo()を呼び出したときにthisがobjに結合されるので、this.aとobj.aは同じです.
オブジェクト属性参照チェーンの最上階または最後の階だけが呼び出し位置に影響します.
function foo() {
    console.log(this.a)
}
var obj2 = {
    a: 42,
    foo: foo
}
var obj1 = {
    a: 2,
    obj2: obj2
}
obj1.obj2.foo() //42
  • 暗黙的な損失
  • thisバインディングの一般的な問題は、バインディングされた関数がバインディングされたオブジェクトをなくします.すなわち、デフォルトのバインディングが適用されます.これにより、thisをグローバルオブジェクトまたはundefinedに結びつけます.
    function foo() {
        console.log(this.a)
    }
    var obj = {
        a:2,
        foo: foo
    }
    var bar = obj.foo; //    
    var a = 'oops, globas'; //a        
    bar(); //'oops, globas'
    barはobj.fooの参照ですが、実際にはfoo関数自体を参照していますので、この時点でbar()は実際には何も修飾されていない関数として呼び出されていますので、デフォルトのバインディングを適用します.
    次のコードのセットを見てください.
    function foo() {
        console.log(this.a)
    }
    function doFoo(fn) {
        fn();
    }
    
    var obj = {
        a:2,
        foo:foo
    }
    var a = 'oops,global'
    doFoo(obj.foo); //'oops, global'
    パラメータ伝達とは、実は一種の暗黙的な賦値であり、したがって、私たちが関数に入っても暗黙的に賦課されるので、結果は前と同じである.
    (3)バインディングを表示する
    関数のcall()とappy()法を使用して、この2つの方法であるオブジェクトに関数を強制的に呼び出すことができます.これらの2つの方法の役割は同じで、最初のパラメータはオブジェクトであり、それらはこのオブジェクトをthisに結び付け、次に関数を呼び出すときにこのthisを指定します.thisのバインディングオブジェクトを直接指定することができますので、表示バインディングといいます.
    function foo() {
        console.log(this.a)
    }
    var obj = {
        a: 2
    }
    foo.call(obj); //2
    foo.call(.)を通じて、fooを呼び出したときに強制的にそのthisをobjに結びつけることができます.
    元の値(文字列タイプ、ブールタイプなど)が入ってきたら、thisのバインディングオブジェクトとして扱います.この元の値はオブジェクト形式に変換されます.つまり、(new String(.))は通常「箱詰め」と呼ばれます.
    function foo() {
        console.log(this.a)
    }
    var obj = {
        a:2
    }
    var bar = function() {
        foo.call(obj)
    }
    bar();//2
    setTimeout(bar, 10); //2
    bar.call(window); //2
    以上のように、私たちはどのようにbarを呼び出しても、常に手動でObjでfooを呼び出します.このようなバインディングの際に表示される強制バインディングは、ハードバインディングと呼ばれます.
    ハードバインディングの典型的なアプリケーションシーンは、すべてのパラメータを入力し、受信したすべての値を返します.
    function foo(something) {
        console.log(this.a, something)
        return this.a + something
    }
    
    //         
    function bind(fn, obj) {
        return function() {
            return fn.apply(obj, arguments)
        }
    }
    
    var obj = {
        a: 2
    };
    var bar = bind(foo, obj)
    
    var b = bar(3) //2, 3
    console.log(b) //5
    bind(...)はハードコードの新しい関数を返します.パラメータをthisのコンテキストに設定して元の関数を呼び出します.
    (4)newバインディング
    JavaScriptでは、構造関数はnewオペレータを使用する時に呼び出される関数だけです.彼らは特定のクラスには属しません.また、実用化されません.実際には彼らは特殊な関数タイプとさえ言えないです.ただnewオペレータに呼び出された普通の関数です.
    newを使って関数を呼び出すと、以下の操作が行われます.
    1.          
    2.          [[  ]]  
    3.               this
    4.             ,  new                   。