您的位置:首页 > Web前端 > JavaScript

读Javascript高级程序设计第三版第六章面向对象设计--创建对象

2016-01-06 12:37 661 查看
虽然Object构造函数或者对象字面量都可以用来创建单个对象,但是缺点非常明显:使用同一接口创建很多对象,会产生大量重复代码。

工厂模式

1functionCreatePerson(name,age,job){

2varo=newObject();

3o.name=name;

4o.age=age;

5o.job=job;

6o.sayName=function(){

7alert(this.name);

8}

9returno;

10}

11varperson1=CreatePerson("Jim",29,"TeachinginColleage");

12varperson2=CreatePerson("Merry",23,"StudyinColleage");

13console.log(person1.sayName==person2.sayName);

ViewCode

解决了创建多个对象的问题,但是却没有解决对象识别的问题。

构造函数模式

1//构造函数模式

2/*

3必须使用new操作符,会经过以下几个步骤

41创建一个新对象

52将构造函数的作用域赋值给新对象

63执行构造函数中的代码(为新对象添加属性)

74返回新对象

8*/

9functionPersonByConstructor(name,age,job){//按照惯例构造函数以大写字母开头

10this.name=name;

11this.age=age;

12this.job=job;

13this.sayName=function(){

14alert(this.name);

15};

16}

17varperson3=newPersonByConstructor("John",24,"SoftwareEngineer");

18varperson4=newPersonByConstructor("Greg",25,"Doctor");

19

20console.log(person3instanceofPersonByConstructor);//返回true

21console.log(person4instanceofPersonByConstructor);

ViewCode

创建自定义的构造函数意味着将来可以将它的实例标识为一种特定的类型。

任何函数,只要通过new操作符来调用,那它就可以作为构造函数;否则和普通函数一样。

1PersonByConstructor("Lily",32,"Driver");//添加到window

2window.sayName();

3

4varo=newObject();

5PersonByConstructor.call(o,"Kristen",23,"Nurse");

6o.sayName();

ViewCode

构造函数模式虽然好用,但是每个方法都要在每个实例上重新创建一遍。
可以将方法移到构造函数的外部解决,但是如对象要调用很多方法,则需要定义很多全局函数,这样就没有封装性可言了。这个问题可以通过原型模式来解决。

原型模式

我们创建的每一个函数都有原型属性(prototype),这个属性是一个指向对象的指针,这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。prototype就是通过调用构造函数而创建的那个对象实例的原型对象。使用对象原型的好处是让所有对象实例共享它所包含的属性和方法。

理解原型对象

  无论什么时候,只要创建一个对象,都会根据一定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。在默认情况下所有原型都会自动获取一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针。

functionPersonByPrototype(){


}

PersonByPrototype.prototype={

name:"Jim",

age:21,

job:"Teaching",

sayName:function(){

console.log(this.name);

}

}

varperson5=newPersonByPrototype();

person5.sayName();


varperson6=newPersonByPrototype("Mick",32,"assitant");

person6.sayName();

console.log(PersonByPrototype.prototype.isPrototypeOf(person5));//通过prototype.isPrototypeOf来确定PersonByPrototype是否是person5的原型

console.log(Object.getPrototypeOf(person5).name);//Object.getPrototypeOf可以方便的获取对象的原型,这在利用原型实现继承的情况下是非常重要的

ViewCode

每当代码读取某个对象的属性时,都会指向一次搜索,目标是具有给定名字的属性。搜索首先从对象实例本身开始,如果找到则返回该属性的值,如果没找到,则搜索指针指向原型对象,在原型对象查找具有给定名字的属性。我们对原型的修改会立刻的体现出来。
当为对象实例添加新的属性时,这个属性就会屏蔽原型对象中的那个同名属性,换句话说,会阻止我们访问原型中的属性,但不会修改那个属性。不过使用delete可以删除实例中的属性,从而使我们能够访问原型中的属性。

console.log(person6.hasOwnProperty("name"));//hasOwnProperty来判断属性是实例的还是原型继承来的

console.log(person5.hasOwnProperty("name"));

ViewCode

原型与IN操作符
  在单独使用时,in操作符会在通过对象能够访问给定属性时返回true,无论该属性存在于实例中还是原型中。只要in操作符返回true,而hasOwnProperty返回false,就可以确定属性是原型中的属性。

functionhasPrototypeProperty(name,obj){

return!obj.hasOwnProperty("name")&&("name"inobj);

}

ViewCode

  在使用for-in循环时,返回的是通过对象访问的、可枚举的属性,其中包括实例和原型对象中的属性。

for(varpropinperson5)

console.log(prop);//返回name,age,job,sayName

ViewCode

原型的动态性
  实例中的指针仅指向原型,而不是构造函数。

  如果把原型改为另外一个对象,相当于切断了构造函数和最初原先对象之间的联系。

原生对象的问题

  1省略了为构造函数传参这一环节

  2原型中所有属性都是被所有实例共享的。

组合使用原型模式和构造函数模式

  构造函数模式用于定义实例属性,原型模式来定义方法和共享的属性。

//寄生构造函数模式
functionPersonByParasitic(name,age,job){
varo=newObject();
o.name=name;
o.age=age;
o.job=job;
o.sayName=function(){
console.log(this.name);
};
returno;
}

varfriend=newPersonByParasitic("Nicholas",20,"SoftwareEngineer");
friend.sayName();
varfriend2=newPersonByParasitic("Nick",32,"");
friend2.sayName();


ViewCode
这个模式可以在特殊情况下为对象创建构造函数。

稳妥构造函数模式

  稳妥对象指的是没有公共属性,而其方法也不引用this对象。

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: