前端基础复习-继承

原型链继承

原型链的基本概念

首先理清构造函数,原型,以及实例的关系。构造函数都有一个prototype属性,指向它的原型。

同时原型又有一个contructor属性指向构造函数。通过构造函数创建的实例都有一个指针[[prototype]](在chrome等浏览器中有属性_proto_)指向

构造函数的原型。如果把原型对象等于另一个类型的实例,这样实例的原型对象中就包含了指向另一个原型对象的指针,而另外一个原型对象包含着指向构造函数

的指针,从而使用它的属性和方法,如此层层递进构成的实例与原型的链条就是原型链。

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function superType() {
this.prototype = true;
}
superType.prototype.getSuperValue = function () {
return this.prototype;
};
function SubType() {
this.subproperty = false;
}
//实现继承
SubType.prototype = new superType();

SubType.prototype.getSubValue = function () {
return this.subproperty;
};

var instance = new SubType();
console.log(instance.getSuperValue());//true

完整的原型链中还有一个所有引用类型默认继承的对象Object,toString(),valueOf()一些默认方法都来自于Object。
在上面的例子中supertype的原型对象中有一个属性[[prototype]]指向Object的原型对象,说明supertype继承与Object

确定原型和实例的关系

instanceof

instanceof操作符测试实例与原型链中出现过的函数,如果出现过则返回true

1
2
3
alert(instance instanceof SubType);//true
alert(instance instanceof Object);//true
alert(instance instanceof superType);//true

重写超类型中的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function superType() {
this.prototype = true;
}
superType.prototype.getSuperValue = function () {
return this.prototype;
};
function SubType() {
this.subproperty = false;
}

SubType.prototype = new superType();
//添加新方法
SubType.prototype.getSubValue = function () {
return this.subproperty;
};
//重写方法
SubType.prototype.getSuperValue = function() {
return false;
}

var instance = new SubType();
console.log(instance.getSuperValue());//true

这个例子中在subtype的原型重写了getSuperValue方法,因此在subtype的实例中调用新方法,但是在supertyoe的实例中仍然会调用原来的方法
要注意的是定义方法必须在用supertype的实例替换原型后。

原型链的问题

原型属性中,如果包含引用类型的值,那这个属性会被所有实例共享。在通过原型继承时,原型事实上会变成另一个类型的实例,所以实例属性会变成现在原型的属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function superType() {
this.colors = ['red','blue','green'];
}

function SubType() {

}
SubType.prototype = new superType();

var instance1 = new SubType();
instance1.colors.push('white');
alert(instance1.colors)//'red','blue','green','white'

var instance2 = new SubType();//'red','blue','green','white'所有的实例都共享了修改后的属性

借用构造函数

使用call或者apply,在子类型中调用超类型的构造函数.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function superType() {
this.colors = ['red','blue','green'];
}

function SubType() {
//继承superType
superType.call(this)
}


var instance1 = new SubType();
instance1.colors.push('white');
alert(instance1.colors)//'red',blue,green,white'
var instance2 = new SubType();
alert(instance2.colors)//'red,blue,green'

借用构造函数继承还可以传递参数

1
2
3
4
5
6
7
8
9
10
11
function superType(name) {
this.name = name
}
function SubType(){
superType.call(this,'phil')
this.age = 21
}

var instance = new SubType()
console.log(instance.name);//phil
console.log(instance.age);//21

组合式继承方法

组合式继承结合以上两种方法,用构造函数完成实例中属性的继承,用原型链完成原型属性方法的继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function superType(name) {
this.name = name
this.colors = ['red','blue','green'];
}
superType.prototype.sayName = function () {
alert(this.name);
};

function SubType(name, age) {
superType.call(this, name);//继承属性
this.age = age
}
SubType.prototype = new superType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
alert(this.age)
}

var instance1 = new SubType('phil', 21);
instance1.colors.push('white');
alert(instance1.colors);//'red',blue,green,white'
instance1.sayName();//phil
instance1.sayAge();//age
var instance2 = new SubType('joy', 41);
alert(instance2.colors);//'red',blue,green'
instance2.sayName();//phil
instance2.sayAge();//age