成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript之深入各種繼承

tomlingtm / 402人閱讀

摘要:通常有這兩種繼承方式接口繼承和實(shí)現(xiàn)繼承。理解繼承的工作是通過調(diào)用函數(shù)實(shí)現(xiàn)的,所以是寄生,將繼承工作寄托給別人做,自己只是做增強(qiáng)工作。適用基于某個(gè)對(duì)象或某些信息來創(chuàng)建對(duì)象,而不考慮自定義類型和構(gòu)造函數(shù)。

一、繼承的概念

繼承,是面向?qū)ο笳Z言的一個(gè)重要概念。
通常有這兩種繼承方式:接口繼承實(shí)現(xiàn)繼承。接口繼承只繼承方法簽名,而實(shí)現(xiàn)繼承則繼承實(shí)際的方法。

《JS高程》里提到:“由于函數(shù)沒有簽名,在‘ECMAScript’中無法實(shí)現(xiàn)接口繼承。”

等等,函數(shù)簽名是什么東西?據(jù)MDN文檔定義如下:

函數(shù)簽名(類型簽名、方法簽名)定義了函數(shù)或方法的輸入與輸出。

簽名可包含以下內(nèi)容:

參數(shù) 及參數(shù)的 類型

一個(gè)的返回值及其類型

可能會(huì)拋出或傳回的異常

該方法在 面向?qū)ο蟪绦蛑械目捎眯苑矫娴男畔ⅲㄈ鏿ublic、static或prototype)。

看起來好復(fù)雜啊,我們換成強(qiáng)類型的語言的角度會(huì)不會(huì)更好理解?
譬如,C的函數(shù)簽名就是我們熟悉的函數(shù)聲明:

int func(double d);

此時(shí):參數(shù)名為d,參數(shù)類型為double,返回值為func(d),返回值類型為int
再如,Java的函數(shù)簽名:

public static void main(String[] args)

此時(shí):參數(shù)名為args,參數(shù)類型為String [],返回值類型為void所以該方法沒有返回值,訪問修飾符public表示該方法是公有方法,static表示該方法是一個(gè)類方法而非實(shí)例方法……

現(xiàn)在,我們知道函數(shù)簽名是怎么回事了。那么,接口繼承又是什么東西?相信大家會(huì)遙想起Java中的interfaceimplements等……在此就不班門弄斧了。

我們知道,JavaScript是類型松散的語言,不像Java它們有嚴(yán)格的變量類型檢查。所以,JS的函數(shù)才沒有簽名,才無法實(shí)現(xiàn)接口繼承。

那么,JS的實(shí)現(xiàn)繼承是怎么回事呢?

二、JS的繼承

原型鏈的基本模式
理解:通過創(chuàng)建SuperType的實(shí)例,并將該實(shí)例賦給SubType.prototype,來實(shí)現(xiàn)SubType繼承SuperType。instance的原型指向SubType,SubType的原型指向SuperType,SuperType的原型指向Object,如此構(gòu)成了原型鏈。
缺點(diǎn):對(duì)象實(shí)例共享所有繼承的屬性和方法,不適宜多帶帶適用

function SuperType() {
    this.property = true;
}
SuperType.prototype.getSuperValue = function() {
    return this.property;
};
function SubType() {
  this.subproperty = false;
}
//SubType繼承SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function() {
  return this.subproperty;
};
var instance = new SubType();
alert(instance.getSuperValue());  //true

于是,有下一個(gè)招式,來解決包含引用類型值的原型屬性會(huì)被所有實(shí)例共享的弱點(diǎn)。

借用構(gòu)造函數(shù)
理解:“借用”超類型構(gòu)造方法,在新的子類型對(duì)象上執(zhí)行超類型函數(shù)定義的所有對(duì)象初始化代碼
適用:解決超類型的引用類型值被所有子類型對(duì)象實(shí)例共享,而且子類型可向超類型傳參
缺點(diǎn):不能做到函數(shù)復(fù)用,從而降低效率,不適宜多帶帶適用

function SuperType(name) {
  this.name = name;
  this.colors = ["red", "blue", "green"]; //引用類型值
}
function SubType() {
  SuperType.call(this, "A"); //繼承SuperType “借用”超類型的構(gòu)造函數(shù) 并傳參
  this.age = 20;    //實(shí)例屬性
}
var instance1 = new SubType();    //instance1.name: "A", instance1.age: 20
instance1.colors.push("black"); //instance1.colors: "red, blue, green, black"
var instance2 = new SubType();  //instance2.colors: "red, blue, green"

接下來,組合技能出大招!

組合繼承
理解:將原型鏈和借用構(gòu)造函數(shù)組合到一起,通過原型鏈來繼承共享的原型屬性和方法,通過借用構(gòu)造函數(shù)來繼承實(shí)例屬性。
適用:最常用的繼承模式。
缺點(diǎn):調(diào)用兩次超類型構(gòu)造函數(shù),在SubType上創(chuàng)建了多余的屬性,造成超類型對(duì)象的實(shí)例屬性的重寫

