繼承

繼承

許多OO語(yǔ)言都支持兩種繼承方式:接口繼承和實(shí)現(xiàn)繼承。接口繼承只繼承方法簽名,而實(shí)現(xiàn)繼承則繼承實(shí)際的方法。由于函數(shù)沒有簽名,在ECMAScript中無(wú)法實(shí)現(xiàn)接口繼承,ECMAScript只支持實(shí)現(xiàn)繼承,而且其實(shí)實(shí)現(xiàn)繼承的主要是依靠原型鏈來實(shí)現(xiàn)的。

一、原型鏈

基本思想是利用原型讓一個(gè)引用型繼承另一個(gè)引用類型的屬性和方法。

構(gòu)造函數(shù)、原型和實(shí)例的關(guān)系:

每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象,原型對(duì)象包含一個(gè)指向構(gòu)造函數(shù)的指針,而實(shí)例包含一個(gè)指向原型對(duì)象的內(nèi)部指針。

      // 構(gòu)造函數(shù) SuperType
      function SuperType() {
        this.property = true;
      }

      SuperType.prototype.getSuperValue = function () {
        return this.property;
      };

      // 構(gòu)造函數(shù) SubType
      function SubType() {
        this.subproperty = false;
      }

      // 繼承了 SuperType
      SubType.prototype = new SuperType();

      SubType.prototype.getSubValue = function () {
        return this.subproperty;
      };

      var instance = new SubType();
      alert(instance.getSuperValue());

那么,讓原型對(duì)象等于另一個(gè)類型的實(shí)例,此時(shí)的原型對(duì)象將包含一個(gè)指向另一個(gè)原型的指針,相應(yīng)地,另一個(gè)原型中也包含一個(gè)指向另一個(gè)原型的指針。假如另一個(gè)原型又是另一個(gè)原型的實(shí)例,那么上述關(guān)系依然成立,如此層層遞進(jìn),就構(gòu)成了實(shí)例與原型的鏈條。這就是所謂原型鏈的基本概念。

  1. 確定原型和實(shí)例的關(guān)系

    a. instanceof

    b. isPrototypeOf()

  2. 原型鏈的問題

    在通過原型來實(shí)現(xiàn)繼承時(shí),原型實(shí)際上會(huì)變成另一個(gè)類型的實(shí)例。于是,原先的實(shí)例屬性也就順理成章地變成了現(xiàn)在的原型屬性。

      function SuperType() {
        this.colors = ["red", "blue", "green"];
      }

      function SubType() {}

      SubType.prototype = new SuperType();

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

      var instance2 = new SubType();
      alert(instance2.colors); //"red,blue,green,black"

3.1.SubType通過原型鏈繼承了SuperType之后,SubType.protype就變成了SubperType的一個(gè)實(shí)例,因此它也擁有了一個(gè)它自己的colors屬性,就跟專門創(chuàng)建了一個(gè)SubType.prototype.colors屬性一樣。結(jié)果SubType的所有實(shí)例都會(huì)共享這一個(gè)colors屬性。

3.2 創(chuàng)建子類型的實(shí)例時(shí),不能想超類型的構(gòu)造函數(shù)傳遞參數(shù)。不能在不影響所有對(duì)象類型的情況下,給超類型的構(gòu)造函數(shù)傳遞參數(shù)。

二、借用構(gòu)造函數(shù)

這種也稱為偽造對(duì)象或經(jīng)典繼承,即在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型構(gòu)造函數(shù)。

      function SuperType() {
        this.colors = ["red", "blue", "green"];
      }

      function SubType() {
        SuperType.call(this);
      }

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

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

2.1 傳遞參數(shù)

      function SuperType(name) {
        this.name = name;
      }

      function SubType() {
        SuperType.call(this, "Nicholas");

        this.age = 29;
      }

      var instance = new SubType();
      alert(instance.name);
      alert(instance.age);

2.2 構(gòu)造函數(shù)的問題

方法都在構(gòu)造函數(shù)中定義,無(wú)法做到函數(shù)復(fù)用

三、組合繼承

組合繼承,有時(shí)候也叫做偽經(jīng)典繼承,指的是將原型鏈和借用構(gòu)造函數(shù)的技術(shù)組合到一塊,從而發(fā)揮二者之長(zhǎng)的一種繼承模式。思路是使用原型鏈實(shí)現(xiàn)對(duì)原型屬性和方法的繼承,而通過借用構(gòu)造函數(shù)來實(shí)現(xiàn)對(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);

        this.age = age;
      }

      // 繼承方法
      SubType.prototype = new SuperType();

      SubType.prototype.sayAge = function () {
        alert(this.age);
      };

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

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

