类与实例
首先,通过两种方式来声明一个类:
第一种,构造函数的方式
1 | function Animal1(name) { |
第二种,ES6中的class声明
1 | class Animal2 { |
两种方式生成实例的方式是一样的
1 | var animal = new Animal1('dog') |
实现继承
第一种:借助构造函数实现继承
1 | function Parent1() { |
这种继承的方式只能继承构造函数内部的属性,缺点是不能继承构造函数原型对象上的属性,如下1
2
3Parent1.prototype.say = function() {
console.log('hello')
}
这时候,say方法Child1是继承不到的
第二种:借助原型链实现继承
1 | function Parent2() { |
这个方法中,child的属性方法先有构造函数Child2内部的属性age,然后我们知道每个对象都有一个_ proto _ 属性,指向构造函数的prototype,这时child._ proto _ === Child2.prototype,然后就继承到Parent2上的属性及方法了
这个方法也有个缺点,如果Parent2中有个属性值是引用类型的,如下1
2
3
4function Parent2() {
this.name = 'parent2'
this.color = ['red', 'green']
}
这时候我们生成两个child实例1
2
3var child1 = new Child2()
var child2 = new Child2()
child1.color.push('blue')
这时候child2.color也会有’blue’,这肯定不是我们想要的结果。这时因为child1._ proto _ 和child2._ proto _都指向Child2.prototype,而Child2.prototype的值是一个实例对象
第三种:组合方式
1 | function Parent3() { |
这种方式可以实现构造函数体内的属性以及原型对象上的属性与方法,但有个缺点,就是我们新生成一个child实例时,Parent3构造函数执行了两次,这样是没必要的,所以继续优化一下,如下:1
2
3
4
5
6
7
8function Parent4() {
this.name = 'parent4'
}
function Child4() {
Parent3.call(this)
this.age = 16
}
Child4.prototype = Parent4.prototype
这种方式也有一个缺点,就是新生成的child实例的constructor会指向Parent4而不是Child4,那继续来优化一下:1
2
3
4
5
6
7
8
9function Parent5() {
this.name = 'parent5'
}
function Child5() {
Parent3.call(this)
this.age = 16
}
Child5.prototype = Object.create(Parent5.prototype)
Child5.prototype.constructor = Child5
至此,继承就完美实现了。
有问题,欢迎指正!