Babel轉碼關於 "super" 的注意事項

事情的原由是在問答上看到一個朋友的提問,問的是阮一峯老師 ECMAScript 6 入門 上關於super關鍵字的一段代碼問題,下面是這個代碼的截圖:javascript

圖片描述

這位樓主說他以爲 this.x 的值不是3,下面有網友說把代碼粘貼到 chrome 控制檯一試就是這結果沒錯,後來樓主說是他想錯了。我也順便把代碼粘貼到 chome 下執行後答案也確實是3。java

原本這個事沒啥就結束了,正好我開着 WebStorm 準備寫代碼,順手粘貼到代碼文件裏面,保存 > webpack打包 > 刷新瀏覽器,瞅了一眼 Console:webpack

!這是神馬狀況,輸出居然是2!es6

問題分析

爲啥與 chrome 直接運行的結果不一致呢?想了想問題應該出在 Babel 轉碼上。立刻打開轉碼後的文件,定位到這段代碼的位置:web

var B = function (_A) {
    _inherits(B, _A);

    function B() {
        _classCallCheck(this, B);

        var _this = _possibleConstructorReturn(this, (B.__proto__ || Object.getPrototypeOf(B)).call(this));

        _this.x = 2;
        _set(B.prototype.__proto__ || Object.getPrototypeOf(B.prototype), 'x', 3, _this);
        console.log(_get(B.prototype.__proto__ || Object.getPrototypeOf(B.prototype), 'x', _this)); // undefined
        console.log(_this.x); // 3
        return _this;
    }

    return B;
}(A);

super.x = 3; 對應的是 _set(B.prototype.__proto__ || Object.getPrototypeOf(B.prototype), 'x', 3, _this); 這裏有個 _set() 函數,再看下這個 _set() 是啥:chrome

var _set = function set(object, property, value, receiver) {
    var desc = Object.getOwnPropertyDescriptor(object, property);
    if (desc === undefined) {
        var parent = Object.getPrototypeOf(object);
        if (parent !== null) {
            set(parent, property, value, receiver);
        }
    } else if ('value' in desc && desc.writable) {
        desc.value = value;
    } else {
        var setter = desc.set;
        if (setter !== undefined) {
            setter.call(receiver, value);
        }
    }
    return value;
};

仔細看看這個函數後,明白是怎麼回事了。結合阮一峯老師的代碼和上面的轉碼能夠看出,_set() 傳進來的第一個參數是 B.prototype.__proto__ -- 也就是A的原型對象 -- A.prototype,第一句代碼會先找 x屬性 的描述符,若是找不到繼續順着原型鏈找... 固然是找不到的了,因此至關於啥也沒執行,this.x 的值依然是2。瀏覽器

若是按照這個 _set() 函數的邏輯,在什麼狀況下 this.x 的值纔會是3呢?要知足兩個條件:函數

  1. A.prototype 上必須有 x 屬性定義
  2. 這個 x 屬性定義上還必須定義 set 訪問器

好比像下面這樣:this

Object.defineProperty(A.prototype, 'x', {
    get: function () {
        return this._x;
    },
    set: function (value) {
        this._x = value;
    }
});

而後再跑一把,果真 this.x 的值是3了!等一下... 怎麼 console.log(super.x); // undefined 這句的結果不是 undefined 也是3了呢?看下轉碼那裏還有個 _get() 函數:spa

var _get = function get(object, property, receiver) {
    if (object === null) object = Function.prototype;
    var desc = Object.getOwnPropertyDescriptor(object, property);
    if (desc === undefined) {
        var parent = Object.getPrototypeOf(object);
        if (parent === null) {
            return undefined;
        } else {
            return get(parent, property, receiver);
        }
    } else if ("value" in desc) {
        return desc.value;
    } else {
        var getter = desc.get;
        if (getter === undefined) {
            return undefined;
        }
        return getter.call(receiver);
    }
};

好吧,代碼走到最後 else 的 getter 那裏了,天然 super.x 的讀取結果就是3了

目前還沒時間看爲啥 Babel 要這麼轉碼處理,若是你有答案了歡迎留言討論。

相關文章
相關標籤/搜索