組合繼承是最常用的繼承模式。

四、原型式繼承

借助已有的對(duì)象創(chuàng)建新對(duì)象,同時(shí)還不必因此創(chuàng)建自定義類型。

      function object(o) {
        function F() {}
        F.prototype = o;
        return new F();
      }

      var person = {
        name: "Nicholas",
        friends: ["Shelby", "Court", "Van"],
      };

      var anotherPerson = object(person);
      anotherPerson.name = "Greg";
      anotherPerson.friends.push("Rob");

      var yetAnotherPerson = object(person);
      yetAnotherPerson.name = "Linda";
      yetAnotherPerson.friends.push("Barbie");

      alert(person.friends);

ECMAScript5通過新增Object.create()方法規(guī)范化了原型式繼承。這個(gè)方法接收兩個(gè)參數(shù):一個(gè)用作新對(duì)象原型的對(duì)象和一個(gè)為新對(duì)象定義額外屬性的對(duì)象。

      var person = {
        name: "Nicholas",
        friends: ["Shelby", "Court", "Van"],
      };

      var anotherPerson = Object.create(person);
      anotherPerson.name = "Greg";
      anotherPerson.friends.push("Rob");

      var yetAnotherPerson = Object.create(person);
      yetAnotherPerson.name = "Linda";
      yetAnotherPerson.friends.push("Barbie");

      alert(person.friends);

五、寄生式繼承

寄生式繼承的思路與寄生構(gòu)造函數(shù)和工廠模式類似,即創(chuàng)建一個(gè)僅用于封裝繼承過程的函數(shù),該函數(shù)在內(nèi)部以某種方式來增強(qiáng)對(duì)象,最后再像真地是它做了所有工作一樣返回對(duì)象。

      function object(o) {
        function F() {}
        F.prototype = o;
        return new F();
      }
      function createAnother(original) {
        var clone = Object(original);
        clone.sayHi = function () {
          alert("Hi");
        };
        return clone;
      }
      var person = {
        name: "Nicholas",
        friends: ["Shelby", "Court", "Van"],
      };

      var anotherPerson = createAnother(person);
      anotherPerson.sayHi();

不能做到函數(shù)復(fù)用;

六、寄生組合繼承

組合繼承最大問題是無(wú)論什么情況下,都會(huì)調(diào)用兩次超類型構(gòu)造函數(shù):一次是創(chuàng)建子類型的時(shí)候,另一次是在子類型構(gòu)造函數(shù)內(nèi)部。

      function object(o) {
        function F() {}
        F.prototype = o;
        return new F();
      }
      function inheritPrototype(subType, superType) {
        // 創(chuàng)建對(duì)象
        var prototype = object(superType.prototype);
        // 增強(qiáng)對(duì)象
        prototype.constructor = subType;
        // 指定對(duì)象
        subType.prototype = prototype;
      }

      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);
      };

只調(diào)用了一次SuperType構(gòu)造函數(shù),最理想的繼承方式

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 繼承是 OO 語(yǔ)言中的一個(gè)最為人津津樂道的概念。許多 OO 語(yǔ)言都支持兩種繼承方式:接口繼承 和 實(shí)現(xiàn)繼承。接口繼...
    threetowns閱讀 491評(píng)論 0 0
  • 1.繼承(接口繼承和實(shí)現(xiàn)繼承) 繼承是 OO 語(yǔ)言中的一個(gè)最為人津津樂道的概念。許多 OO 語(yǔ)言都支持兩種繼承方式...
    believedream閱讀 1,058評(píng)論 0 3
  • 一、原型鏈 學(xué)過java的同學(xué)應(yīng)該都知道,繼承是java的重要特點(diǎn)之一,許多面向?qū)ο蟮恼Z(yǔ)言都支持兩種繼承方式:接口...
    grain先森閱讀 1,480評(píng)論 0 39
  • 內(nèi)容來自《JavaScript高級(jí)程序設(shè)計(jì)》第三版第6章第3節(jié) 原型鏈 ECMAScript中描述了 原型鏈的概念...
    angelwgh閱讀 283評(píng)論 0 0
  • 1、構(gòu)造函數(shù)模式 [url=]file:///C:/Users/i037145/AppData/Local/Tem...
    橫沖直撞666閱讀 927評(píng)論 0 0

友情鏈接更多精彩內(nèi)容