创建对象的方式
构造函数模式创建对象
function Person(name, age) {
this.name = name;
this.age = age;
this.getName = function() {
return this.name;
}
}
var amy = new Person("amy", 18);
var sam = new Person("sam", 23);
//构造函数创建对象的过程:
//1.创建了一个新对象amy
//2.构造函数中的this指向了amy这个新对象
//3.为amy添加属性(执行构造函数内的语句)
//4.返回这个新对象
构造函数还存在着一些问题:Person有两个实例amy和sam,他们都有执行相同代码的方法getName。但是对于amy和sam来说,他们的getName方法不是同一个Function的实例。对于小数目的实例来说,这没什么大不了,但是一旦实例数量较大,执行同一种功能的不同实例是很没有必要的。
this.getName = new Function("return this.name");
//可以看到,每次执行new Function()的时候都会创建一个实例对象。
解决这种问题的其中一个方式就是使用原型模式
原型模式创建对象
什么是原型对象?
函数的prototype属性:在ECMA标准中,只要创造了一个函数,就会为这个函数创建一个prototype属性。该属性指向的是该函数的原型对象。
函数的原型对象:函数的原型对象也会有一个默认的属性,constructor。该属性指向的是该函数。
function Person() {}
Person.prototype.name = "amy";
Person.prototype.age = 18;
Person.prototype.getName = function() {
return this.name;
};
实例对象的[proto]属性:该属性是指向该实例的构造函数的原型对象。
实例属性可覆盖原型属性:在搜索某个属性值时,首先会从实例对象的属性开始查找,找到则结束查找,否则将继续往构造函数的原型对象属性开始查找。
封装原型
如果每次想要给原型对象添加一个属性都要敲一次“Person.prototype.property”,这样将会浪费很多时间。封装原型的方式可以更好地封装所有属性和方法。
function Person(){}
Person.prototype = {
name = "amy",
age = 18,
getName = function(){
return name;
}
};
注意:此时你会发现,Person.prototype不再指向原来Person的那个原型对象了,即原型对象重写了。此时原型对象的constructor属性也会改变,变成Object构造函数。解决方法如下:
Person.prototype = {
constructor: Person, //加上这句
//...
};
结合构造函数模式和原型模式来创建对象
使用构造函数模式可以传入参数用以定义属性值,使用原型模式可以用于定义共同的属性和方法的同时还不用增加属性实例数。
原型链与继承
先使用一个例子来说明原型链
function Supertype(){
this.superProperty = true;
}
Supertype.prototype.getSuperValue = function(){
return this.superProperty;
};
function Subtype(){
this.subProperty = false;
}
Subtype.prototype = new Supertype();
Subtype.prototype.getSubValue = function(){
return this.subProperty;
};
var instance = new Subtype();
显然,通过将Subtype.prototype = new Supertype();使得Subtype的原型对象的proto属性指向了Supertype的原型对象,从而获取到了supertype的属性和方法。
原型链的问题:原型链最大的问题在于,构造函数内定义的属性应该是实例属性,但是一旦被继承,实例属性就会变成继承的对象的实例的原型属性。(书p167)
解决原型链继承问题——借用构造函数
function Supertype(){
this.superProperty = true;
}
Supertype.prototype.getSuperValue = function(){
return this.superProperty;
};
function Subtype(){
//继承属性
Supertype.call(this);
this.subProperty = false;
}
//继承方法
Subtype.prototype = new Supertype();
//添加新的方法
Subtype.prototype.getSubValue = function(){
return this.subProperty;
};
//重写超类型中的方法
Subtype.prototype.getSubValue = function(){
return false;
};
var instance = new Subtype();