继承就是子类可以使用父类的所有功能,并且对这些功能进行扩展。
原型链继承
function Parent () {
this.name = 'Parent'
this.sex = 'boy'
}
Parent.prototype.getName = function () {
console.log(this.name)
}
function Child () {
this.name = 'child'
}
Child.prototype = new Parent()//子类的原型指向父类的实例
var child1 = new Child()
child1.getName()//‘child’
console.log(child1)//Child {name:"child"}
child1
是通过子类构造函数Child
生成的对象,拥有自己的属性name
,并且属性值也是自己的child
。- 子类的实例可以使用父类实例的所有属性和方法,
getName
打印出name
。 - 由于
sex
、getName
都是Child
原型对象上的属性,所以并不会表现在child1
上。
原型继承的优缺点
function Parent(name){
this.name=name;
this.sex='boy';
this.color=['red']
}
function Child(){
this.friend=['jack']
}
var parent= new Parent('parent')
Child.prototype=parent;//子类原型指向父类实例
var child1=new Child('child1');
child1.sex='girl';
child1.color.push('blue');
child1.friend.push('mimi')
var child2=new Child('child2');
console.log(child1)
console.log(child2)
console.log(child1.name,child1.color)
console.log(parent)
此段代码运行的结果:
-
child1.sex = 'girl'
这段代码相当于是给child1这个实例对象新增了一个sex属性。相当于是:原本没有sex这个属性,我想要获取就得拿原型对象parent上的sex,但是现在你加了一句child1.sex就等于是我自己也有了这个属性了,就不需要你原型上的了,所以并不会影响到原型对象parent上 -
child1.colors
这里,是直接使用了.push(),也就是说得先找到colors这个属性,发现实例对象parent上有,然后就拿来用了,之后执行push操作,所以这时候改变的是原型对象parent上的属性,会影响到后续所有的实例对象。(因为操作的方式不同) -
而friend它是属于child1实例自身的属性,它添加还是减少都不会影响到其他实例。因此child1打印出了feature和sex两个属性。(name和colors属于原型对象上的属性并不会被表现出来)
-
虽然我们在new Child的时候传递了’child1’,但接收name属性的是构造函数Parent,而不是Child。child2.colors由于用的也是原型对象parent上的colors,由于之前被child1给改变了,所以打印出来的会是[‘white’, ‘black’, ‘yellow’]。最后的原型对象parent打印出来,name和sex没变,colors却变了。
-
优点
1)继承了父类的模板,又继承了父类的原型对象 -
缺点
1) 如果要给子类的原型上新增属性和方法,就必须放在Child.prototype = new Parent()
这样的语句后面
2)来自原型对象的所有属性都被共享了,如果不小心修改了原型对象中的引用类型属性,那么所有子类创建的实例对象都会受到影响。
3)创建子类时,无法向父类构造函数传参数
构造函数继承
function Parent (name) {
this.name = name