标签:
学习资料:《JavaScript》高级程序设计
创建对象可以是通过创建object实例然后为其添加属性的方法,也可以通过对象字面量方式创建对象。但是如果想要创建大量的对象,这两种方法可能会导致很多重复代码。为解决这个问题,可以采用工厂模式的一种变体:
1.工厂模式
用函数来封装以特定接口创建对象的细节,如下列:
function createPerson(name, age, job){ var o=new Object(); o.name=name; o.age=age; o.job=job; o.sayName=function(){ alter(this.name); } return o; } var person1=createPerson("Shirley",22,"software engineer");
工厂模式解决了创建多个相似对象的问题,但却没有解决对象识别的问题(即怎样知道一个对象的类型)。
2.构造函数模式
创建自定义的构造函数,从而定义自定义对象的属性和方法。可以使用构造函数将上面的例子重写如下:
function Person(name, age, job){ this.name=name; this.age=age; this.job=job; this.sayName=function(){ alter(this.name); } } var person1=new Person("Shirley",22,"software engineer");
与工厂模式相比:
(1).没有显式的创建对象;
(2).直接将属性和方法赋值给了this对象
(3).没有return语句
同时,注意构造函数的函数名第一个字母大写,创建Person的实例的时候,要采用new操作符。以new调用构造函数实际上会经历四个步骤:
(1).创建一个新的对象
(2).将构造函数的作用域赋予这个新对象(因此,this就指向了新对象)
(3).调用构造函数中的代码给新对象赋属性和方法
(4). 返回新对象
因此,person1是Person的一个实例,而且person1.constructor=Person。
对象的constructor属性最初是用来识别对象类型的,但是检测对象类型,采用instanceof操作符更加可靠:
alert(person1 instanceof Person); //true alert(person1 instanceof Object); //true
因此创建自定义构造函数可以将来将它的实例标识为一种特定的类型。注意,所有对象均继承自Object。
2.1构造函数的问题
构造函数的主要问题是每个方法都要在每个实例上重新创建一遍。因为函数也是对象,每定义一个函数,就是实例化了一个对象,因此,从逻辑上将,构造函数也可以定义如下:
function Person(name, age, job){ this.name=name; this.age=age; this.job=job; this.sayName=new Function("alter(this.name)"); } var person1=new Person("Shirley",22,"software engineer");
为了解决这个问题,可以采用原型模式
3.原型模式
我们创建的每一个函授都有一个prototype属性,这个属性是个指针,指向一个对象。这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。使用原型对象的好处可以让所有对象实例共享它的属性和方法。前面的例子采用原型模型可以写成:
function Person(){ } Person.prototype.name=Shirley; Person.prototype.age=18; Person.prototype.job=“Software Engineer”; Person.prototype.sayName=function(){ alter(this.name); } var person1=new Person();
上面的创建方法,每添加一个属性和方法就要敲入Person.prototype.XX一遍,为了减小不必要的输入,也为了从视觉上更好的封装原型的功能,更常见的做法是采用一个包含所有属性和方法的对象字面量来重写整个原型对象。
function Person(){ } Person.prototype={ name:“Shirley”, age:18, job:“Software Engineer”, sayName:function(){ alter(this.name); } }; var person1=new Person();
在上面的代码中,Person.prototype设置为一个以对象字面量形式创建的新对象。最终结果与上面的创建方法一致,但是有一个的例外:constructor属性不再指向Person了。每创建一个函数,同时会创建它的prototype对象,这个对象也会自动获得constructor属性。而上述的语法,本质上重写了默认的prototype对象,因此constructor属性也就会变成新对象的constructor属相(指向Object构造函数)。但是,person1 instanceOf Person依然会返回TRUE
如果constructor非常重要的话,可以通过下面的方法对其进行设置。不过这样的话,constructor的属性的[[Enumerable]]特性会被设置为true,默认情况下, 原生的constructor是不可枚举的,可以用Object.defineProperty()方法对其进行设置。
function Person(){ } Person.prototype={ constructor:Person, name:“Shirley”, age:18, job:“Software Engineer”, sayName:function(){ alter(this.name); } }; var person1=new Person();
注意,可以通过对象实例来访问原型中的值,但是却不能通过对象实例重写原型中的值。如果在实例中添加了一个属性,而这个属性与原型中的一个属性同名,那么我们就在实例中创建了该属性,该属性会屏蔽原型中的那个属性。但是如果是包含引用类型的属性,在某个实例对其进行操作的时候,由于数组存在原型中,而不是实例中,有可能会更改原型中的数据。见下面的例子
function Person(){ } Person.prototype={ constructor:Person, name:“Shirley”, age:18, job:“Software Engineer”, friends:[‘a‘,‘b‘], sayName:function(){ alter(this.name); } }; var person1=new Person(); var person2=new Person(); person1.friends.push(‘c‘); alert(person2.friends); //"a,b,c"
因此很少有人单独使用原型模式。
4.组合使用构造函数模式和原型模式
创建自定义类型的最常见的方法,是组合使用构造函数模式与原型模式。构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。这种混合模式还支持向构造函数传递参数。
function Person(name,age,job){ this.name=name; this.age=age; this.job=job; this.friends=[‘a‘,‘b‘]; } Person.prototype={ constructor:Person, sayName:function(){ alter(this.name); } }; var person1=new Person("Lily",23,"Doctor"); var person2=new Person("Emma",24,"Student"); person1.friends.push(‘c‘); alert(person2.friends); //"a,b"
5.动态原型模式
动态原型模式是将所有信息都封装到构造函数中,而通过在构造函数中初始化原型(仅在必要的情况下),同时保持了同时使用构造函数和原型的优点。
function Person(name,age,job){ this.name=name; this.age=age; this.job=job; this.friends=[‘a‘,‘b‘]; if(typeOf this.sayName != "function"){ Person.prototype.sayName=function(){ alter(this.name); }; } } var person1=new Person("Lily",23,"Doctor");
用if语句检查的可以是初始化后应该存在的任何一个属性或者方法,不必检查每一个。对于用这种模式创建的对象,也可以用instanceOf操作符判断它的类型。但是应该注意的是,不能用对象字面量的方式重写原型。
6.寄生构造函数模式
基本思想是创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后返回新创建的对象。
function Person(name, age, job){ var o=new Object(); o.name=name; o.age=age; o.job=job; o.sayName=function(){ alter(this.name); } return o; } var person1= new Person("Shirley",22,"software engineer");
除了使用new操作符并把包装函数叫做构造函数之外,这个模式和工厂模式其实是一模一样的。注意,返回的对象和构造函数或者构造函数的原型没有关系,不能通过instanceof操作符来确定对象类型。
7.稳妥构造函数模式
稳妥对象,是指没有公共属性,而且其方法也不引用this的对象,稳妥对象最适合在一些安全的环境中(这些环境会禁止this 和 new)或者防止数据被其它应用程序改动时使用。稳妥构造函数与寄生构造函数模式类似,但是有以下两点不同,一是新创建对象的实例方法不引用this,二是不适用new操作符调用构造函数。(还不是很理解)
标签:
原文地址:http://www.cnblogs.com/shirleyyang-fe/p/5792361.html