前言: 我能理解爲什麼有些人那麼喜歡語言了,或許這就是一種探索發現的魅力吧。一種語言的成型蘊含了它的設計思想。
我們經常遇到這種(mdn截圖):
你也是class,我也是class,憑什麼我繼承了你就不能主宰自己的this。es5沒有這麼說過。
我想這是一種規範,內部肯定做了什麼騷操作,那就一起看一下吧。
es6寫法如下:
class a{}
class b extends a{
constructor(){
super()
console.log(this)
}
}
轉碼後的es5代碼如下:
"use strict";
function _typeof(obj) {
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function _typeof(obj) {
return typeof obj;
};
} else {
_typeof = function _typeof(obj) {
return obj &&
typeof Symbol === "function" &&
obj.constructor === Symbol &&
obj !== Symbol.prototype
? "symbol"
: typeof obj;
};
}
return _typeof(obj);
}
function _possibleConstructorReturn(self, call) {
if (call && (_typeof(call) === "object" || typeof call === "function")) {
return call;
}
return _assertThisInitialized(self);
}
function _getPrototypeOf(o) {
_getPrototypeOf = Object.setPrototypeOf
? Object.getPrototypeOf
: function _getPrototypeOf(o) {
return o.__proto__ || Object.getPrototypeOf(o);
};
return _getPrototypeOf(o);
}
function _assertThisInitialized(self) {
if (self === void 0) {
throw new ReferenceError(
"this hasn't been initialised - super() hasn't been called"
);
}
return self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function");
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: { value: subClass, writable: true, configurable: true }
});
if (superClass) _setPrototypeOf(subClass, superClass);
}
function _setPrototypeOf(o, p) {
_setPrototypeOf =
Object.setPrototypeOf ||
function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
function _instanceof(left, right) {
if (
right != null &&
typeof Symbol !== "undefined" &&
right[Symbol.hasInstance]
) {
return !!right[Symbol.hasInstance](left);
} else {
return left instanceof right;
}
}
function _classCallCheck(instance, Constructor) {
if (!_instanceof(instance, Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var a = function a() {
_classCallCheck(this, a);
};
var b =
/*#__PURE__*/
(function(_a) {
_inherits(b, _a);
function b() {
var _this;
_classCallCheck(this, b);
_this = _possibleConstructorReturn(this, _getPrototypeOf(b).call(this));
console.log(_assertThisInitialized(_this));
return _this;
}
return b;
})(a);
轉碼後的代碼聲明瞭一個臨時變量_this並且最終也是返回它,加上super後無非是多了一部操作,即執行了_possibleConstructorReturn這個函數
有位姓李的大佬的說法引起了我的思考,不妨以名字來推斷內容。_possibleConstructorReturn是說constructor可能會返回,我們知道constructor中如果寫了return一個對象,那麼對應的instanceOf將失效,如下:
es5也是如此
_possibleConstructorReturn函數的第二個參數_getPrototypeOf(b).call(this),調用了父類的構造函數,這一操作更完整的實現了繼承(幫助子類this增添父類構造器中的屬性和方法),當父類的constructor沒有顯式返回一個對象時,_getPrototypeOf(b).call(this)的值是undefined,然而當其顯式返回一個對象時,子類this會被廢棄,_getPrototypeOf(b).call(this)的值是return的值,將轉碼後的代碼進行測試如下:
不加return的效果:
再回到_possibleConstructorReturn這個函數
function _possibleConstructorReturn(self, call) {
if (call && (_typeof(call) === "object" || typeof call === "function")) {
return call;
}
return _assertThisInitialized(self);
}
當第二個參數call,即_getPrototypeOf(b).call(this)是一個對象或者函數時,會直接把它賦值給_this並返回。
constructor的這種顯式return對象的操作影響了this的值,我又特地試了一下es5
父類return並沒什麼用。
所以回到最開始的問題,爲什麼使用this前要加super(),我的理解還是一種規範問題,要繼承就實現最優最完整的繼承,不加的話轉碼的變量_this就沒有initialize,既然super不是默認加上的,那我們就主動加吧。