function SuperType(name) {
  this.name = name;
  this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
  alert(this.name);
};
function SubType(name, age) {
  SuperType.call(this, name);   //繼承屬性 第二次調(diào)用超類型構(gòu)造函數(shù) 新實(shí)例得到兩個(gè)實(shí)例屬性name,colors
  this.age = age;
}
SubType.prototype = new SuperType();  //繼承方法 第一次調(diào)用超類型構(gòu)造函數(shù) SubType.prototype得到兩個(gè)實(shí)例屬性name,colors
SubType.prototype.sayAge = function() {
  alert(this.age);
};

var instance1 = new SubType("妹妹", 18);
instance1.colors.push("black");
alert(instance1.colors);  //"red, blue, green, black"
instance1.sayName();  //"妹妹"
instance1.sayAge();  //18

var instance2 = new SubType("弟弟", 20);
alert(instance2.colors);  //"red, blue, green"
instance2.sayName();  //"弟弟"
instance2.sayAge();  //20

這是打boss的大招,那我怎么對(duì)付小怪?

原型式繼承
理解:本質(zhì)是對(duì)給定對(duì)象的淺復(fù)制
適用:不必預(yù)先定義構(gòu)造函數(shù)來實(shí)現(xiàn)繼承,只想讓一個(gè)對(duì)象與另一個(gè)對(duì)象保持類似
缺點(diǎn):引用類型值的屬性被共享,如同原型模式一樣

function object(o) {    //對(duì)o進(jìn)行淺復(fù)制
  function F() {}    //創(chuàng)建一個(gè)臨時(shí)性的構(gòu)造函數(shù)
  F.prototype = o;    //將傳入的對(duì)象o作為F的原型
  return new F();    //返回F的新實(shí)例
}

var person = {
  name: "A",
  friends: ["B", "C", "D"]
};
var anotherPerson = object(person);    // Object.create(person)
anotherPerson.name = "E";
anotherPerson.friends.push("F");
var yetAnotherPerson = object(person);    //Object.create(person)
yetAnotherPerson.name = "G";
yetAnotherPerson.friends.push("H");
alert(person.friends);  //"B, C, D, F, H" 引用類型值的屬性被共享啦

注意:Object.create()方法的第二個(gè)參數(shù),新對(duì)象的額外屬性的對(duì)象,會(huì)覆蓋原型對(duì)象上的同名屬性。

var anotherPerson = Object.create(person, {
  name: { value: "E" }
});
alert(anotherPerson.name);   // "E"

打了這么久,能不能讓小招也升級(jí)(封裝)一下???

寄生式繼承

創(chuàng)建一個(gè)僅用于封裝繼承過程的函數(shù),該函數(shù)在內(nèi)部以某種方式來增強(qiáng)對(duì)象,最后再像真的是它做了所有工作一樣返回對(duì)象。

理解:繼承的工作是通過調(diào)用函數(shù)實(shí)現(xiàn)的,所以是“寄生”,將繼承工作寄托給別人做,自己只是做增強(qiáng)工作。
適用:基于某個(gè)對(duì)象或某些信息來創(chuàng)建對(duì)象,而不考慮自定義類型和構(gòu)造函數(shù)。
缺點(diǎn):不能做到函數(shù)復(fù)用,從而降低效率

 function createAnother(original) {
   var clone = object(original); //通過調(diào)用函數(shù)創(chuàng)建一個(gè)新對(duì)象
   clone.sayHi = function() {  //以某種方式來增強(qiáng)這個(gè)對(duì)象
     alert("hi");
   }
   return clone;
 }
 var person = {
   name: "A",
   friends: ["B", "C", "D"]
 };
 var anotherPerson = createAnother(person);  //不僅有person所有屬性方法,還有自己的sayHi方法
 anotherPerson.sayHi();  //"hi"

經(jīng)驗(yàn)攢足,我要把之前打boos的組合大招升到滿級(jí)!

寄生組合繼承
理解:通過借用構(gòu)造函數(shù)來繼承屬性,通過原型鏈的混用形式來繼承方法。用寄生式繼承來繼承超類型的原型,再將增強(qiáng)后的結(jié)果指定給子類型的原型。
適用:引用類型最理想的繼承模式,高效,只調(diào)用了一個(gè)SuperType構(gòu)造函數(shù)

function inheritPrototype(subType, superType) {
  var prototype = object(superType.prototype); //創(chuàng)建對(duì)象 超類型原型的副本
  prototype.constructor = subType;  //增強(qiáng)對(duì)象 彌補(bǔ)因重寫原型而失去默認(rèn)的constructor屬性
  subType.prototype = prototype;  //指定對(duì)象
}

function SuperType(name) {
  this.name = name;
  this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
  alert(this.name);
};
function SubType(name, age) {
  SuperType.call(this, name);   //繼承屬性
  this.age = age;
}
inheritPrototype(SubType, SuperType);  //繼承方法
SubType.prototype.sayAge = function() {
  alert(this.age);
};

