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

工厂模式

 1 function CreatePerson(name,age,job){
 2         var o=new Object();
 3         o.name=name;
 4         o.age=age;
 5         o.job=job;
 6         o.sayName=function(){
 7             alert(this.name);
 8         }
 9         return o;
10     }
11     var person1=CreatePerson("Jim",29,"Teaching in Colleage");
12     var person2=CreatePerson("Merry",23,"Study in Colleage");
13     console.log(person1.sayName==person2.sayName);

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

构造函数模式

 1 // 构造函数模式
 2     /*
 3         必须使用 new 操作符,会经过以下几个步骤
 4         1 创建一个新对象
 5         2 将构造函数的作用域赋值给新对象
 6         3 执行构造函数中的代码(为新对象添加属性)
 7         4 返回新对象
 8     */
 9     function PersonByConstructor(name,age,job){//按照惯例构造函数以大写字母开头
10         this.name=name;
11         this.age=age;
12         this.job=job;
13         this.sayName=function(){
14             alert(this.name);
15         };
16     }
17     var person3=new PersonByConstructor("John",24,"Software Engineer");
18     var person4=new PersonByConstructor("Greg",25,"Doctor");
19 
20     console.log(person3 instanceof PersonByConstructor);//返回true
21     console.log(person4 instanceof PersonByConstructor);

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

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

1 PersonByConstructor("Lily",32,"Driver");//添加到window
2     window.sayName();
3 
4     var o=new Object();
5     PersonByConstructor.call(o,"Kristen",23,"Nurse");
6     o.sayName();

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

原型模式

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

理解原型对象

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

function PersonByPrototype(){
 
    }
    PersonByPrototype.prototype={
        name:"Jim",
        age:21,
        job:"Teaching",
        sayName:function(){
            console.log(this.name);
        }
    }
    var person5=new PersonByPrototype();
    person5.sayName();
 
    var person6= new PersonByPrototype("Mick",32,"assitant");
    person6.sayName();
    console.log(PersonByPrototype.prototype.isPrototypeOf(person5));//通过 prototype.isPrototypeOf 来确定PersonByPrototype是否是person5的原型
    console.log(Object.getPrototypeOf(person5).name);//Object.getPrototypeOf可以方便的获取对象的原型,这在利用原型实现继承的情况下是非常重要的

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

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

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

function hasPrototypeProperty(name,obj){
        return !obj.hasOwnProperty("name") && ("name" in obj);
    }

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

for (var prop in person5)
        console.log(prop);    //返回  name,age ,job, sayName

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

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

原生对象的问题

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

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

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

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

function PersonByConstructorAndPrototype(name,age,job){
this.name=name;
this.age=age;
this.job=job;
this.friends=[];
}
PersonByConstructorAndPrototype.prototype={
constructor:PersonByConstructorAndPrototype,
sayName:function(){console.log(this.name);}
} var person7=new PersonByConstructorAndPrototype("LiLei",12,"Student");
var person8 = new PersonByConstructorAndPrototype("LiuLei",13,"Student")
person7.friends.push("LiuLei");
person8.friends.push("LiLei");
console.log(person7.friends.toString());
console.log(person8.friends);

动态原型模式

  有其他 OO 语言经验的开发人员在看到独立的构造函数和原型时,很可能会感到非常困惑。动态原型模式正是致力于解决这个问题的一个方案,它把所有信息都封装在了构造函数中,而通过在构造函数中初始化原型(仅在必要的情况下),又保持了同时使用构造函数和原型的优点。换句话说,可以通过检查某个应该存在的方法是否有效,来决定是否需要初始化原型。

寄生构造函数模式

  如果上面几种方式都不适用,可以适用寄生模式。该模式的核心思想是创建一个函数,该函数的作用仅仅是封装创建对象的代码。

//寄生构造函数模式
function PersonByParasitic(name,age,job){
var o=new Object();
o.name=name;
o.age=age;
o.job=job;
o.sayName=function(){
console.log(this.name);
};
return o;
} var friend=new PersonByParasitic("Nicholas",20,"Software Engineer");
friend.sayName();
var friend2=new PersonByParasitic("Nick",32,"");
friend2.sayName();

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

稳妥构造函数模式

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

  

