事情的原由是在問答上看到一個朋友的提問,問的是阮一峯老師 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呢?要知足兩個條件:函數
A.prototype
上必須有 x
屬性定義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 要這麼轉碼處理,若是你有答案了歡迎留言討論。