1. 程式人生 > >js深入(四)萬臉懵圈的this指向

js深入(四)萬臉懵圈的this指向

作為一個js菜雞的我而言,在之前講到過那麼多的js鏈式查詢機制,比如說原型鏈,作用域鏈等等,想當然的把這個機制帶入到了this指向上邊,結果就是這個this指向指的我萬臉懵逼(標題換字了,擔心被河蟹),在經過漫長的通(gou)俗(pi)易(bu)懂(tong)的 ECMAScript規範閱讀之後,分享一下我所認知的this指向

簡而言之,js中this的指向不是在函式定義的時候確定的,而是在呼叫的時候建立階段確定的,也就是說this指向誰,完全取決於函式的呼叫方式

常見的幾種呼叫方式

  • 直接呼叫, 比如說

      function a() {
      console.log(this);  
      }
    
      a();  

這個例子裡邊this指向的是全域性物件,在客戶端的全域性物件是window物件,在node 中的全域性物件是global物件

    (function a() {
        function b() {
            console.log(this);  
        }
        b()
    })()

直接呼叫指的是直接用函式名稱後邊加()執行呼叫的函式,無論是否在全域性作用域

  • 間接呼叫

      const obj ={
          name:'obj物件',
          a(){
              console.log(this)
          }
      }
      obj.a()

如圖

在圖中我們可以看到我們在物件裡邊呼叫物件裡邊的方法的時候,this指向的是obj物件,

或者說外邊有一個函式 然後給一個obj物件的屬性賦值

    const obj ={
        name:'obj物件',
        a(){
            console.log(this)
        }
    }
    obj.a()
    obj.b=function(){
        console.log(this,'b')
    }
    obj.b()

列印的結果都是obj物件

  • new呼叫

當我們他用過new 建立一個新的物件的時候,new會呼叫這個建構函式來建立一個物件,那麼這個物件裡邊的this是這個被new的函式呼叫的,那麼自然 new呼叫的時候,this就是指向這個新物件的

    function A(data) {
        this.data = data;
    }
    class B{
        constructor(data){
              this.data = data
        }
    }
    let a = new A("A");
    let b = new B("B");
    console.log(a.data);   
    console.log(b.data);   

如圖

這個new,在建立物件的時候做了什麼,我們會在下一篇部落格裡邊仔細說明

  • 箭頭函式中的this

箭頭函式可以理解成是是一個語法糖,他沒有自己的this繫結,箭頭函式中使用的this是包含他的那個函式的this

比如說

    const obj = {
        a() {
            return () => {
                console.log(this);
            };
        }
    }    

上邊這段程式碼被轉譯成es5 的時候如下

const obj = {
    a: function a() {
        var _this = this;
        return function () {
            console.log(_this);
        };
    }
};

綜合以上所有的程式碼,得出一個結論就是,在js中this的繫結正常來講是指向呼叫這個方法的物件來確定的,當然還有一些不正常的方法,可以改變this的指向

注意 ,下邊介紹的幾種方法,不能改變箭頭函式的this指向,箭頭函式本身是沒有this繫結的,在介紹完不正常的情況後,再來說一說那些能夠改變this指向的方法

ECMAScript 5.1 規範的this指向

      js中this的繫結正常來講是指向呼叫這個方法的物件來確定的  
      

這句話在理論上是這麼講,在工作中正常的呼叫的話,這個理論是沒有毛病的,在 ECMAScript 5.1 的規範裡邊規定,在js裡邊分為語言型別和規範型別

  • 語言型別

ECMAScript 裡邊的語言型別規定的是我們可以直接操作的一些型別,比如string number,object等等這些

  • 規範型別

規範型別ECMAScript 裡邊指的是一種抽象的規範,他們並不是讓我們用來進行操作的,二是用來描述一些行為或者邏輯的,比如說typeof delete等等

ECMAScript 5.1 裡邊的this規定大概講就是這樣的,每個物件裡邊有一個Reference 規範型別,this會根據Reference這個規範型別進行賦值

ECMAScript 5.1

規範奉上 Reference 這個東西大家簡單的理解成是()前邊的那一塊就好了,上邊我們講的那些正常的就是說左邊是

  • 函式定義表示式
  • 屬性訪問表示式
  • 物件建立表示式
  • 屬性建立表示式

這幾種情況,在這幾種情況的時候上邊那句話是成立的

但是如果不是這上邊的那幾句話的時候,比如說括號裡邊是一個和函式相關計算或者一個運算子等等

這個時候this會指向undefined ,這個時候在非嚴格模式的情況下會被隱式轉換成window物件

    var value = 1;

    var obj = {
      value: 2,
      a() {
        return this.value;
      }
    }
    
    console.log(obj.a());
    console.log((obj.a)());
    console.log((obj.a = obj.a)());
    console.log((false || obj.a)());
    console.log((obj.a, obj.a)());
    

記得之前看到過這個一個例子,執行結果如圖

時間關係就說這些,下一篇部落格會說new在執行時候過程和改變this指向的一些方法,
以上是我對this指向的一些認識,有不足的地方希望之