js之各種繼承(二)

原型繼承

  • object.create()有兩個參數,第一個是用作新對象原型的對象,第二個參數是可選項,是一個定義額外新屬性的對象。
  • object.create()使得新創建的anotherPerson對象的__proto__指針指向person的原型對象
  • 需要注意的是,原型式繼承中, 包含引用類型值的屬性始終都會共享相應的值, 就像使用原型模式一樣,無法實現複用
// 無第二個參數
var person = {
	friends : ["Van","Louis","Nick"]
};
var anotherPerson = Object.create(person);
anotherPerson.friends.push("Rob");
var yetAnotherPerson = Object.create(person);
yetAnotherPerson.friends.push("Style");
alert(person.friends);//"Van,Louis,Nick,Rob,Style"
// create第二個參數的使用方法
var person = {
	name : "Van"
};
var anotherPerson = Object.create(person, {
	name : {
		value : "Louis"
	}
});
alert(anotherPerson.name);//"Louis"

寄生式繼承

  • 寄生式繼承的思路與(寄生)構造函數和工廠模式類似, 即創建一個僅用於封裝繼承過程的函數,該函數在內部以某種方式來增強對象,最後再像真的是它做了所有工作一樣返回對象
  • 比起原型繼承,它將類似於Object.create()object()函數及一些操作封裝金一個函數中,外界直接調用它就彷彿繼承了它原來的父類一樣
var original = {
	friends : ["Van","Louis","Nick"]
};
// object() 對傳入其中的對象執行了一次淺複製,整個函數的工作就是讓一個對象的__proto__指針指向參數
function object(o){
	function F(){}
	F.prototype = o;
	return new F();
}
function createAnother(original){ // 創建一個函數封裝這些過程
	var clone = object(original); // 通過調用object函數創建一個新對象
	clone.sayHi = function(){ // 以某種方式來增強這個對象
		alert("hi");
	};
	return clone;//返回這個對象
}
var clone = createAnother(original);
console.log(clone.friends);
clone.sayHi()

寄生組合式繼承

  • 爲了解決組合繼承兩次調用父類構造函數的弊端(第一次是在子類型構造函數內部,第二次是在創建子類型原型的時候)
  • 寄生組合式繼承就是爲了降低調用父類構造函數的開銷而出現的
function extend(subClass,superClass){
	var prototype = object(superClass.prototype); // 創建對象
	prototype.constructor = subClass; // 增強對象
	subClass.prototype = prototype; // 指定對象
}
function Parent (name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}

Parent.prototype.getName = function () {
    console.log(this.name)
}

function Child (name, age) {
    Parent.call(this, name);
    this.age = age;
}
// object(o)方法的工作就是:
// 創建一個構造函數f
// 使該構造函數的prototype指針指向參數
// 創建f對象的一個實例,幷返回
// 在該函數調用完以後,f的構造函數便會銷燬,所以整個函數的工作就是讓一個對象的__proto__指針指向參數。
function object(o) { // 感覺相當於製作了一個parent的副本
    function F() {}
    F.prototype = o; // 繼承了傳入的參數,這段代碼extend中爲其傳人的參數是parent.prototype
    return new F();
    // 通過構造一個介於 Parent 與 Child 之間的對象,並使該對象的 prototype 屬性指向 Parent 的 prototype對象,
    // 來避開通過調用 Parent 構造函數的方式來產生一個 prototype 指向Parent prototype對象的對象。
}

function extend(child, parent) {
// 不直接child.prototype=parent.prototype呢?
// 原因 : 當我們想給 Child 的prototype裏面添加共享屬性或者方法時,如果其 prototype 指向的是 Parent 的 prototype,那麼在 Child 的 prototype 裏添加的屬性和方法也會反映在 Parent 的 prototype 裏面,
// 這明顯是不合理的,這樣做的後果是當我們只想使用 Parent 時,也能看見 Child 往裏面扔的方法和屬性。
// 所以需要每個構造函數都需要持有自己專用的prototype對象
    var prototype = object(parent.prototype); // 創建對象
    prototype.constructor = child; // 增強對象
    child.prototype = prototype; // 指向對象
}

extend(Child, Parent);
var child1 = new Child('kevin', '18');
console.log(child1);
  • object方法圖解:

img

在該函數調用完以後,f的構造函數便會銷燬,所以整個函數的工作就是讓一個對象的__proto__指針指向參數

上一篇在js之各種繼承(一)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章