ECMAScript支持面向对象(OO)编程,但不使用类或者接口。对象可以在代码执行过程中创建或增强,因此具有动态性而非严格定义的实体。在没有类的情况下,可以采用下列模式创建对象。

对象的创建

工厂模式

工厂模式是软件工程里面一种广为人知的设计模式,这种模式抽象了创建具体对象的过程。考虑到ECMAScript中无法创建类,开发人员就发明了一种函数,用函数来封装以特定接口创建对象的细节,如下代码所示:

  1. function createPerson(name,age,job)
  2.  
  3. {
  4.  
  5. 	var o=new Object();
  6.  
  7. 	o.name=name;
  8.  
  9. 	o.age=age;
  10.  
  11. 	o.job=job;
  12.  
  13. 	o.sayName=function(){
  14.  
  15. 		alert(this.name);
  16.  
  17. 	};
  18.  
  19. 	return o;
  20.  
  21. }
  22.  
  23. var person1=createPerson("Tom",28,"软件工程师");
  24.  
  25. var person2=createPerson("XXX",23,"系统架构师");

函数createPerson()能够根据接受的参数来创建一个包含所有必要信息的Person对象。可以无数吃的调用该方法,而每次都会返回一个包含3个属性一个方法的对象。工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题(即怎样知道一个对象的类型),随着Javascript的发展,又一个新模式出现了。

构造函数模式

众所周知,ECMAScript的构造函数可以用来创建特定类型的对象。像Object和Array这样的原生构造函数,在运行时就会自动出现在执行环境中。此外,也可以创建自定义的构造函数,从而自定义对象类型的属性和方法。将上面的例子用构造函数的方式重写如下所示:

  1. function Person(name,age,job)
  2.  
  3. {
  4.  
  5. 	this.name=name;
  6.  
  7. 	this.age=age;
  8.  
  9. 	this.job=job;
  10.  
  11. 	this.sayName=function(){
  12.  
  13. 		alert(this.name);
  14.  
  15. 	};
  16.  
  17. }
  18.  
  19. var person1=new Person("Tom",28,"软件工程师");
  20.  
  21. var person2=new Person("XXX",23,"系统架构师");

在这个例子中,Person()函数取代了createPerson()函数。我们注意到,Person()中的代码除了与createPerson()相同部分外,还存在以下不同之处:

  1. 没有显示的创建对象;

  2. 直接将属性和方法赋予this对象;
  3. 没有return语句。

此外,还应注意到Person()首字母大写了(这是Javascript构造函数约定俗成的写法,以区别于普通的函数)。使用构造函数时,务必要加上new操作符,否则构造函数与普通函数并没什么区别(换句话说,任何普通函数前面加上new操作符都可以是构造函数)。

创建自定义的构造函数意味着将来可以将它的实际类型标识为一种特定的类型,这恰恰解决了工厂模式的问题。但是构造函数仍然存在以下问题:

  1. 主要问题就是每个方法都要在每个示例上重新创建一遍。在上面的例子中person1和person2都有一个名为sayName的方法,但是两个方法不是同一个Function的实例;

  2. 固然我们可以将方法放在构造函数的外面,但是这样一来就使得全局作用域定义的函数实际上只能被某个对象调用,这让全局作用域有点名不副实;如果对象需要定义很多方法,那么就要定义很多全局函数,这也就失去了封装的应用类型的意义了。

原型模式

