在我们聊JavaScript的对象与继承之前,先来认识一个别的东西:构造函数。构造函数是对象和继承的基础,所以理解它至关重要。
1: JavaScript的构造函数是什么?
1: 它是一个普通的函数
2: 它内部用了this关键字
3: 它有一个prototype属性,这个prototype是一个对象(其实每一个函数都有prototype属性)
4: 这个prototype包含的是可以被继承的属性
接下来用代码来解释一下上面的文字:
function Apple(price, colour){
this.price = price;
this.colour = colour;
}
Apple.prototype.type = 'fruit'; //可被继承的属性
var appleRed = new Apple(10, 'red');
var appleGreen = new Apple(20, 'green');
appleRed.colour;//red
appleGreen.colour;//green
appleRed.type; //fruit
appleGreen.type;//fruit
以上是一个从原型对象(Apple)生成实例对象(appleGreen, appleRed)的例子。接下来看看基于构造函数继承:
首先假设有两个构造函数:
function Fruit(){
this.taste = 'sweet';
}
function Apple(color){
this.color = color;
}
我们希望Apple能继承Fruit,怎么做?总共有5种继承方法:
1: 构造函数绑定
在子构造函数中,在父构造器身上调用call或者apply方法
function Fruit(){
this.taste = 'sweet';
}
function Apple(color){
Fruit.apply(this, arguments);
this.color = color;
}
var appleRed = new Apple('red');
appleRed.taste;// 'sweet'
2: prototype赋值
实例化一个父对象,然后把它赋给子构造函数的prototype属性
function Fruit(){
this.taste = 'sweet';
}
function Apple(color){
this.color = 'red'
}
Apple.prototype = new Fruit();
Apple.prototype.constructor = Apple;//特别注意这一行
var appleRed = new Apple('red');
appleRed.taste;//'sweet'
appleRed.constructor === Apple;//true
每一个实例都有一个constructor,继承自构造函数的prototype的constructor属性。在执行了
Apple.prototype = new Fruit();
之后,相当于是把Apple的prototype这个对象整个覆盖了,这个时候 Apple.prototype.constructor是Fruit这个方法。这样子就意味这appleRed.constructor也是Fruit,这样继承就混乱了,因为appleRed明明是由Apple这个构造方法实例化出来的。所以我们要把Apple正确的constructor重新设置回去:
Apple.prototype.constructor = Apple;
3: 把父构造函数的prototype直接赋给子构造函数的prototype
function Fruit(){}
Fruit.prototype.taste = 'sweet';
function Apple(color){
this.color = 'red'
}
Apple.prototype = Fruit.prototype;
Apple.prototype.constructor = Apple;
var appleRed = new Apple('red');
appleRed.taste;//'sweet'
Fruit.prototype.constructor === Apple;//true
虽然实现了继承,但是现在Apple和Fruit的prototype指向了同一段内存,任何对Apple.prototype的修改都会影响到Fruit.prototype,所以代码最后一行的这种结果,是我们不愿意看到的。
4: 利用一个空的中介构造函数
其实第四种是第二种和第三种的结合
function Fruit(){}
Fruit.prototype.taste = 'sweet';
function Apple(color){
this.color = 'red'
}
var F = function(){};
F.prototype = Fruit.prototype;
Apple.prototype = new F();
Apple.prototype.constructor = Apple;
var appleRed = new Apple('red');
appleRed.taste;//'sweet'
appleRed.constructor === Apple;//true
1: 中介构造函数的prototype=父构造函数的prototype;
2: 子构造函数的prototype=中介构造函数的一个实例;
3: 把子构造函数的constructor复原为自己
5: copy继承
就是把父构造函数的prototype上的所有属性和方法拷贝进子构造方法。
function Fruit(){}
Fruit.prototype.taste = 'sweet';
function Apple(color){
this.color = color;
}
function extend(child, parent){
var c = child.prototype;
var p = parent.prototype;
for(var i in p){
c[i] = p[i];
}
}
extend(Apple, Fruit);//调用继承方法
var appleRed = new Apple('red');
appleRed.taste;//'sweet'
但是以上实现的是一个浅拷贝,浅拷贝存在一些问题。在实现继承的时候,到底要使用浅拷贝还是深拷贝,要根据具体的需求,具体可以看这一篇关于浅拷贝和深拷贝的对比
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。