1. 原型链式继承
缺点:由于俩个实例使用的是同一个原型对象,他们的内存空间是共享的,当其中一个变化时,另一个也跟着变化
function Parent() {
this.name = 'parent'
this.number = [1,2,3]
}
Parent.prototype.getName = function() {
return this.name // parent
}
function Child() {
this.newName = 'child'
}
Child.prototype = new Parent()
console.log(new Child())
2.构造函数继承(Parent.call(this))
缺点:父类原型对象中存在父类之前自己定义的方法,子类将无法继承这些方法
function Parent() {
this.name = 'parent'
}
Parent.prototype.getName = function() {
return this.name
}
let parent = new Parent()
console.log('getName-Parent:',parent.getName())
function Child() {
Parent.call(this) // 改变this指向,this是 Child函数
this.newName = 'child'
}
let child = new Child()
console.log('child:',child)
console.log('getName:',child.getName)
3.组合式继承
缺点: Parent执行了俩次, 第一次是改变Child的prototype的时候, 第二次是通过call方法调用Parent,Parent多构造一次就多进行了一次性能开销
function Parent() {
this.name = 'parent'
this.number = [1,2,3]
}
Parent.prototype.getName = function() {
return this.name
}
function Child() {
// 第二次调用Parent()
Parent.call(this) // 改变this指向
this.newName = 'child'
}
// 第一次调用 Parent()
Child.prototype = new Parent()
// 手动挂上构造器,指向自己的构造函数
Child.prototype.constructor = Child
var child1 = new Child()
var child2 = new Child()
child1.number.push(4)
console.log(child1.number, child2.number) // 不互相影响 [1,2,3,4] [1,2,3]
console.log(child1.getName()) // 'parent'
console.log(child1.getName()) // parent
4.原型继承:拷贝继承(Object.create()),这个方法接收俩个参数:一个是用作新对象原型的对象,而是新对象定义额外的对象,实现的是浅拷贝
缺点:多个实例的引用类型属性指向相同的内存地址,存在篡改的可能
let parent = {
name: 'parent',
number: [1,2,3],
getName: function() {
return this.name
}
}
let child1 = Object.create(parent)
child1.name = 'child1'
child1.number.push(4)
let child2 = Object.create(parent)
child2.number.push(5)
console.log(child1.name) // child1
console.log(child1.name === child1.getName()) // true
console.log(child2.name) // parent
console.log(child1.number) // [1,2,3,4,5]
console.log(child2.number) // [1,2,3,4,5]
5.寄生式继承
在原型继承的基础上,再添加一些方法,进行返回
缺点:同原型继承
let parent = {
name: 'parent',
number: [1,2,3],
getName: function() {
return this.name
}
}
function clone(original) {
let clone = Object.create(original)
clone.getNumber = function() {
return this.number
}
return clone
}
let child = clone(Parent)
console.log(child.getName()) // parent
console.log(child.getNumber()) // [1,2,3]
6.寄生组合式继承
extends基本和寄生组合式继承类似
function Parent() {
this.name: 'parent'
this.number: [1,2,3]
}
Parent.prototype.getName = function() {
return this.name
}
function Child() {
Parent.call(this)
this.newName = 'child'
}
function clone(parent, child) {
// 这里改用 Object.create 就可以减少组合继承中多进行一次构造的过程
child.prototype = Object.create(parent.prototype)
child.prototype.constructor = child
}
clone(Parent, Child)
Child.prototype.getNewName = function() {
return this.newName
}
let child = new Child()
console.log(child)
console.log(child.getName()) // parent
console.log(child.getNewName()) // child
示例
const foo = function(a) {
this.name = 'foo'
this.a = 'aa'
this.fun = function() {
console.log('baz:',a) // 3
}
function b() {
console.log('b:', a)
}
}
foo.prototype = {
c: function() {
console.log('this.name',this.name) // foo
console.log('c:', a) // a is not defined
}
}
const f = new foo(3)
console.log('f:',f)
f.fun() // 3
f.c() // this.name: foo a is not defined
f.b() // f.b is not a function