day19_JS_繼承進(jìn)階
1.JS中的繼承
繼承是面向?qū)ο笾幸粋€(gè)比較核心的概念诡壁。
其他正統(tǒng)面向?qū)ο笳Z(yǔ)言都會(huì)有兩種方式實(shí)現(xiàn)繼承:一個(gè)是接口實(shí)現(xiàn)鳞陨,一個(gè)是繼承颠猴。
而JS只是繼承,不支持接口實(shí)現(xiàn)而姐,而實(shí)現(xiàn)繼承的方式依靠原型鏈完成腊凶。
在js里划咐,被繼承的函數(shù)稱為超類型(父類拴念,基類也行,其他語(yǔ)言叫法)
繼承的函數(shù)稱為子類型(子類褐缠,派生類)政鼠。
繼承也有之前問(wèn)題,比如字面量重寫原型會(huì)中斷關(guān)系队魏,使用引用類型的原型公般,并且子類型還無(wú)法給超類型傳遞參數(shù)。
為了解決引用共享和超類型無(wú)法傳遞參數(shù)的問(wèn)題胡桨,我們采用一種借用構(gòu)造函數(shù)的技術(shù)或者成為對(duì)象冒充(偽造對(duì)象官帘、經(jīng)典繼承)的技術(shù)來(lái)解決這兩種問(wèn)題。
-
冒充式繼承
function Box(_a) { this.a = _a; this.play(); } // 添加一個(gè)實(shí)例化屬性和方法 Box.prototype.a = 10; Box.prototype.play = function () { } // 添加一個(gè)靜態(tài)屬性和方法 Box.b = 20; Box.run = function () { } function Ball(_a) { //此處會(huì)出錯(cuò)昧谊,this.play is not a function Box.call(this, _a); } var b = new Ball(10); console.loe(b);
-
組合式繼承
function Box(_a) { console.log("aaa");//打印兩次aaa this.a = _a; this.play(); } // 添加一個(gè)實(shí)例化屬性和方法 Box.prototype.a = 10; Box.prototype.play = function () { } // 添加一個(gè)靜態(tài)屬性和方法 Box.b = 20; Box.run = function () { } function Ball(_a) { // Box.call(this,_a); this.a = _a; this.play(); } Ball.prototype = new Box(); // 將原來(lái)constructor中的Box替換為Ball Ball.prototype.constructor = Ball; var b = new Ball(10); console.log(b); // 缺點(diǎn):原型中a的屬性值沒(méi)有繼承到
-
原型式繼承
function Box(_a) { console.log("aaa");//打印兩次aaa this.a = _a; this.play(); } // 添加一個(gè)實(shí)例化屬性和方法 Box.prototype.a = 10; Box.prototype.play = function () { } // 添加一個(gè)靜態(tài)屬性和方法 Box.b = 20; Box.run = function () { } function Ball(_a) { Box.call(this, _a); } function F() { } F.prototype = Box.prototype; Ball.prototype = new F(); Ball.prototype.constructor = Ball; let b = new Ball(10); console.log(b);
-
寄生式繼承
- 版本一(相對(duì)容易理解)
function Box(_a) { this.a = _a; this.play(); } // 添加一個(gè)實(shí)例化屬性和方法 Box.prototype.a = 10; Box.prototype.play = function () { } // 添加一個(gè)靜態(tài)屬性和方法 Box.b = 20; Box.run = function () { } function extend(subClass, supClass) { // 創(chuàng)建一個(gè)中間替代類,防止多次執(zhí)行父類(超類)的構(gòu)造函數(shù) function F() { } // 將父類的原型賦值給這個(gè)中間替代類 F.prototype = supClass.prototype; // 將原子類的原型保存 var proto = subClass.prototype; // 將子類的原型設(shè)置為中間替代類的實(shí)例對(duì)象 subClass.prototype = new F(); // 將原子類的原型復(fù)制到子類原型上,合并超類原型和子類原型的屬性方法 var names = Object.getOwnPropertyNames(proto); for (var i = 0; i < names.length; i++) { var desc = Object.getOwnPropertyDescriptor(proto, names[i]); Object.defineProperty(subClass.prototype, names[i], desc); } // 設(shè)置子類的構(gòu)造函數(shù)時(shí)自身的構(gòu)造函數(shù),以防止因?yàn)樵O(shè)置原型而覆蓋構(gòu)造函數(shù)(防止) subClass.prototype.constructor = subClass; // 給子類的原型中添加一個(gè)屬性,可以快捷的調(diào)用到父類的原型方法 subClass.prototype.superClass = supClass.prototype; // 如果父類的原型構(gòu)造函數(shù)指向的不是父類構(gòu)造函數(shù),重新指向(防止) if (supClass.prototype.constructor !== supClass) { supClass.prototype.constructor = supClass; } } function Ball(_a) { this.superClass.constructor.call(this, _a); } Ball.prototype.play = function () { //執(zhí)行超類的play方法 this.superClass.play.call(this); } Object.defineProperty(Ball.prototype, "d", { value: 20 }) extend(Ball, Box); var b = new Ball(10); console.log(b);
- 版本二(ES5)
function Box(_a) { this.a = _a; this.play(); } // 添加一個(gè)實(shí)例化屬性和方法 Box.prototype.a = 10; Box.prototype.play = function () { } // 添加一個(gè)靜態(tài)屬性和方法 Box.b = 20; Box.run = function () { } Function.prototype.extend = function (supClass) { function F() { } F.prototype = supClass.prototype; var proto = this.prototype; this.prototype = new F(); var names = Object.getOwnPropertyNames(proto); for (var i = 0; i < names.length; i++) { var desc = Object.getOwnPropertyDescriptor(proto, names[i]); Object.defineProperty(this.prototype, names[i], desc); } this.prototype.constructor = this; this.prototype.superClass = supClass.prototype; if (supClass.prototype.constructor !== supClass) { supClass.prototype.constructor = supClass; } } function Ball(_a) { this.superClass.constructor.call(this, _a); } Ball.prototype.play = function () { this.superClass.play.call(this); } Object.defineProperty(Ball.prototype, "d", { value: 20 }) Ball.extend(Box); var b = new Ball(10); console.log(b);
還有其他混入式繼承等刽虹,博主就不一一羅列了~~~