1.对象字面量的方式
缺点:使用同一个接口创建很多对象会产生大量重复代码,创建有相同属性的对象时,会产生重复代码
var person = {
name:"nicl",
age:14,
sayName:function () {
alert(this.name);
}
};
2.工厂模式:
优点:解决了创建多个相似对象的问题,
缺点:没有解决对象识别的问题
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;
}
createPerson("zhangsan",14,"farmer");
createPerson("li",24,"toilet");
3.构造函数模式(大驼峰式命名规则)
function Person(name,age,job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function () {
alert(this.name);
}
}
var person1 = new Person("ni",21,"coder");
var person2 = new Person("li",15,"student");
与工厂模式不同的是:
1.没有显示的创建对象;2.直接将属性和方法赋给了this对象;3.没有return语句
要创建一个Person实例必须使用new操作符,以这种方式调用构造函数会经历4个步骤:
- 1:创建一个新的对象;
- 2:将构造函数的作用域赋给新对象(this就指向了这个新的对象)
- 3:执行构造函数中的代码(为新对象添加属性)
- 4:返回新对象
缺点:每个方法都要在每个实例上重新创建一遍,在上面那个例子当中person1和person2都有一个sayName方法,但是这两个方法不是同一个Function的实例。这样可能比较好理解:
function Person1(name,age,job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = new Function('alert(this.name)'); //不是同一个Function的实例,与之前的例子是等价的
}
var person3 = new Person1("nj",43,"teacher");
var person4 = new Person1("fdf",54,"child");
alert(person3.sayName === person4.sayName); //false
4:原型模式
在js中,每个函数都有一个prototype属性,它是一个指针,指向一个对象,叫做原型对象,原型对象包含了可以由特定类型的所有实例对象共享的属性和方法。 此外,这个对象有一个与生自来的属性constructor,指向创建对象的构造方法。使用原型模式可以让所有的实例共享原型对象中的属性和方法,
也就是说,不必再构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中。
function Person2() {}
Person2.prototype.name = "nico";
Person2.prototype.age = 32;
Person2.prototype.job = "coder";
Person2.prototype.friends = ["she","he"];
Person2.prototype.sayName = function () {
alert(this.name);
};
var person5 = new Person2();
person5.sayName();
var person6 = new Person2();
person6.sayName();
alert(person5.sayName === person6.sayName); //true
//可以通过对象实例来访问原型上的属性和方法,但是不能通过对象实例重写原型的值,如果我们在实例中添加了一个属性,该属性与原型上的属性同名
//那么该属性会屏蔽掉原型中的那个属性,代码如下:
person6.name = "mini";
alert(person6.name); //mini
缺点:
首先,它省略了为构造函数传递初始化参数这一环节,结果所有实例在默认情况下都将取得相同的属性值。虽然这会在某种程度上带来一些不方便, 但还不是原型的最大问题。原型模式的最大问题是由共享的本性所导致的。原型中所有属性是被很多实例共享的,这种共享对于函数非常合适。对于那些包含基本值的属性倒也说的过去,通过在实例上添加一个同名属性,可以隐藏原型中的对应属性。然后,对于包含引用类型的属性来说,问题就比较突出了。
person5.friends.push('it');
alert(person5.friends); //she,he,it
alert(person6.friends); //she,he,it
alert(person6.friends === person5.friends); //true
向person5的friends字符串数组里面添加一项,由于friends是存在于原型中的,当更改person5时,person6的属性值也会跟着变化
5.构造函数与原型模式组合使用
组合使用构造函数模式和原型模式,是创建自定义类型的最常见方式。构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。结果,每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用,最大限度的节省了内存。
function Person3(name,age,job) {
this.name = name;
this.age = age;
this.job = job;
this.friends = ["lili","liming","joh"]
}
Person3.prototype.sayName = function () {
alert(this.name);
};
var person7 = new Person3('zhang',23,'teacher');
var person8 = new Person3('li',2,'child');
person7.friends.push('fei');
alert(person7.friends); //lili,liming,joh,li
alert(person8.friends); //lili,liming,joh
alert(person7.friends === person8.friends); //false
参考书籍《JavaScript高级程序设计》