原型鏈繼承
function Parent() {
this.name = ['zhangsan']
}
Parent.prototype.getName = function() {
console.log(this.name)
}
function Child() {
}
Child.prototype = new Parent()
var child1 = new Child()
child1.getName() ['zhangsan']
缺點(diǎn):
-
引用類型的屬性被所有實(shí)例共享
child1.name.push('lisi') child1.getName() // ['zhangsan', 'lisi'] var child2 = new Child() child2.getName() // ['zhangsan', 'lisi']
在創(chuàng)建child的實(shí)例時(shí),不能像Parent傳參
借用構(gòu)造函數(shù)(經(jīng)典繼承)
function Parent() {
this.name = ['zhangsan', 'lisi']
}
function Child() {
Parent.call(this)
}
var child1 = new Child()
child1.name.push('wangwu')
console.log(child1.name) // ['zhangsan', 'lisi', 'wangwu']
var child2 = new Child()
console.log(child2.name) // ['zhangsan', 'lisi']
優(yōu)點(diǎn):
- 避免了引用類型的屬性被所有實(shí)例共享
- 可以在Child中向Parent傳參
function Parent(name) {
this.name = name
}
function Child(name) {
Parent.call(this, name)
}
var child1 = new Child('zhangsan')
console.log(child1.name) // zhangsan
var child2 = new Child('lisi')
console.log(child2.name) // lisi
缺點(diǎn):
- 方法都在構(gòu)造函數(shù)中定義,每次創(chuàng)建實(shí)例都會(huì)創(chuàng)建一遍方法
組合繼承(原型鏈繼承+經(jīng)典繼承)
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
}
Child.prototype = new Parent()
var child1 = new Child('zhangsan', 18)
child1.colors.push('black')
console.log(child1.name) // zhangsan
console.log(child1.age) // 18
console.log(child1.colors) // ['red', 'blue', 'green', 'black']
var child2 = new Child('lisi', 16)
console.log(child2.name) // lisi
console.log(child2.age) // 16
console.log(child2.colors) // ['red', 'blue', 'green']
優(yōu)點(diǎn):
融合原型鏈繼承和構(gòu)造函數(shù)的優(yōu)點(diǎn)哲银,是JavaScript中最常用的繼承模式
原型式繼承
function createObj(o) {
function F() {}
F.prototype = o
return new F()
}
就是ES5 Object.create的模擬實(shí)現(xiàn)童太,將傳入的對(duì)象作為創(chuàng)建的對(duì)象的原型移盆。
缺點(diǎn):
包含引用類型的屬性值始終都會(huì)共享相應(yīng)的值惰拱,這點(diǎn)跟原型鏈繼承很像
function createObj(o) {
function F() {}
F.prototype = o
return new F()
}
var person = {
name: 'zhangsan',
friends: ['lisi']
}
var person1 = createObj(person)
var person2 = createObj(person)
person1.name = 'person1'
console.log(person1.name) // person1
console.log(person2.name) // zhangsan
person1.friends.push('wangwu')
console.log(person2.friends) // ['lisi', 'wangwu']
注意:修改person1.name的值判没,person2.name的值并未發(fā)生改變仪吧,并不是因?yàn)閜erson1和person2有獨(dú)立的值庄新,而是因?yàn)閜erson1.name = ’person1‘,給person1添加了name值薯鼠,并非修改了原型上的name值择诈。
寄生式繼承
創(chuàng)建個(gè)僅用于繼承封裝過(guò)程的函數(shù),該函數(shù)在內(nèi)部以某種形式來(lái)做增強(qiáng)對(duì)象出皇,最后返回對(duì)象
function createObj(o) {
var clone = Object.create(o)
clone.sayName = function() {
console.log('hi')
}
return clone
}
缺點(diǎn):跟借用構(gòu)造函數(shù)模式一樣羞芍,每次創(chuàng)建對(duì)象都會(huì)創(chuàng)建一遍方法。
寄生組合式繼承
組合式繼承最大的缺點(diǎn)是會(huì)調(diào)用兩次父構(gòu)造函數(shù)
一次是設(shè)置子類型實(shí)例的原型的時(shí)候
Child.prototype = new Parent()
一次在創(chuàng)建子類型實(shí)例的時(shí)候
var child1 = new Child('zhangsan', 18)
// new的時(shí)候郊艘,會(huì)執(zhí)行
Parent.call(this, name)
如何避免這一次的重復(fù)調(diào)用
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
}
// 關(guān)鍵步驟
var F = function() {}
F.prototype = Parent.prototype
Child.prototype = new F()
var child1 = new Child('zhangsan', 18)
封裝一下這個(gè)繼承方法
function object(o) {
function F() {}
F.prototype = o
return new F()
}
function prototype(child, parent) {
var prototype = object(parent.prototype)
prototype.constructor = child
child.prototype = prototype
}