三、ES6的繼承
extends關(guān)鍵字用來創(chuàng)建一個(gè)普通類或者內(nèi)建對(duì)象的子類。
class A {
    ...
}
class B extends A {
    ...
}

其中,

B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true

因?yàn)?b>extends實(shí)現(xiàn)了:

Object.setPrototypeOf(B.prototype, A.prototype);    //B.prototype.__proto__ = A.prototype;

Object.setPrototypeOf(B, A);    //B.__proto__ = A

extends更具體的實(shí)現(xiàn)方法參見面試官問:JS的繼承,在此就不班門弄斧了~

完~若有不足,請(qǐng)多指教,不勝感激!

以上代碼借鑒于《JS高級(jí)程序設(shè)計(jì)》

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/103867.html

相關(guān)文章

  • JavaScript深入繼承的多種方式和優(yōu)缺點(diǎn)

    摘要:深入系列第十五篇,講解各種繼承方式和優(yōu)缺點(diǎn)。優(yōu)點(diǎn)融合原型鏈繼承和構(gòu)造函數(shù)的優(yōu)點(diǎn),是中最常用的繼承模式。寄生組合式繼承為了方便大家閱讀,在這里重復(fù)一下組合繼承的代碼組合繼承最大的缺點(diǎn)是會(huì)調(diào)用兩次父構(gòu)造函數(shù)。 JavaScript深入系列第十五篇,講解JavaScript各種繼承方式和優(yōu)缺點(diǎn)。 寫在前面 本文講解JavaScript各種繼承方式和優(yōu)缺點(diǎn)。 但是注意: 這篇文章更像是筆記,哎...

    JackJiang 評(píng)論0 收藏0
  • 深入理解JavaScript

    摘要:深入之繼承的多種方式和優(yōu)缺點(diǎn)深入系列第十五篇,講解各種繼承方式和優(yōu)缺點(diǎn)。對(duì)于解釋型語言例如來說,通過詞法分析語法分析語法樹,就可以開始解釋執(zhí)行了。 JavaScript深入之繼承的多種方式和優(yōu)缺點(diǎn) JavaScript深入系列第十五篇,講解JavaScript各種繼承方式和優(yōu)缺點(diǎn)。 寫在前面 本文講解JavaScript各種繼承方式和優(yōu)缺點(diǎn)。 但是注意: 這篇文章更像是筆記,哎,再讓我...

    myeveryheart 評(píng)論0 收藏0
  • JavaScript深入從原型到原型鏈

    摘要:深入系列的第一篇,從原型與原型鏈開始講起,如果你想知道構(gòu)造函數(shù)的實(shí)例的原型,原型的原型,原型的原型的原型是什么,就來看看這篇文章吧。讓我們用一張圖表示構(gòu)造函數(shù)和實(shí)例原型之間的關(guān)系在這張圖中我們用表示實(shí)例原型。 JavaScript深入系列的第一篇,從原型與原型鏈開始講起,如果你想知道構(gòu)造函數(shù)的實(shí)例的原型,原型的原型,原型的原型的原型是什么,就來看看這篇文章吧。 構(gòu)造函數(shù)創(chuàng)建對(duì)象 我們先...

    Songlcy 評(píng)論0 收藏0
  • JavaScript深入系列15篇正式完結(jié)!

    摘要:寫在前面深入系列共計(jì)篇已經(jīng)正式完結(jié),這是一個(gè)旨在幫助大家,其實(shí)也是幫助自己捋順底層知識(shí)的系列。深入系列自月日發(fā)布第一篇文章,到月日發(fā)布最后一篇,感謝各位朋友的收藏點(diǎn)贊,鼓勵(lì)指正。 寫在前面 JavaScript 深入系列共計(jì) 15 篇已經(jīng)正式完結(jié),這是一個(gè)旨在幫助大家,其實(shí)也是幫助自己捋順 JavaScript 底層知識(shí)的系列。重點(diǎn)講解了如原型、作用域、執(zhí)行上下文、變量對(duì)象、this、...

    fxp 評(píng)論0 收藏0
  • JavaScript深入創(chuàng)建對(duì)象的多種方式以及優(yōu)缺點(diǎn)

    摘要:深入系列第十四篇,講解創(chuàng)建對(duì)象的各種方式,以及優(yōu)缺點(diǎn)。也就是說打著構(gòu)造函數(shù)的幌子掛羊頭賣狗肉,你看創(chuàng)建的實(shí)例使用都無法指向構(gòu)造函數(shù)這樣方法可以在特殊情況下使用。 JavaScript深入系列第十四篇,講解創(chuàng)建對(duì)象的各種方式,以及優(yōu)缺點(diǎn)。 寫在前面 這篇文章講解創(chuàng)建對(duì)象的各種方式,以及優(yōu)缺點(diǎn)。 但是注意: 這篇文章更像是筆記,因?yàn)椤禞avaScript高級(jí)程序設(shè)計(jì)》寫得真是太好了! 1....

    Terry_Tai 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<