读Javascript高级程序设计第三版第六章面向对象设计--创建对象的更多相关文章

  1. javascript高级程序设计第3版——第6章 面向对象的程序设计

    第六章——面向对象的程序设计 这一章主要讲述了:面向对象的语言由于没有类/接口情况下工作的几种模式以及面向对象语言的继承: 模式:工厂模式,构造函数模式,原型模式 继承:原型式继承,寄生式继承,以及寄 ...

  2. JavaScript高级程序设计第三版.CHM【带实例】

    从驱动全球商业.贸易及管理领域不计其数的复杂应用程序的角度来看,说 JavaScript 已经成为当今世界上最流行的编程语言一点儿都不为过. JavaScript 是一种非常松散的面向对象语言,也是 ...

  3. Javascript高级程序设计读书笔记(第六章)

    第6章  面向对象的程序设计 6.2 创建对象 创建某个类的实例,必须使用new操作符调用构造函数会经历以下四个步骤: 创建一个新对象: 将构造函数的作用域赋给新对象: 执行构造函数中的代码: 返回新 ...

  4. javascript高级程序设计第三版书摘

    在HTML 中使用JavaScript <script>元素 在使用<script>元素嵌入 JavaScript 代码时,只须为<script>指定 type 属 ...

  5. 22.1 高级函数【JavaScript高级程序设计第三版】

    函数是JavaScript 中最有趣的部分之一.它们本质上是十分简单和过程化的,但也可以是非常复杂和动态的.一些额外的功能可以通过使用闭包来实现.此外,由于所有的函数都是对象,所以使用函数指针非常简单 ...

  6. JavaScript高级程序设计第三版-读书笔记(1-3章)

    这是我第一次用markdown,也是我第一次在网上记录我自己的学习过程. 第一章 JavaScript主要由以下三个不同的部分构成 ECMAScript   提供核心语言功能 DOM     提供访问 ...

  7. 21.1 XMLHttpRequest 对象【JavaScript高级程序设计第三版】

    IE5 是第一款引入XHR 对象的浏览器.在IE5 中,XHR 对象是通过MSXML 库中的一个ActiveX对象实现的.因此,在IE 中可能会遇到三种不同版本的XHR 对象,即MSXML2.XMLH ...

  8. 《JavaScript高级程序设计第三版》——细碎知识痛点整理(第六章)

    面向对象的程序设计 对象是一组没有特定顺序的值6.1.1 属性类型ECMAScript中有两种属性:数据属性和访问器属性.1. 数据属性Configurable 表示能否通过delete删除属性从而重 ...

  9. 14.5 富文本编辑【JavaScript高级程序设计第三版】

    富文本编辑,又称为WYSIWYG(What You See Is What You Get,所见即所得).在网页中编辑富文本内容,是人们对Web 应用程序最大的期待之一.虽然也没有规范,但在IE 最早 ...

随机推荐

  1. LINUX 下Open cv练习使用小记(1)

    首先肯定离不开选一张自己喜欢的图像来显示 #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp ...

  2. Socket与Http方式解析发送xml消息封装中间件jar包

    最近项目代码中太多重复的编写Document,不同的接口需要不同的模板,于是重写提取公共部分打成jar包,方便各个系统统一使用~ 提取结构: Http连接方式: import java.nio.cha ...

  3. Linux命令(22)find的使用

    在linux下面工作,有些命令能够大大提高效率. 比如说find命令,他哥俩可以算是必会的linux命令,几乎每天都要用到他们. find命令 find命令的一般形式 find命令的常用选项及实例 f ...

  4. metasploit渗透初探MR.robot(一)

    看了MR.robot,有一种研究渗透技术的冲动, 网上也看了些教程,要从kali linux说起, 下载vmware 12,http://www.vmware.com/go/tryworkstatio ...

  5. UIScrollView 性能优化 - view转为Image

    进入做地图闹钟app,图层关系是这样的: subwayView 上先绘制线路上各个元素:线条 ,站点名称-Label,站点位置(画圆圈表示)-View.shapeLayer UIBezierPath ...

  6. 两种流行Spring定时器配置:Java的Timer类和OpenSymphony的Quartz

    1.Java Timer定时 首先继承java.util.TimerTask类实现run方法 import java.util.TimerTask; public class EmailReportT ...

  7. android studio新建hello world时出现Rendering Problems

    The following classes could not be instantiated:        - android.support.v7.internal.widget.ActionB ...

  8. MVC中的Html.Partial和Html.RenderPartial

    Partial辅助方法用于将部分视图渲染成字符串.注意没必要为视图指定路径和文件扩展名,因为运行时定位部分视图与定位正常视图使用的逻辑相同.例如,下面代码就渲染一个名为AlbumDisplay的部分视 ...

  9. (windows)mongoDB3X+Robomongo的安装与基础配置

    一开始安装的时候还觉得很简单真正装了时候发现网上的资料参差不齐再次整理一份安装方法 ---------------------------------------------------------- ...

  10. MVC之路由规则 (自定义,约束,debug)

    自定义路由规则的要求,小范围写在前,大范围写在后.路由规则可以注册多条,路由规则的名称不能重复路由规则有顺序,并且按照顺序进行匹配,建议小范围写在前,大范围写在后.路由规则可以设置约束 即正则表达式路 ...