生活随笔
收集整理的這篇文章主要介紹了
JavaScript | 继承
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
—————————————————————————————————————————————————————————
繼承 - ECMAScript只支持實現繼承(依靠原型鏈),不支持接口繼承(函數沒有簽名)
原型鏈
- 利用原型讓一個引用類型繼承另一個引用類型的屬性和方法,
- 構造函數、原型、實例的關系:每個構造函數都有一個原型對象,原型對象包含一個指向構造函數的指針。實例包含一個指向原型對象的內部指針,在創建實例之后即指向原型對象
- 而當A原型對象的指針指向B個原型對象時(此時A原型對象與B實例同級),就形成了一條原型鏈。
- 圖解:
原型搜索機制:當讀取模式訪問一個實例屬性時,首先會在實例中搜索該屬性,如果沒有找到該屬性則沿著原型鏈向上查找
在例子<Demo-1>中,調用instance.getSuperValue(),先搜索實例instance,再搜索SubType.prototype,再搜索SuperType.protorype,最后一步才找到該方法。
默認的原型:所有的引用類型默認都繼承了Object,所以默認原型的指針都會指向Object.prototype,完整的原型鏈如下:
instance → SubType.prototype → SuperType.prototype → Object.prototype
- p.s.
必須替換掉實例的原型后才能給實例添加方法
不能使用對象字面量創建原型方法,這樣做會重寫原型鏈,如<Demo-3>
- 缺點:
包含引用類型值(Function Object Array)的原型屬性會被所有實例共享,在通過原型來實現繼承時,原型實際上會變成另一個類型的實例,所以原先的實例屬性就變成了現在的原型屬性了。<Demo-4>
在創建子類型的實例時,不能向超類型的構造函數中傳遞參數。
// "use strict";// Demo - 1
// SuperType 擁有一個屬性和一個方法
// SubType 擁有一個屬性和一個方法,又從SuperType那里繼承了一個屬性一個方法
function SuperType(){this.property = "111"
;
}
SuperType.prototype.getSuperValue =
function(){return this.property;
}
function SubType(){this.subproperty = "222"
;
}
// p.s.new操作之前,SubType.prototype指向的是function,不允許為function()定義.getSubValue方法,所以要將添加方法放在修改原型指向之后
// 操作之后SubType.prototype指向SuperType
SubType.prototype =
new SuperType();
SubType.prototype.getSubValue =
function(){
// 必須在SubType替換原型之后才能定義return this.subproperty;
}
var instance =
new SubType();
console.log(instance.property); // 111
console.log(instance.getSuperValue());
// 111
console.log(instance.subproperty);
// 222
console.log(instance.getSubValue());
// 222
console.log(instance.constructor);
// f SuperType(){} 原本SubType中的constructor屬性被重寫
// 重寫SuperType.getSuperValue()
// 如果要重寫這個方法,會屏蔽原來的方法
// 換句話說,當通過SubType的實例調用getSuperValue時調用的就是這個重新定義的方法,但通過SuperType的實例調用時還會繼續調用原來的方法
var beforeReWrite =
new SuperType();
SuperType.prototype.getSuperValue =
function(){console.log("rewrite"
);
}
console.log(instance.getSuperValue()); // rewrite,this.property = undefined
console.log(SuperType.prototype.getSuperValue());
// rewrite,this.property = undefined
console.log(beforeReWrite.getSuperValue());// Demo - 2
// 確認原型和實例的關系
console.log(instance
instanceof Object);
// true
console.log(instance
instanceof SuperType);
// true
console.log(instance
instanceof SubType);
// true
// 另一種方法
console.log(Object.prototype.isPrototypeOf(instance));
// true
console.log(SuperType.prototype.isPrototypeOf(instance));
// true
console.log(SubType.prototype.isPrototypeOf(instance));
// true// Demo - 3
function SuperType2(){this.property = "1111"
;
}
SuperType2.prototype.getSuperValue =
function(){return this.property;
}
function SubType2(){this.subproperty = "2222"
;
}
SubType2.prototype =
new SuperType2();
SubType2.prototype =
{getSubValue:function(){return this.subproperty;},someOtherMethod:function(){return false;}
}
var instance2 =
new SubType2();
console.log(instance2 instanceof Object);
// true
console.log(instance2
instanceof SuperType2);
// false,原型鏈被切斷
console.log(instance2
instanceof SubType2);
// true
// console.log(instance2.getSuperValue()); // error// Demo - 4
function SuperType3(){this.colors = ["red","blue","green"
];
}
function SubType3(){}
SubType3.prototype =
new SuperType3();
var instance3 =
new SubType3();
instance3.colors.push("black"
);
console.log(instance3.colors); // ["red", "blue", "green", "black"]
var instance4 =
new SubType3();
console.log(instance4.colors); // ["red", "blue", "green", "black"] ?
借用構造函數(偽造對象 / 經典繼承)
// "use strict";function SuperType(name) {this.name =
name;this.colors = ["111", "222", "333"
];
}function SubType() {SuperType.call(this, "name1"
);this.age = 20
;
}var instance =
new SubType();
instance.colors.push("444"
);
console.log(instance.colors); // ["111", "222", "333", "444"]
console.log(instance.name);
// name1
console.log(instance.age);
// 20
var instance2 =
new SubType();
console.log(instance2.colors); // ["111", "222", "333"] ?
組合繼承(偽經典繼承)
- 將原型鏈和借用構造函數組合,使用原型鏈實現對原型屬性和方法的繼承,通過借用構造函數來實現對實例屬性的繼承
- 對應創建對象 <組合使用構造函數模式和原型模式>
- 優點:最常用
- 缺點:需要調用兩次超類型構造函數,一次在創建子函數原型時,另一次在子函數構造函數內部。調用子類型構造函數時需要重寫屬性
// "use strict";
function SuperType(name) {this.name =
name;this.colors = ["111", "222", "333"
];
}
SuperType.prototype.sayName =
function() {console.log(this.name);
}function SubType(name, age) {SuperType.call(this, name);
// 繼承屬性this.age =
age;
}
SubType.prototype =
new SuperType();
// 繼承方法
SubType.prototype.constructor =
SubType;
SubType.prototype.sayAge =
function() {console.log(this.age);
}
var instance1 =
new SubType("hugh", 20
);
instance1.colors.push("444"
);
console.log(instance1.colors); // ["111", "222", "333", "444"]
instance1.sayName();
// hugh
instance1.sayAge();
// 20
var instance2 =
new SubType("dong", 21
);
console.log(instance2.colors); // ["111", "222", "333"]
instance2.sayName();
// dong
instance2.sayAge();
// 21 ?
原型式繼承
// "use strict";
function object(o){function F(){}
// 創建臨時性構造函數F.prototype = o;
// 將傳入的對象作為構造函數的原型return new F();
// 返回臨時類型的一個新實例
}var person =
{name:"hugh"
,friends:["111",'222','333'
]
};var anotherPerson =
object(person);
anotherPerson.name = "dong"
;
anotherPerson.friends.push("444"
);var yetAnotherPerson =
object(person);
yetAnotherPerson.name = "hehe"
;
yetAnotherPerson.friends.push("555"
);console.log(person.friends); // ["111", "222", "333", "444", "555"]
console.log(person.name);
// hugh
console.log(anotherPerson.friends);
// ["111", "222", "333", "444", "555"]
console.log(anotherPerson.name);
// dong
console.log(yetAnotherPerson.friends);
// ["111", "222", "333", "444", "555"]
console.log(yetAnotherPerson.name);
// hehe// 使用Object.create()規范化原型式繼承
// 以這種方式指定的任何屬性都會覆蓋原型對象上的同名屬性
var otherPerson1 =
Object.create(person);
otherPerson1.friends.push("666"
);
console.log(yetAnotherPerson.friends); // ["111", "222", "333", "444", "555", "666"]
var otherPerson2 =
Object.create(person,{name:{value:"test"
}
});
console.log(otherPerson2.name); ?
寄生式繼承
- 對應創建對象 <寄生構造函數 / 工廠模式>
- 創建一個僅用于封裝繼承過程的函數,在內部增強對象,最后返回對象
- 示范集成模式時使用的object()函數不是必須的,任何能夠返回新對象的函數都適用于此模式
- 使用場景:在主要考慮對象而不是自定義類型和構造函數的情況下,寄生式繼承也是一種有用的模式
- 缺點:無法做到函數復用,類似于構造函數模式
// "use strict";
function object(o) {function F() {}
// 創建臨時性構造函數F.prototype = o;
// 將傳入的對象作為構造函數的原型return new F();
// 返回臨時類型的一個新實例
}function createAnother(original) {
// 接收的函數作為新對象基礎的對象var clone =
object(original);clone.sayHi =
function() {
// 添加新方法console.log('hi'
);};return clone;
}
var person =
{name: "hugh"
,friends: ['111', '222', '333'
]
};
var person1 =
createAnother(person);
person1.sayHi();
console.log(person1.name);
console.log(person1.friends); ?
寄生組合式繼承
- 優點:
最理想的繼承范式
解決組合繼承重寫屬性的問題,只調用了一次SuperType構造函數
避免了在SubType.prototype上創建不必要的屬性
原型鏈保持不變
能夠正常使用instanceof和isPrototypeOf()
"use strict"
;
function object(o) {function F() {}F.prototype =
o;return new F();
}// 1.創建超類型原型的一個副本
// 2.為創建的副本添加constructor屬性,彌補因重寫原型而失去的屬性
// 3.將新創建的對象(即副本)賦值給子類型的原型
function inheritProtoType(subType,superType){var prototype = object(superType.prototype);
// 創建對象prototype.constructor = subType;
// 增強對象subType.prototype = prototype;
// 指定對象
}
function SuperType(name){this.name =
name;this.colors= [1,2,3,4
];
}
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);
}
轉載于:https://www.cnblogs.com/hughdong/p/7264122.html
總結
以上是生活随笔為你收集整理的JavaScript | 继承的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。