this詳細


一、thisメカニズム
  • thisは、作成時に結合された
  • ではなく、実行時にバインディングされています.
  • thisは、関数に依存した呼び出し方式を指す.
    二、thisバインディング規則
    1.標準バインディング
    まず、最もよく使われている関数の呼び出し方法です.独立関数の呼び出しです.
    function foo(){
        console.log(this.a)
    }
    //     a,              
    var a=2;
    foo(); // 2
    foo()呼び出しには何の修飾も参照しないので、デフォルトのバインディングのみを使用します.
    2.陰式バインディング
    (1)呼び出し位置にコンテキストオブジェクトがあるかどうか、またはあるオブジェクトに所有されているかどうか
    function foo(){
        console.log(this.a)
    }
    var obj={
        a:2,
        foo:foo
    }
    obj.foo() // 2
    関数fooはobjオブジェクトではありませんが、呼び出し位置はobjコンテキストを使用して関数を参照します.このとき、暗黙的なバインディングはこのコンテキストオブジェクトにthisバインディングされます.
    (2)また、オブジェクト参照では、最後のレイヤーだけが呼び出し位置で機能します.
    function foo(){
        console.log(this.a)
    }
    var obj2={
        a:42,
        foo:foo
    }
    var obj1={
        a:2,
        obj2:obj2
    }
    
    obj1.obj2.foo(); // 42               
    (3)暗黙的な紛失(デフォルトのバインディングに変わります)
    function foo(){
        console.log(this.a)
    }
    var obj={
        a:2,
        foo:foo
    }
    var bar=obj.foo;
    var a="oops, global";
    bar(); // "oops, global"
    barはobj.fooの引用ですが、実際にはfoo関数自体を参照してください.bar呼び出しには修飾がありません.したがって、デフォルトのバインディングです.
    function foo(){
        console.log(this.a)
    }
    var obj={
        a:2,
        foo:foo
    }
    function doFoo(fn){
        fn();  //      
    }
    
    var a="oops, global";
    doFoo(obj.foo); // "oops, global"
    パラメータ伝達は、関数に過ぎず、前の栗と同じです.
    function foo(){
        console.log(this.a)
    }
    var obj={
        a:2,
        foo:foo
    }
    var a="oops, global";
    setTimeout(obj.foo,100); // "oops, global"
    結果は同じです.違いはありません.setTimeoutは
    function setTimeout(fn,deplay){
        //   deplay   
        fn(); //     
    }
    3.明示的なバインディング(ハードバインディング)
    callでappy関数がthisの方向を変えます.
    function foo(){
        console.log(this.a)
    }
    var obj={
        a:2,
        foo:foo
    }
    var bar=function(){
        foo.call(obj);
    }
    bar(); // 2
    setTimeout(bar,100); // 2
    bar.call(window); // 2
    ハードバインディングを見ても、thisの方向は変更できません.
    4.newバインディング
    new呼び出し時に、関数が他のオブジェクトに戻らないと、newから出てきたオブジェクトに紐付けされます.
    function foo(a){
        this.a=a;
    }
    var bar=new foo(2);
    console.log(bar.a); //2
    
    var obj={
        a:3
    }
    function boo(a){
        this.a=a;
        return obj; //      
    }
    var baz=new boo(2);
    console.log(baz.a); // 3
    三、thisバインディング優先度
    newバインディング>call/appy(明示的バインディング)>暗黙的バインディング>デフォルトのバインディングを証明します.
    1.バインディングvs暗黙的バインディングを表示する
    function foo(){
        console.log(this.a);
    }
    var obj1={
        a:2,
        foo:foo
    }
    var obj2={
        a:3,
        foo:foo
    }
    obj1.foo(); // 2    
    obj2.foo(); // 3    
    
    obj1.foo.call(obj2); // 3
    obj2.foo.call(obj1); // 3
    上記の証明:バインディングを表示する.
    2.newバインディングvsバインディング
    function foo(something){
        this.a=something;
    }
    var obj1={
        foo:foo
    }
    var obj2={}
    
    obj1.foo(2); //   
    console.log(obj1.a); // 2
    
    obj1.foo.call(obj2,3); //   
    console.log(obj2.a); // 3
    
    var bar=new obj1.foo(4);
    console.log(obj1.a); // 2
    console.log(bar.a); // 4
    最後の3行のコードを見ると、newバインディング>暗黙的バインディング
    3.newバインディングvsはバインディングを表示します.
    newバインディングはcall/applyと一緒に使えません.new foo.call(obj 1)という形でテストできません.私達はbindで試してみます.
    function foo(something){
        this.a=something;
    }
    var obj1={};
    var bar=foo.bind(obj1);
    bar(2);
    console.log(obj1.a); // 2
    
    var baz=new bar(3);
    console.log(obj1.a); // 2
    console.log(bar.a); // 3
    最後の3行:
  • これまでにfooはObj 1に縛られていましたが、new bar(3)はbar(2)のように、Obj 1.aが変わっていません.Obj 1.aはまだ2です.
  • はむしろbar.aが3になりました.new bar(3)の中(new bar)が一つの全体として有効であると説明しました.
  • したがって、newバインディングは
  • を示す.
    四、バインディング例外
    1.無視されたthis
    null/undefinedをthisのバインディングオブジェクトとしてcall/apply/bindに入力すると、これらの値の呼び出しは無視され、デフォルトのバインディングルールに変わります.
    function foo(){
        console.log(this.a);
    }
    var a=2;
    foo.call(null); // 2
    
    //      
    function fo(a,b){
        console.log("a:"+a+",b:"+b);
    }
    var bar = fo.bind(null,2);
    bar(3); // a:2,b:3
    2.間接参照
    function foo(){
        console.log(this.a);
    }
    var a=2;
    var o={a:3,foo:foo};
    var p={a:4};
    
    o.foo(); // 3
    (p.foo=o.foo)(); // 2
    p.foo=o.fooの戻り値は、ターゲット関数の参照であり、呼び出したfoo()は、p.foo()やo.foo()ではなく、標準バインディングです.
    五、矢印関数
    矢印関数は、thisの4つの標準的な規則を使用しないで、外層作用領域に基づいてthisを決定します.
    function foo(){
        return (a)=>{
            console.log(this.a);
        }
    }
    var obj1={a:2};
    var obj2={a:3};
    
    var bar=foo.call(obj1);
    bar.call(obj2); // 2     3
    カッター関数がthisを結合した後、変更できません.
    function foo(){
        setTimeout(()=>{
            console.log(this.a);
        },100)
    }
    
    var obj={a:2};
    foo.call(obj); // 2
    六、経典蔑視問題
    function Foo () {
        getName = function () {
            console.log(1);
        };
        return this;
    }
    Foo.getName = function () {
        console.log(2);
    };
    Foo.prototype.getName = function () {
        console.log(3);
    };
    var getName = function () {
        console.log(4);
    };
    function getName () {
        console.log(5);
    }
    
    Foo.getName(); // 2
    getName(); // 4 
    Foo().getName(); // 1
    getName(); // 1
    new Foo.getName(); //2
    new Foo().getName(); // 3 
    new new Foo().getName(); // 3