我们创建的每一个函数都有一个prototype(原型)属性(构造函数的一个属性),该属性指向一个对象. 而这个对象将作为该构造函数所创建的所有实例的基引用(base reference), 可以把对象的基引用想像成一个自动创建的隐藏属性. 当访问对象的一个属性时, 首先查找对象本身, 找到则返回; 若不, 则查找基引用指向的对象的属性(如果还找不到实际上还会沿着原型链向上查找,  直至到根). 只要没有被覆盖的话, 对象原型的属性就能在所有的实例中找到.使用原型对象的好处就是可以让所有特定类型实例共享其中定义的属性和方法。示例代码如下所示:

  1. // prototype默认为new Object(); 为了方便, 记为p_obj
  2.  
  3. function Person(name) {
  4.  
  5.     this.name = name;
  6.  
  7. }
  8.  
  9. // 为 p_obj 增加 sayName 属性
  10.  
  11. Person.prototype.sayName = function(){
  12.  
  13.     alert(this.name);
  14.  
  15. }
  16.  
  17. var john = new Person("John"); // john 的 base reference指向p_obj
  18.  
  19. var eric = new Person("Eric");  // eric 的 base reference也是指向p_obj
  20.  
  21. // 注意sayName代码中的this将指向实例化后的对象(this绑定)
  22.  
  23. john.sayName(); // john对象本身没有sayName属性, 于是访问原型对象p_obj的sayName属性
  24.  
  25. eric.sayName(); // 访问同一个原型对象p_obj的sayName属性
  26.  
  27. var tmp = Person.prototype;
  28.  
  29. tmp.boss = "David";
  30.  
  31. // 于这个运行点, p_obj已经被修改
  32.  
  33. // 根据上述属性访问流程, 新的修改(boss属性)能反映到所有的实例, 包括已经创建和即将创建的
  34.  
  35. alert("John's boss is " + john.boss);
  36.  
  37. alert("Eric's boss is " + eric.boss);
  38.  
  39. // hisCar和sayCar属性将增加到john对象而不是p_obj对象..
  40.  
  41. john.hisCar = "Audi";
  42.  
  43. john.sayCar = function(){
  44.  
  45.     alert(this.name + " has a car of " + this.hisCar);
  46.  
  47. }
  48.  
  49. john.sayCar();
  50.  
  51. // ..因此下一句将错误, 因为eric对象本身和原型p_obj都没有sayName属性
  52.  
  53. /* eric.sayCar(); */

除了上述方式直接定义Prototype外,还可以使用字面量创建原型,但是要注意使用字面量定义的原型属性和方法不能再以字面量的方式重写,一旦重写了原型,原来的原型中定义的所有属性和方法都将被清除(当然用普通的方式是没有问题的),如下所示:

  1. //使用字面量方式创建原型
  2.  
  3. function User(name,age){//构造方法
  4.  
  5.     this.name = name;//属性
  6.  
  7.     this.age = age;
  8.  
  9. }
  10.  
  11. User.prototype = {
  12.  
  13.     addr : '湖北武汉',
  14.  
  15.     show : function(){
  16.  
  17.         alert(this.name+'|'+this.age+'|'+this.addr);
  18.  
  19.     }
  20.  
  21. };
  22.  
  23. //重写了原型
  24.  
  25. User.prototype = {
  26.  
  27.     other : '暂时没有说明……',
  28.  
  29.     show : function(){
  30.  
  31.         alert(this.addr);
  32.  
  33.     }
  34.  
  35. };
  36.  
  37. var user1 = new User('ZXC',22);//创建实例
  38.  
  39. var user2 = new User('CXZ',21);
  40.  
  41. user1.show();//返回 undefined
  42.  
  43. user2.show(); 

