ECMA-262把对象定义为:”无序属性的集合,其属性可以包含基本值、对象或者函数”。
我们可以把ECMAScript的对象想象成是拥有属性和方法的数据。
1.object的构造函数
创建自定义对象最简单的方式就是创建一个object的实例,然后为它添加属性和方法,早期JavaScript开发人员经常使用这个模式创建新对象。
var person = new Object();
person.name = "Nicholas";
person.age = 29;
person.job = "Software Engineer";
person.sayName = function () {
alert(this.name);
}
2.对象字面量
几年后,对象字面量成为创建这种对象的首选模式。
var person = {
name: "Nicholas",
age:29,
job:"Software Engineer",
sayName: function () {
alert(this.name);
}
};
问题:
虽然Object构造函数或对象字面量都可以用来创建单个对象,但这些方式有个明显的缺点:
使用同一个接口创建很多对象,会产生大量的重复代码。为解决这个问题,人们开始使用工厂模式的一种变体。
3.工厂模式
定义:开发人员用一种函数封装以特定接口创建对象的细节
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;
}
var person1 = createPerson("Nicholas", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");
问题:
工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题(即怎样知道一个对象的类型)。
4.构造函数模式
解决问题:解决对象识别的问题(即怎样知道一个对象的类型)
存在的问题:
1.在全局作用域中定义的函数实际上只能被某个对象(person1,person2)调用,这让全局作用域有点名不副实。
2.如果对象需要定义很多方法,就要定义很多个全局函数,于是我们这个自定义的引用类型就丝毫没有封装性可言。
规则:构造函数始终应以一个大写字母开头,非构造函数则应以小写字母开头
原生构造函数:Object和Array
自定义的构造函数,如下所示
1.person1和person2都有一个sayName()的方法,但那两个方法不是同一个Function的实例。
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function () {
alert(this.name);
};
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
2.通过把函数定义到构造函数外面解决这个问题
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = sayName;
}
function sayName() {
alert(this.name);
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
5.原型模式
解决的问题:
1.不必再构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象(prototype)中。
2.可以让所有实例对象 (var person1 = new Person(); ) 共享它所包含的属性和方法。
存在的问题:
向friends数组添加一个字符串,由于数组存在于prototype属性中,添加字符串也会通过person2.friends反映出来。
function Person() {
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.friends= ["Shelby","Court"];
Person.prototype.sayName = function () {
alert(this.name);
}
var person1 = new Person();
person1.sayName(); //"Nicholas"
var person2 = new Person();
person2.sayName(); //"Nicholas"
alert(person1.friends == person2.friends);
6.组合使用构造函数和原型模式(推荐)
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