探索javascript中的this

若是你是個js的初學者,當決定使用js來開創一個新世界的時候,你會忽然遇到不少摸不到頭腦的問題,好比繼承,塊做用域,或者如今的主題,this關鍵詞。js中的this究竟是什麼?咱們爲何每次使用它的時候,都會忘記它的使用場景和環境。有時候當咱們嘗試用以前的經驗來處理的時候發現,what?爲何跟個人設想不一致?那麼好,如今你就能夠花費你打一把遊戲的時間,來跟隨我看一下,this究竟是什麼。
js的內存包括兩個部分,執行棧和內存堆。js運行時會維護一系列的棧,當前的棧老是處在內存棧的棧頂,因此this變量就會隨着棧的操做(pop/push)而改變指向的對象。es6

  1. 普通函數
    默認的執行棧是全局的,若是一段代碼在普通函數中調用,this會指向默認的全局對象,window或者global,視運行環境而定。固然,若是咱們在代碼中啓用了嚴格模式use stirct;,那麼在嚴格模式下,this指向的是undefined。能夠參考如下的示例:數組

    function normalFunc() {
        console.log(this);
        console.log(this === window); // or global
    }
    function useStrictNormalFunc() {
        'use strict';
        console.log(this);
        console.log(this === window); // or global
    }
  2. 構造函數
    js中的構造函數,其實和普通函數沒啥區別,除了它可使用new來實例化(可是普通函數也可使用new的啊)。哦還有一個區別,構造函數首字母是大寫(固然沒有任何規定,可是若是你小寫,那確定會帶來驚喜的)。app

    function Person(name) {
        this.name = name;
    }
    const person = new Person("fengxh");
    // person.name = "fengxh";

    當咱們使用new來實例化的時候,此時構造函數內的this指向的是實例對象,實例過程當中爲實例創造了多個屬性來達到咱們建立構造函數的目的,這樣person其實就是被構建出來的實例。除非咱們手動爲Person返回一個對象類型數據,不然Person默認返回的就是this(若是手動return基礎數據,則也會被默認返回this)。函數

  3. 對象的方法調用學習

    function normalFunc() {
        console.log(this);
    }
    const person = {
        normalFunc
    };
    normalFunc(); // window or global or undefined
    person.normalFunc(); // yes, it's person. no!! why person

    對象的方法調用,this會指向對象自己,而不是全局變量。那麼咱們接着再看。this

    const myFunc = person.normalFunc;
    myFunc(); // window or global

    哈哈,這裏由於myFunc是普通的函數調用,因此this仍是指向到全局變量,而不是person了。那麼,咱們再接着看。rest

    const person = {
        normalFunc: function() {
            console.log(this); // person
            function innerFunc() {
                console.log(this); // window or global
            }
            innerFunc();
        }
    };

    這裏innerFunc仍是做爲一個普通函數被調用,因此this指向爲全局變量。固然這裏的函數定義都是普通定義,若是遇到箭頭函數,那麼狀況又會不同,這種狀況咱們隨後再說。code

  4. call,apply和bindorm

    const a = {
        name: "a"
    };
    const b = {
        name: "b"
    };
    function log() {
      console.log(this.name); 
    }
    log.call(a); // "a"
    log.call(b); // "b"
    log(); // undefined

    若是咱們在執行時改變this的綁定,那麼會產生意外的驚喜,函數中的this會被綁定到咱們指向的那個對象,而不是全局變量window。Interesting。call和apply均可以動態改變函數中的this指向,他們的不一樣點是call的參數第一個是改變this的綁定指向,第二個及之後都是做爲普通函數的參數被調用,而apply的第一個參數和call同樣,第二個函數則是參數數組,等同於arguments。而bind則是修改函數的this指向的對象,而後返回一個函數,不一樣於前二者都是直接會調用對象

  5. 箭頭函數
    詳細定義的地方請看阮大師的介紹箭頭函數定義
    箭頭函數是不持有this的,因此它的this是屬於外層的(此處不徹底精確,但願讀者能夠自行閱讀相關文獻)。並且它不能做爲構造函數使用,不能被call/apply/bind處理來達到改變函數裏this指向的目的,它不持有this。

好了,看完這篇文章你們有沒有學習到,有沒有總結出下次遇到this再怎麼處理它的問題。若是你們有什麼疑問,或者對文章的理解有不一樣之處,請指出互相學習。謝謝。

相關文章
相關標籤/搜索