能使用{}创建对象就不要使用new Object,能使用[]创建数组就不要使用new Array,JS中字面量的访问速度要高于对象。
1、通过object构造函数创建单个对象
var o = new Object(); o.name = 'camille'; o.age = 24; o.getName = function() { return '我的名字是:'+ this.name; }; o.getAge = function() { return '我的年龄是:' + this.age; };
2、通过对象字面量创建单个对象,JSON(常用)
var personObj = { name: 'camille', age: 25, getName: function(){ return '我的名字是:'+ this.name; }, getAge: function(){ return '我的年龄是:' + this.age; } } personObj.getAge();
使用同一个接口创建很多对象,会产生大量的重复代码。
3、稳妥构造函数模式
所谓稳妥对象,指的是没有公共属性,而且其方法也不引用this的对象。
function Person(name, age) { var o = new Object(); o.getName = function() { return '我的名字是:'+ name; }; o.getAge = function() { return '我的年龄是:' + age; }; return o; } var nobj = Person('camille',25); console.log(nobj.getAge());
与寄生构造函数模式类似,使用稳妥构造函数模式创建的对象与构造函数之间没有什么关系,因此instanceof操作符对这种对象也没有意义。
4、工厂模式:带参数的函数,返回对象,流水线工作。在函数内定义对象,并定义对象的各种属性,虽然属性可以是方法,但是建议在函数外定义属性为方法的属性,这样可以避免重复创建该方法。解决了创建多个相似对象的问题,但却没有解决对象识别的问题。
function Person(name, age) { var o= new Object(); o.name = name; o.age = age; o.getName = function() { return '我的名字是:'+ this.name; }; o.getAge = function() { return '我的年龄是:' + this.age; }; return o; } var nobj = Person('camille',25); console.log(nobj.getAge());
5、寄生构造函数模式
创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后在返回创建对象。
function Person(name, age) { var o = new Object(); o.name = name; o.age = age; o.getName = function() { return '我的名字是:'+ this.name; }; o.getAge = function() { return '我的年龄是:' + this.age; }; return o; } var nobj = new Person('camille',25); console.log(nobj.getAge());
返回的对象与构造函数或者与构造函数的原型之间没有关系,也就是说,构造函数返回的对象与在构造函数外部创建的对象没什么不同。为此,不能依赖instanceof操作符来确定对象的类型。由于存在这一问题,我们建议在可以使用其他模式的情况下不要使用这种模式。
6、构造函数模式:没有显式的创建对象,直接将属性和方法赋给了this对象,没有return语句;创建自定义的构造函数意味着将来可以将它的实例标识为一种特定的类型。每个方法都要在每个实例上重新创建一遍。
function Person(name, age) { this.name = name; this.age = age; this.getName = function() { return '我的名字是:'+ this.name; }; this.getAge = function() { return '我的年龄是:' + this.age; }; } var nobj = new Person('camille',25); console.log(nobj.getAge());
注意!如果不加new关键字,Person就不是构造函数,会意外地给它的外部作用域即window添加属性,为了安全,这里的new是必须的。
7、原型模式:属性没有在函数内定义,而是利用prototype属性对属性进行定义。所有的属性,方法都是共享的,不能让对象具体化。实例中的指针仅指向原型,而不指向构造函数。
//写法1 function Person() { } Person.prototype.name = 'camille'; Person.prototype.age = 26; Person.prototype.getName = function() { return '我的名字是:'+ this.name; }; Person.prototype.getAge = function() { return '我的年龄是:' + this.age; }; var nobj = new Person(); console.log(nobj.getAge());
//写法2 function Person() { } Person.prototype = { constructor: Person,//必须手动设置这个属性,不然就断了与构造函数的联系了。没有实例共享原型的意义了。 name: 'camille', age: 26, getName: function() { return '我的名字是:'+ this.name; }, getAge: function() { return '我的年龄是:' + this.age; } }; var nobj = new Person(); console.log(nobj.getAge());
8、构造-原型组合模式(推荐)
构造函数模式用于定义实例属性,而原型模式用于定义方法和共享属性。
//写法1 function Person(name, age) { this.name = name; this.age = age; } Person.prototype.getName = function() { return '我的名字是:'+ this.name; }; Person.prototype.getAge = function() { return '我的年龄是:' + this.age; }; var nobj = new Person('camille',25); console.log(nobj.getAge());
//写法2 function Person(name, age) { this.name = name; this.age = age; } /** * 为了让属性和方法更好的体现封装的效果,减少不必要的输入,原型的创建可以使用字面量方式 */ Person.prototype = { constructor: Person,//必须手动设置这个属性,不然就断了与构造函数的联系了。没有实例共享原型的意义了。 getName: function() { return '我的名字是:'+ this.name; }, getAge: function() { return '我的年龄是:' + this.age; } }; var nobj = new Person('camille',25); console.log(nobj.getAge());
//写法3 function Person(name, age) { this.name = name; this.age = age; } (function() { this.getName = function() { return '我的名字是:'+ this.name; }; this.getAge = function() { return '我的年龄是:' + this.age; }; }).call(Person.prototype); var nobj = new Person('camille',25); console.log(nobj.getAge());
9、动态原型模式:可以理解为构造-原型组合模式的一个特例,在函数内定义属性为方法的属性,if语句保证创建该对象的实例时,属性的方法不会被重复创建。(推荐)
function Person(name, age) { this.name = name; this.age = age; if (typeof this.getName != "function") { //使用动态原型模式时,不能使用对象字面量重写原型。如果在已经创建了实例的情况下重写原型,就会切断现有实例与新原型之间的联系 Person.prototype.getName = function () { alert(this.name); } } }
通过检查某个应该存在的方法是否有效,来决定是否需要初始化原型。