一、对象
1、对象的创建(对象字面量)
对象字面量
var person = {
name: "Nicholas",
age: 29,
job: "Software Engineer",
sayName: function(){
alert(this.name);
}
};
工厂模式
function createPerson(name, age, job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
};
return o;
}
工厂模式有一个缺点:就是无法识别生成的实例的类型。
构造函数模式
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
构造函数模式生成的实例,比如person1,有一个属constructor,该属性指向他的构造函数Person。(还可以使用instanceof)。
这种方法并非没有缺点,使用构造函数的主要问题,就是每个方法都要在每个实例上重新创建一遍,比如如果我们创建了两个实例person1和person2,那这两个实例内部的sayName()函数是独立的两个Function()实例,并不相同,这完全没有必要,方法其实有一个通用的就够了,因此有了原型模式。
原型模式
每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。其实也就是调用构造函数生成的所有的实例共享的一个原型对象。
捋一捋原型对象中的概念:创建了自定义的构造函数(以Person为例)之后,该函数有一个prototype属性,这个属性指向函数的原型对象。而原型对象默认只会取得constructor 属性,这个属性包含一个指向prototype 属性所在函数的指针,Person.prototype.constructor 指向Person。当调用构造函数创建一个新实例(person1)后,该实例的内部将包含一个指针 __ proto __,这个属性指向构造函数的原型对象,而非构造函数。
明显:
Person.prototype指向Person的原型对象;
Person的原型对象.constructor 指向Person;
Person的实例person1.__ proto __指向Person的原型对象
注意:
- 虽然可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值(下层不能碰上层)。如果我们在实例中添加了一个属性,而该属性与实例原型中的一个属性同名,那我们就在实例中创建该属性,该属性将会屏蔽原型中的那个属性。换句话说,添加这个属性只会阻止我们访问原型中的那个属性,但不会修改那个属性。
- hasOwnProperty()方法,只在给定属性存在于对象实例中时,而不是属于原型时候,才会返回true。通过使用hasOwnProperty()方法,什么时候访问的是实例属性,什么时候访问的是原型属性就一清二楚了。
- 定义原型对象的时候一定要注意下面这种方式,此时constructor不在指向Person(而是Object),为了依旧指向Person,需要显式指定。这是因为尽管可以随时为原型添加属性和方法,并且修改能够立即在所有对象实例中反映出来,但如果是重写整个原型对象,那么情况就不一样了,把原型修改为另外一个对象就等于切断了构造函数与最初原型之间的联系。
function Person(){
}
Person.prototype = {
*constructor : Person,*(显式指示)
name : "Nicholas",
age : 29,
job: "Software Engineer",
sayName : function () {
alert(this.name);
}
};
原型模式也存在问题:原型中所有属性是被很多实例共享的,对于包含引用类型值的属性来说问题很大,比如原型中有一个属性是数组,在一个实例中向数组push一个值,那么在其他实例中获得的数组也会被改变。
组合使用构造函数模式和原型模式(最常用)
构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。例子:
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ["Shelby", "Court"];
}
Person.prototype = {
constructor : Person,
sayName : function(){
alert(this.name);
}
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Count,Van"
alert(person2.friends); //"Shelby,Count"
alert(person1.friends === person2.friends); //false
alert(person1.sayName === person2.sayName); //true