繼承行為在 ES5 與 ES6 中的區(qū)別詳解
筆者注:一句話引發(fā)的基礎(chǔ)知識(shí)回爐,基礎(chǔ)不扎實(shí),還要什么自行車
最近在看 React 方面的一些文章時(shí),看到了這樣一個(gè)問(wèn)題,「為什么每個(gè) class 中都要寫(xiě) super, super 是做什么的?」, 剛看到這個(gè)問(wèn)題時(shí),直接就想到了繼承行為在 javascript 中的表現(xiàn)。后面作者的一句話「super 不可以省略,省略的話會(huì)報(bào)錯(cuò)」。當(dāng)時(shí)腦海中蹦出來(lái)一個(gè)念頭,這個(gè)同學(xué)是不是寫(xiě)錯(cuò)了,super 不就是用來(lái)完成調(diào)用父類構(gòu)造函數(shù),將父類的實(shí)例屬性掛在到 this 上嗎?為什么不寫(xiě)還會(huì)報(bào)錯(cuò)?
后來(lái)自己親自寫(xiě)了一個(gè) Demo 嘗試了一下,還真是會(huì)報(bào)錯(cuò),到底是哪里出了問(wèn)題,找到了阮老師的教程又打開(kāi)仔細(xì)看了一遍,發(fā)現(xiàn)里面還真是有這樣一句話:
子類必須在 constructor 方法中調(diào)用 super 方法,否則新建實(shí)例時(shí)會(huì)報(bào)錯(cuò)。這是因?yàn)樽宇愖约旱?this 對(duì)象,必須先通過(guò)父類的構(gòu)造函數(shù)完成塑造,得到與父類同樣的實(shí)例屬性和方法,然后再對(duì)其進(jìn)行加工,加上子類自己的實(shí)例屬性和方法。如果不調(diào)用 super 方法,子類就得不到 this 對(duì)象。
原來(lái)如此,ES6 中 this 對(duì)象的構(gòu)造方式發(fā)生了變化。
ES5 中的繼承
// Shape - 父類(superclass)
function Shape() {
this.x = 0;
this.y = 0;
}
// 父類的方法
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info('Shape moved.');
};
// Rectangle - 子類(subclass)
function Rectangle() {
Shape.call(this); // call super constructor.
}
// 子類續(xù)承父類
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
console.log('Is rect an instance of Rectangle?',
rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?',
rect instanceof Shape); // true
rect.move(1, 1); // Outputs, 'Shape moved.'
如上所示: 展示了一個(gè) ES5 中實(shí)現(xiàn)單繼承的例子,在《Javascript 高級(jí)程序設(shè)計(jì)》一書(shū)中,給這種繼承方式定義為「寄生組合式繼承」。不管什么形式,什么命名,在 ES5 中實(shí)現(xiàn)繼承始終就是要堅(jiān)持一個(gè)原則:將實(shí)例屬性放在構(gòu)造函數(shù)中掛在this上,將一些方法屬性掛在原型對(duì)象上,子類可共享。 上面這種繼承方式的關(guān)鍵在于兩點(diǎn):
- 子類構(gòu)造函數(shù)通過(guò) apply 或者 call 的方式運(yùn)行父類的構(gòu)造函數(shù),此舉將父類的實(shí)例屬性掛在子類的 this 對(duì)象上
- 以父類的原型對(duì)象為基礎(chǔ),與子類的原型對(duì)象之間建立原型鏈關(guān)系,使用了 Object.create,本質(zhì)在于 Child.prototype.__proto === Parent.prototype;
ES6 中的繼承
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); // 調(diào)用父類的constructor(x, y)
this.color = color;
}
toString() {
return this.color + ' ' + super.toString();
}
}
ES6 中的繼承使用到了 extends 關(guān)鍵字,function 也變成了 class 關(guān)鍵字。class 的本質(zhì)還是一個(gè)語(yǔ)法糖,這個(gè)大家都會(huì)脫口而出,但是在繼承機(jī)制這里到底是如何做到的,我們看一下 babel 在此處是如何幫我們轉(zhuǎn)譯的,
var ColorPoint =
/*#__PURE__*/
function (_Point) {
_inherits(ColorPoint, _Point);
function ColorPoint(x, y, color) {
var _this;
_classCallCheck(this, ColorPoint);
_this = _possibleConstructorReturn(this, _getPrototypeOf(ColorPoint).call(this, x, y)); // 調(diào)用父類的constructor(x, y)
_this.color = color;
return _this;
}
_createClass(ColorPoint, [{
key: "toString",
value: function toString() {
return this.color + ' ' + _get(_getPrototypeOf(ColorPoint.prototype), "toString", this).call(this);
}
}]);
return ColorPoint;
}(Point);
如上是經(jīng)過(guò)babel轉(zhuǎn)譯后的代碼,有幾個(gè)關(guān)鍵點(diǎn):
一、 _inherits()
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);
}
首先完成extends對(duì)象的校驗(yàn),必須是function 或者null,否則報(bào)錯(cuò)。其次完成以下事情:
ColorPoint.__proto__ === Point; ColorPoint.prototype.__proto__ === Point.prototype;
二、 ColorPoint 構(gòu)造函數(shù)中 _classCallCheck(), _possibleConstructorReturn()
function _classCallCheck(instance, Constructor) {
if (!_instanceof(instance, Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
主要是用來(lái)檢測(cè)構(gòu)造函數(shù)不能直接調(diào)用,必須是通過(guò)new的方式來(lái)調(diào)用。
function _possibleConstructorReturn(self, call) {
if (call && (_typeof(call) === "object" || typeof call === "function")) {
return call;
}
return _assertThisInitialized(self);
}
調(diào)用父類的構(gòu)造函數(shù),初始化一些實(shí)例屬性,并將this返回。使用該返回的this賦值給子類的this對(duì)象,子類通過(guò)這一步返回的this對(duì)象,再該基礎(chǔ)之上在添加一些實(shí)例屬性。
這就是最大的不同之處。如果不經(jīng)歷這一步,子類沒(méi)有this對(duì)象,一旦操作一個(gè)不存在的this對(duì)象就會(huì)報(bào)錯(cuò)。
三、 _createClass()
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
最后一步完成原型屬性與靜態(tài)屬性的掛載,如果是原型屬性,掛在在Constructor上的prototype上,如果是靜態(tài)屬性或者靜態(tài)方法,則掛在Constuctor 上。
總結(jié)
基礎(chǔ)知識(shí)要打牢,不是為了面試,前期打不勞,后面很多事情就會(huì)變的模棱兩可,別人問(wèn)到的時(shí)候,就會(huì)是「可能」、「也許」。不積跬步何以至千里 ,加油。
參考鏈接
http://es6.ruanyifeng.com/#docs/class-extends
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create
https://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=false&presets=es2015%2Creact%2Cstage-2&targets=&browsers=&builtIns=false&debug=false&code_lz=Q
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持我們。
上一篇:微信小程序如何獲取地址
欄 目:JavaScript
下一篇:淺析vue-router中params和query的區(qū)別
本文標(biāo)題:繼承行為在 ES5 與 ES6 中的區(qū)別詳解
本文地址:http://www.jygsgssxh.com/a1/JavaScript/9404.html
您可能感興趣的文章
- 01-10在Vue項(xiàng)目中使用Typescript的實(shí)現(xiàn)
- 01-10Vuex實(shí)現(xiàn)數(shù)據(jù)共享的方法
- 01-10推薦幾個(gè)不錯(cuò)的console調(diào)試技巧實(shí)現(xiàn)
- 01-10在JavaScript中實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用的實(shí)現(xiàn)
- 01-10vue遠(yuǎn)程加載sfc組件思路詳解
- 01-10使用pkg打包ThinkJS項(xiàng)目的方法步驟
- 01-10在weex中愉快的使用scss的方法步驟
- 01-10vue項(xiàng)目中在可編輯div光標(biāo)位置插入內(nèi)容的實(shí)現(xiàn)代碼
- 01-10微信小程序wxs實(shí)現(xiàn)吸頂效果
- 01-10如何在Node和瀏覽器控制臺(tái)中打印彩色文字


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02javascript點(diǎn)線,點(diǎn)線的代碼
- 04-02javascript潛力,javascript強(qiáng)大嗎
- 04-02javascript替換字符串,js字符串的替換
- 04-02javascript移出,js 移入移出
- 04-02包含javascript舍的詞條
- 04-02javascript并行,深入理解并行編程 豆瓣
- 04-02javascript匿名,js匿名方法
- 04-02javascript警報(bào),JavaScript警告
- 04-02javascript遮蓋,JavaScript遮蓋PC端頁(yè)面
- 04-02javascript前身,javascript的前身
隨機(jī)閱讀
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 04-02jquery與jsp,用jquery
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-10delphi制作wav文件的方法
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 01-11Mac OSX 打開(kāi)原生自帶讀寫(xiě)NTFS功能(圖文
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-10C#中split用法實(shí)例總結(jié)


