一個JS初學者關於查找變量的一些感悟。。

我是一個js的初學者,這幾天被直接訪問標識符和經過this訪問標識符搞的頭疼,因而大膽的作了一個猜想:
1. 直接訪問標識符是經過做用域鏈進行查找的。
2. 經過this訪問標識符是經過原型鏈來查找的。
而後就開始試了起來!!!!前端

結合下面的代碼來講瀏覽器

var a = "abc";

var obj = {
    a: "def",
    display3: function () {
        var a = "sssss";
        console.log(a);
    },
    display4: function() {
        console.log(this.a);
    }
}

Object.prototype.a = "ghi";

function display1() {
    // var = "hahaha";
    console.log(a)
}

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

display1(); // "abc"
display2();  // "abc"

obj.display3();
obj.display4();

// display2.call(obj);  // "def"
// display1.call(obj);  // "abc"

首先:函數

第一個:
調用display1函數,經過做用域鏈來查找a。此時display1的做用域鏈爲:display1的活動對象→全局活動對象,
因此找到了全局活動對象中的"abc",若是在display1中有變量a,那麼輸出的則是這個變量的值。this

第二個
調用diplay2函數,經過原型鏈來查找a。由於this是基於當前的執行環境綁定的,因此this指向全局變量對象(也就是window),因此找到了"abc"並輸出。
有意思的是,此時若是我刪除window中定義的a="abc", 那麼輸出結果則是"ghi". 因而回憶了一下本身所學的知識,發現由於window對象是Global對象在瀏覽器中的表現,而後Global是js中的單體內置對象,那麼彷佛它也應該繼承自Object.prototype, 恩..按照個人猜測,輸出結果爲"ghi"是情理之中的。prototype

第三個:
經過obj調用display3函數,由於前面沒有this,因此是經過做用域鏈進行查找的,此時display3的做用域鏈爲display1的活動對象→全局活動對象,因此輸出結果是"abc", 一樣,若是我再display3中定義了a,那麼輸出的則是這個a的值code

第四個
經過obj調用display4函數,由於前面有this,因此是經過原型鏈進行查找的,此時this指向的是obj,因此輸出的結果是obj對象中"def",若是咱們刪除obj中的a屬性,那麼輸出結果則是Object.prototype中的"ghi",若是再刪除這個ghi,那麼輸出結果就是undefined了。
上面這些好像都符合邏輯,但是我又忽然發現,當調用display1時,若是刪除了做用域鏈中每一個變量對象的a屬性,那麼輸出結果則是"ghi", 這個"ghi"是在Object.prototype中定義的,因此對象

綜合了一下繼承

1. 直接訪問標識符是經過做用域鏈和原型鏈綜合進行查找的。
2. 經過this訪問標識符是經過原型鏈來查找的。
而後又出現了一個問題:直接訪問標識符的查找順序是 1:先查找做用域鏈前端的變量對象,而後再查找它的原型,而後再查找做用域鏈中下一個變量對象,而後再查找它的原型 仍是 2: 一直查找做用域鏈中的變量對象,知道window對象,再查找它的原型呢?ip

而後又忽然發現,在調用display1時,若是display1中沒有定義a變量,訪問到的則是window中的a = "abc",而不是Object.prototype中的a = "ghi".原型鏈

因此再綜合一下

1. 直接訪問標識符的順序是按順序查找做用域鏈中的每個變量對象直至全局變量對象,若是全局變量對象中沒

有該變量,則沿着window對象的原型鏈進行查找。

2. 經過this訪問標識符是經過原型鏈來查找的。

我去累死了,我也沒想到本身寫了這麼多,從結果來看,應該是這樣,不過也不知道究竟是不是這樣。。

相關文章
相關標籤/搜索