《JavaScript高级程序设计》读书笔记--(4)对象的创建的更多相关文章

  1. javascript高级程序设计读书笔记-事件(一)

    读书笔记,写的很乱   事件处理程序   事件处理程序分为三种: 1.html事件2. DOM0级,3,DOM2级别  没有DOM1 同样的事件 DOM0会顶掉html事件   因为他们都是属性  而 ...

  2. JavaScript高级程序设计-读书笔记(2)

    第6章 面向对象的程序设计 创建对象 1.最简单方式创建Object的实例,如 var person = new Object(); person.name = “Greg”; person.age ...

  3. javascript高级程序设计读书笔记----面向对象的程序设计

        创建对象   工厂模式 function createPerson(name, age, job){ var o = new Object(); o.name = name; o.age = ...

  4. javascript高级程序设计 读书笔记1

    第二章  在HTML中使用JS 加载JS有三种:行内,head头部和外部链接JS   最好使用外部链接<script src="example.js" ></sc ...

  5. Javascript高级程序设计--读书笔记之理解原型对象

    先上一段代码和关系图 function Person(){} Person.prototype.name = "Nic" Person.prototype.age = 22 Per ...

  6. javascript高级程序设计读书笔记

    第2章  在html中使用javascript 一般都会把js引用文件放在</body>前面,而不是放在<head>里, 目的是最后读取js文件以提高网页载入速度. 引用js文 ...

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

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

  8. JavaScript高级程序设计-读书笔记(7)

    第22章 高级技巧 1.高级函数 (1)安全的类型检测 在任何值上调用Object原生的toString()方法,都会返回一个[object NativeConstructorName]格式的字符串. ...

  9. JavaScript高级程序设计-读书笔记(6)

    第20章 JSON JSON是一个轻量级的数据格式,可以简化表示复杂数据结构的工作量 JSON的语法可以表示一下三种类型的值 l        简单值:使用与JavaScript相同的语法,可以在JS ...

  10. JavaScript高级程序设计-读书笔记(5)

    第13章 事件 1.事件流 事件流描述的是从页面中接收事件的顺序.IE的事件流是事件冒泡流,而Netscape Communicator的事件流是事件捕获流. (1)事件冒泡,即事件开始时由最具体的元 ...

随机推荐

  1. EF CodeFirst 关系配置

    自从开始学习asp.net mvc采用code first以来,关系配置就没有搞清楚过!(⊙﹏⊙)b 笔记之前先感谢以下文章和博主,对他们表示崇拜,由浅入深.举例恰当.拨云见日.茅塞顿开,还有什么词, ...

  2. java内存泄漏的经典案例

    这篇文章主要介绍了Java中典型的内存泄露问题和解决方法,典型的内存泄露例子是一个没有实现hasCode和 equals方法的Key类在HashMap中保存的情况,可以通过实现Key类的equals和 ...

  3. 如何让老Mac机支持USB安装Windows

    一些老Mac机的用户想装Windows,却发现自己的系统上的Boot Camp Assistant(以下简称BCA)没有USB安装Windows的选项. 下面以我的MacBook Pro (13-in ...

  4. 需求:输入一个年份和月份 ,显示当前月日情况 ,星期数要对应准确 * 1.1900年1月1号开始 * 2.星期 : 直接用总天数对7求余数 31 28 59 / 7 = 5 * 3.以\t来个开

    public class Demo4 { /** * @param args */ public static void main(String[] args) { // TODO Auto-gene ...

  5. [git] git代理及常用命令,远程桌面代理

     1.代理 公司只能内网,上外网只能用代理,坑货! 2. 更新代码命令    1)下载代码:git clone ------------    2) 指定目录: cd 文件名    3)git add ...

  6. 获取Echarts的DataZoom的起始值

    创建DataZoom拖动事件 myChart.on(ecConfig.EVENT.DATA_ZOOM, eConsole);   //事件名, 相关联的方法名 var ecConfig = requi ...

  7. jQuery get() 函数

    get() 函数 用于获取当前jQueryobject对象所匹配的DOM元素 语法 jQueryobject.get(index)//因为在JQuery中.很多时候和[]等价所以jQueryobjec ...

  8. 文件上传(excel服务端解析)

    1,html结构 <!-- 引入jQuery和jQuery.form.js插件 --><script type="text/javascript" src=&qu ...

  9. js中call、apply、bind的用法

    原文链接:http://www.cnblogs.com/xljzlw/p/3775162.html var zlw = { name: "zlw", sayHello: funct ...

  10. 初学js/jquery 心得

    1.多个对象操作的时候可以放在一起,eg: $('.send_message, .friends_increment').blur(function() {}); 2.三元表达式与if else,eg ...