js中this的「終極三問」

this是什麼?

this 本質是一個綁定, 在函數被調用時創建。它的指向是徹底由函數被調用的調用點來決定的。

function baz() {
    console.log(this);//由於baz函數的調用點在全局做用域,因此this指向全局變量
}
baz();//這裏就是baz函數的調用點

this 存在的意義

在函數體內部指代函數當前的運行環境。從而實現乾淨的 API 設計和更容易的複用。

this的使用

  1. top-level scopegit

    1) In browsers, the top-level scope is the global scope. This means that within the browser var something will define a new global variable.In Node.js this is different. The top-level scope is not the global scope; var something inside a Node.js module will be local to that module. 
       2) 可是在Node REPL下,與瀏覽器的行爲保持一致(timers除外)
           In browsers
               var that = this;
               setTimeout(function() {
                 console.log(this);//window
               }, 0);
            Node REPL
               var that = this;
               setTimeout(function() {
                 console.log(this);//Timeout {...}
               }, 0);   
           setInterval 結果相同
  2. 嚴格模式下github

    指定的this不在被封裝爲對象,並且若是沒有指定this,則this的值爲undefined
       sloppy mode
           function foo() {
             console.log(this);
           }
           foo.apply("test"); //==>String {"test"}0: "t"1: "e"2: "s"3: "t"length: 4...[[PrimitiveValue]]: "test"
        strict mode    
           function foo() {
             "use strict";
             console.log(this);
           }
           foo.apply("test"); //==>test
  3. 調用方法時沒有明確對象,this指向全局對象瀏覽器

    sloppy mode
           In browsers,this指向window
               console.log(this);//window
           Node REPL, this指向global
               console.log(this);//global
       strict mode
           In browsers,this指向window
               "use strict";
               console.log(this);//window
           Node REPL, this指向global
               "use strict";
               console.log(this);//global
  4. 匿名函數執行時當前對象是全局對象app

    sloppy mode
           In browsers,
               (function() {
                 console.log(this);//window
               })();
           Node REPL
               (function() {
                 console.log(this);//global
               })(); 
       strict mode
           In browsers,
               (function() {
                 "use strict";
                 console.log(this);//undefined
               })();
           Node REPL
               (function() {
                 "use strict";
                 console.log(this);//undefined
               })();
  5. 強制一個函數調用使用某個特定對象做爲 this 綁定,而不在這個對象上放置一個函數引用屬性
    就 this 綁定的角度講,call(..) 和 apply(..) 是徹底同樣的
    callide

    function foo() {
         console.log(this.a);
       }
       var obj = {
         a: 2
       };
       foo.call(obj); //==>2 強制函數foo()的 this 指向 obj

    apply函數

    function foo() {
         console.log(this.a);
       }
       var obj = {
         a: 2
       };
       foo.apply(obj); //==>2 強制函數foo()的 this 指向 obj     
        
    bind 返回一個硬編碼的新函數,它使用你指定的 this 環境來調用本來的函數
       function foo(something) {
         console.log(this.a, something);
         return this.a + something;
       }
       var obj = {
         a: 2
       };
       var a = 6;
       var bar = foo.bind(obj);//使用obj做爲this環境調用foo()
       var b = bar(3); // 2 3
       console.log(b); // 5
       var test = bar.bind(window);//2 3 
       console.log(test(3)); // 5

    傳遞 null 或 undefined 做爲 call、apply 或 bind 的 this 綁定參數,那麼這些值會被忽略掉。ui

    sloppy mode
           function foo() {
             console.log(this);
           }
           var obj = {};
           foo.call(null);//window or global
           foo.apply(null);//window or global
           var bar = foo.bind(null);
           console.log(bar());//window or global
        strict mode
           "use strict";
           function foo() {
             console.log(this);
           }
           var obj = {};
           foo.call(null);//null
           foo.apply(null);//null
           var bar = foo.bind(null);
           console.log(bar());//null
  6. newthis

    將新構建的對象被設置爲函數調用的 this 綁定
       function foo(a) {
         console.log(this);
         this.a = a;
       }
       var bar = new foo(2);//構建了一個新的對象(foo {a: 2})並把這個新對象做爲 foo(..) 調用的 this
       console.log(bar); //foo {a: 2}
       console.log(bar.a); // 2
  7. arrow functions編碼

    箭頭函數從封閉它的(函數或全局)做用域採用 this 綁定
       function foo() {
         // 返回一個箭頭函數
         return (a) => { //箭頭函數在詞法上捕獲 foo() 被調用時的 this(obj1)
           // 這裏的 `this` 是詞法上從 `foo()` 採用的
           console.log(this.a);
         };
       }
       var obj1 = {
         a: 2
       };
       var obj2 = {
         a: 3
       };
       var bar = foo.call(obj1);
       bar.call(obj2); //2

Refer:設計

https://github.com/CuiFi/You-Dont-Know-JS-CN
  https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/this
相關文章
相關標籤/搜索