1. 程式人生 > >JavaScript之原型式繼承&寄生式繼承和寄生組合式繼承以及優缺點

JavaScript之原型式繼承&寄生式繼承和寄生組合式繼承以及優缺點

一.原型式繼承

1.這種方法並沒有使用嚴格意義上的建構函式,藉助原型可以基於已有的物件建立新的物件

function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}
// 在object()函式內部,先建立一個臨時性的建構函式,然後將傳入的物件作為這個建構函式原型,最後返回了這個臨時型別的一個新例項.
// object()本質上對其中傳入的物件進行了一次淺複製
// 看如下的例子:
var person = {
  name: "kebi",
  friends: ["kuli", "hadeng"]
};
var onePerson = object(person);
onePerson.name = "heyushuo";
onePerson.friends.push("heyushuo");
var twoPerson = object(person);
twoPerson.name = "yaoming";
twoPerson.friends.push("yaoming");

//這裡列印
console.log(twoPerson); //['kuli','hadeng','heyushuo','yaoming']

缺點: 包含引用型別的屬性值始終都會共享相應的值,和原型鏈繼承一樣。

2.ES5 通過新增 Object.create()方法規範化了原型式繼承,此方法可以接受兩個引數,第一個引數最為新物件原型的物件 和一個為新物件定義額外屬性的物件.

var person = {
  name: "kebi",
  friends: ["kuli", "hadeng"]
};
var onePerson = Object.create(person, {
  name: "heyushuo"
});
onePerson.friends.push("heyushuo");
var twoPerson = Object.create(person, {
  name: "yaoming"
});
twoPerson.friends.push("yaoming");
//這裡列印
console.log(twoPerson); //['kuli','hadeng','heyushuo','yaoming']
// 主:在沒有必要建立建構函式,而是指向讓一個物件與另外一個物件保持類似的情況下,原型式繼承完全可以勝任

二.寄生式繼承

建立一個僅用於封裝繼承過程的函式,該函式在內部以某種形式來做增強物件,最後返回物件。

function createAnother(original) {
  var clone = object(original); // 通過呼叫 object() 函式建立一個新物件
  clone.sayHi = function() {
    // 以某種方式來增強物件
    console.log("hi");
  };
  return clone; // 返回這個物件
}
// 函式的主要作用是為建構函式新增屬性和方法,以增強函式
var person = {
  name: "Nicholas",
  friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); //"hi"```

缺點:

  1. 原型繼承存在的缺點他都存在
  2. 使用寄生式繼承為物件新增方法,會由於不能做到方法的複用而降低效率,這一點和建構函式模式類似

三.寄生組合式繼承

寄生組合式繼承, 即通過借用建構函式來繼承屬性, 在原型上新增共用的方法, 通過寄生式實現繼承.

//寄生式繼承的基本模式
function inheritPrototype(subType, superType) {
  var prototype = Object.create(superType.prototype); // 建立物件,建立父類原型的一個副本
  prototype.constructor = subType; // 增強物件,彌補因重寫原型而失去的預設的constructor 屬性
  subType.prototype = prototype; // 指定物件,將新建立的物件賦值給子類的原型
}

// 父類初始化例項屬性和原型的屬性和方法
function SuperType(name) {
  this.name = name;
  this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
  console.log(this.name);
};

// 借用建構函式繼承建構函式的例項的屬性(解決引用型別共享的問題)
function SubType(name, age) {
  SuperType.call(this, name);
  this.age = age;
}

// 將子型別的原型重寫替換成父類的原型
inheritPrototype(SubType, SuperType);

// 對子類新增自己的方法
SubType.prototype.sayAge = function() {
  console.log(this.age);
};

var instance1 = new SubType("heyushuo");
var instance2 = new SubType("kebi");
instance1.sayName(); //heyushuo
instance2.sayName(); //kebi
instance1.colors.push("yellow"); // ["red", "blue", "green", "yellow"]
instance1.colors.push("black"); // ["red", "blue", "green", "black"]

總結:

上邊的例子高效的體現了只調用了一次 SuperType 建構函式,並且因此也避免了在 SubType.prototype 上面建立不必要的 多餘的屬性.與此同時,原型鏈還能保持不變