1.原型鏈繼承
核心思想是構(gòu)造函數(shù)欠痴,實(shí)例對(duì)象以及原型這三者的關(guān)系
// 原型鏈繼承
function Person(){
this.name = "張大寶";
}
Person.prototype.getName = function(){
console.log(this.name);
}
function Student(){
}
Student.prototype = new Person();
var student = new Student();
student.getName(); // 張大寶
缺點(diǎn):
1.原型鏈中引用類型的屬性會(huì)被所有實(shí)例共享的,即所有實(shí)例對(duì)象使用的是同一份數(shù)據(jù)单刁,會(huì)相互影響。
function Person(){
this.colors = ["red", "green", "pink"];
}
function Student(){
}
Student.prototype = new Person();
var a1 = new Student();
var a2 = new Student();
a1.colors.push("white");
console.log(a2.colors); //"red", "green", "pink" ,"white"
2.在創(chuàng)建子類的實(shí)例時(shí)糕簿,不能向超類傳參(無(wú)法向父級(jí)構(gòu)造函數(shù)傳參)
2.借用構(gòu)造函數(shù)(經(jīng)典繼承)
核心思想是:在子級(jí)構(gòu)造函數(shù)中調(diào)用父級(jí)構(gòu)造函數(shù)。
如何實(shí)現(xiàn)在一個(gè)構(gòu)造函數(shù)中調(diào)用另一個(gè)函數(shù)?——call()和apply()
// 借用構(gòu)造函數(shù)繼承(經(jīng)典繼承)
function Person(){
this.name = "張大寶";
this.colors = ["red", "green", "pink"]];
}
Person.prototype.getName = function(){
console.log(this.name);
}
function Student(){
Person.call(this);
}
var a1 = new Student();
var a2 = new Student();
a1.colors.push("white");
console.log(a1.name);
console.log(a1.colors); // ["red", "green", "pink", "white"]
console.log(a2.colors); // ["red", "green", "pink"]
優(yōu)點(diǎn):
1.避免了引用類型的屬性被所有實(shí)例共享
2.可以在子類中向超類傳參
缺點(diǎn):
1.只能繼承父類的私有的屬性和方法,不能繼承原型上的屬性和方法;
2.無(wú)法實(shí)現(xiàn)構(gòu)造函數(shù)的復(fù)用术奖,每個(gè)子類都有父類實(shí)例函數(shù)的副本,影響性能轻绞,代碼會(huì)臃腫采记。
3.組合繼承
組合繼承 = 原型鏈 + 借用構(gòu)造函數(shù)。取其長(zhǎng)避其短:共享的用原型鏈铲球,各自的借用構(gòu)造函數(shù)
核心思路是使用原型鏈實(shí)現(xiàn)對(duì)原型屬性和方法的繼承挺庞,而通過(guò)借用構(gòu)造函數(shù)來(lái)實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承晰赞,這樣稼病,既通過(guò)在原型上定義方法實(shí)現(xiàn)了函數(shù)復(fù)用,又能保證每個(gè)實(shí)例都有它自己的屬性掖鱼。
function Parent(name){
this.name = name;
this.colors = ["red", "green", "pink"];
}
Parent.prototype.getName = function(){
console.log(this.name);
}
function Student(name,age){
Parent.call(this,name);// 第二次調(diào)用 Parent()
this.age = age;
}
Student.prototype = new Parent(); // 第一次調(diào)用 Parent()
var a1 = new Child("張大寶",18);
var a2 = new Child("張小寶",19);
a1.getName(); //張大寶
a2.getName();// 張小寶
console.log(a1.age); // 18
console.log(a2.age); // 19
child1.colors.push("white");
console.log(a1.colors); // ["red", "blue", "green", "white"]
console.log(a2.colors); // ["red", "blue", "green"]
console.log(a1 instanceof Child); // true
console.log(a2 instanceof Parent); // true
優(yōu)點(diǎn):融合原型鏈繼承和構(gòu)造函數(shù)的優(yōu)點(diǎn)然走,是JavaScript中最常用的繼承模式
缺點(diǎn):調(diào)用了兩次父類構(gòu)造函數(shù)
(組合繼承最大的問(wèn)題是無(wú)論什么情況下,都會(huì)調(diào)用兩次超類型構(gòu)造函數(shù):一次是在創(chuàng)建子類型原型的時(shí)候戏挡,另一次是在子類型構(gòu)造函數(shù)內(nèi)部)
4.原型式繼承
在createObj()函數(shù)內(nèi)部,先創(chuàng)建了一個(gè)臨時(shí)性的構(gòu)造函數(shù),然后將傳入的對(duì)象作為這個(gè)構(gòu)造函數(shù)的原型,最后返回了這個(gè)臨時(shí)類型的一個(gè)新實(shí)例.從本質(zhì)上講,createObj()對(duì)傳入其中的對(duì)象執(zhí)行了一次淺復(fù)制.
// 原型式繼承
function createObj(o){
function F(){}
F.prototype = o;
return new F()
}
var person = {
name:"張大寶",
colors:["red","pink","green"]
}
var a1 = createObj(person)
a1.name = "張小寶"
a1.colors.push = "white"
console.log(a1.name) // 張小寶
console.log(a1.colors) // "red","pink","green","white"
var a2 = createObj(person)
console.log(a2.name) // 張大寶
console.log(a2.colors) // "red","pink","green","white"
找對(duì)象上的屬性時(shí)芍瑞,總是先找實(shí)例上對(duì)象,沒(méi)有找到的話再去原型對(duì)象上的屬性褐墅。實(shí)例對(duì)象和原型對(duì)象上如果有同名屬性拆檬,總是先取實(shí)例對(duì)象上的值
缺點(diǎn): 包含引用類型的屬性值始終都會(huì)共享相應(yīng)的值, 這點(diǎn)跟原型鏈繼承一樣
ECMAScript5通過(guò)新增Object.create()方法規(guī)范化了原型式繼承妥凳,這個(gè)方法接收兩個(gè)參數(shù):
一個(gè)用作新對(duì)象原型的對(duì)象和一個(gè)作為新對(duì)象定義額外屬性的對(duì)象竟贯。
上面的代碼還可以這樣寫:
在傳入一個(gè)參數(shù)的情況下,Object.create()與createObj()方法的行為相同
var person = {
name:"張大寶",
colors:["red","pink","green"]
}
var a1 = Object.create(person)
a1.name = "張小寶"
a1.colors.push = "white"
console.log(a1.name) // 張小寶
console.log(a1.colors) // "red","pink","green","white"
var a2 = Object.create(person)
console.log(a2.name) // 張大寶
console.log(a2.colors) // "red","pink","green","white"
Object.create()方法的第二個(gè)參數(shù)與object.defineProperties()方法的第二個(gè)參數(shù)格式相同:每個(gè)屬性都是通過(guò)自己的描述符定義的
var a1 = Object.create(person,{
name:{
value:"張二寶"
});
console.log(a1.name); // 張二寶
5.寄生式繼承
在原型式繼承的基礎(chǔ)上逝钥,在函數(shù)內(nèi)部豐富對(duì)象
function fun(obj) {
function Son() { };
Son.prototype = obj;
return new Son();
}
function JiSheng(obj) {
var clone = fun(obj); // 通過(guò)調(diào)用函數(shù)創(chuàng)建一個(gè)新對(duì)象
clone.Say = function () { // 以某種方式來(lái)增強(qiáng)這個(gè)對(duì)象
console.log('我是新增的方法');
}
return clone; // 返回這個(gè)對(duì)象
}
var parent = {
name: '張三'
}
var parent1 = JiSheng(parent);
var parent2 = JiSheng(parent);
console.log(parent2.Say==parent1.Say);// false
優(yōu)缺點(diǎn):跟借用構(gòu)造函數(shù)類似屑那,調(diào)用一次函數(shù)就得創(chuàng)建一遍方法,無(wú)法實(shí)現(xiàn)函數(shù)復(fù)用艘款,效率較低持际。
6.寄生組合式繼承
利用組合繼承和寄生繼承各自優(yōu)勢(shì)
寄生組合式繼承,是集寄生式繼承和組合繼承的有點(diǎn)與一身哗咆,主要是通過(guò)借用構(gòu)造函數(shù)來(lái)繼承屬性蜘欲,通過(guò)原型鏈的混成形式來(lái)繼承方法。它的缺點(diǎn)是兩次調(diào)用父級(jí)構(gòu)造函數(shù)晌柬,一次是在創(chuàng)建子級(jí)原型的時(shí)候姥份,另一次是在子級(jí)構(gòu)造函數(shù)內(nèi)部呜叫,那么我們只需要優(yōu)化這個(gè)問(wèn)題就行了,即減少一次調(diào)用父級(jí)構(gòu)造函數(shù)殿衰,正好利用寄生繼承的特性朱庆,繼承父級(jí)構(gòu)造函數(shù)的原型來(lái)創(chuàng)建子級(jí)原型。
function JiSheng(son,parent) {
var clone = Object.create(parent.prototype);//創(chuàng)建對(duì)象
son.prototype = clone; //指定對(duì)象
clone.constructor = son; //增強(qiáng)對(duì)象
}
function Parent(name){
this.name = name;
this.type = ['JS','HTML','CSS'];
}
Parent.prototype.Say=function(){
console.log(this.name);
}
function Son(name){
Parent.call(this,name);
}
JiSheng(Son,Parent);
son1 = new Son('張三');
son2 = new Son('李四');
son1.type.push('VUE');
son2.type.push('PHP');
console.log(son1.type);//['JS','HTML','CSS','VUE']
console.log(son2.type);//['JS','HTML','CSS','PHP']
son1.Say();//張三
son2.Say();//李四
優(yōu)缺點(diǎn):組合繼承優(yōu)點(diǎn)闷祥、寄生繼承的優(yōu)點(diǎn)娱颊,目前JS繼承中使用的都是這個(gè)繼承方法
7.ES6里的extends繼承
class People{
constructor(name){
this.name = name;
}
walk(){
console.log(this.name + "會(huì)走路");
}
}
class Student extends People{
constructor(name){
super();//調(diào)用了父類的構(gòu)造函數(shù)
this.name = name;
}
}
var ZhangDaoBao = new Student("張大寶");
ZhangDaoBao.walk();//張大寶會(huì)走路