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

对象的创建

工厂模式

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

function createPerson(name,age,job)
{
	var o=new Object();
	o.name=name;
	o.age=age;
	o.job=job;
	o.sayName=function(){
		alert(this.name);
	};
	return o;
}
var person1=createPerson("Tom",28,"软件工程师");
var person2=createPerson("XXX",23,"系统架构师");

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

构造函数模式

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

function Person(name,age,job)
{
	this.name=name;
	this.age=age;
	this.job=job;
	this.sayName=function(){
		alert(this.name);
	};
}
var person1=new Person("Tom",28,"软件工程师");
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), 可以把对象的基引用想像成一个自动创建的隐藏属性. 当访问对象的一个属性时, 首先查找对象本身, 找到则返回; 若不, 则查找基引用指向的对象的属性(如果还找不到实际上还会沿着原型链向上查找,  直至到根). 只要没有被覆盖的话, 对象原型的属性就能在所有的实例中找到.使用原型对象的好处就是可以让所有特定类型实例共享其中定义的属性和方法。示例代码如下所示:

// prototype默认为new Object(); 为了方便, 记为p_obj
function Person(name) {
    this.name = name;
}

// 为 p_obj 增加 sayName 属性
Person.prototype.sayName = function(){
    alert(this.name);
}

var john = new Person("John"); // john 的 base reference指向p_obj
var eric = new Person("Eric");  // eric 的 base reference也是指向p_obj

// 注意sayName代码中的this将指向实例化后的对象(this绑定)
john.sayName(); // john对象本身没有sayName属性, 于是访问原型对象p_obj的sayName属性
eric.sayName(); // 访问同一个原型对象p_obj的sayName属性


var tmp = Person.prototype;
tmp.boss = "David";
// 于这个运行点, p_obj已经被修改
// 根据上述属性访问流程, 新的修改(boss属性)能反映到所有的实例, 包括已经创建和即将创建的
alert("John's boss is " + john.boss);
alert("Eric's boss is " + eric.boss);


// hisCar和sayCar属性将增加到john对象而不是p_obj对象..
john.hisCar = "Audi";
john.sayCar = function(){
    alert(this.name + " has a car of " + this.hisCar);
}
john.sayCar();
// ..因此下一句将错误, 因为eric对象本身和原型p_obj都没有sayName属性
/* eric.sayCar(); */

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

//使用字面量方式创建原型
function User(name,age){//构造方法
    this.name = name;//属性
    this.age = age;
}
User.prototype = {
    addr : '湖北武汉',
    show : function(){
        alert(this.name+'|'+this.age+'|'+this.addr);
    }
};
//重写了原型
User.prototype = {
    other : '暂时没有说明……',
    show : function(){
        alert(this.addr);
    }
};
var user1 = new User('ZXC',22);//创建实例
var user2 = new User('CXZ',21);
user1.show();//返回 undefined
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. Linux查看程序端口占用情况

    今天发现服务器上Tomcat 8080端口起不来,老提示端口已经被占用. 使用命令: ps -aux | grep tomcat 发现并没有8080端口的Tomcat进程. 使用命令:netstat ...

  2. exel按行查找或按列查找

    表1:sheet1 1). 在表1中找出ID号位0928的基因相对应的数值 在相对应的单元格输入:B2=VLOOKUP(A:A,Sheet1!A:D,3,0) 既可以得到: ············· ...

  3. html+js 的一些小问题

    html+js 的一些小问题: 选择器+遍历函数: $("#taskStatusList tr:gt(0)").find("td:eq(3)").find(&q ...

  4. Jquery Json 下拉联动

    #region dataTable转换成Json格式 /// <summary> /// dataTable转换成Json格式 /// </summary> /// <p ...

  5. 解决IIS上无法添加.NET用户的问题

    最近开发了一个简单的管理后台,后台用户管理都用的是AspNetSqlMembershipProvider这一套框架,添加和删除用户的功能在开发阶段通过ASP.NET网站管理工具完成. 部署到服务器上时 ...

  6. [地图SkyLine二次开发]关于IE内存限制问题(1G)

    相信很多人也遇到过同样的问题,地图加载中,IE占用的内存一直增加,到了1G多一些的时候,IE就崩溃了. 在网上查阅了一番,有很多结果,下面归纳一下: a).64bit的IE最多可达到4G的内存,但Sk ...

  7. FirstUniqueCharacterInString

    Given a string, find the first non-repeating character in it and return it's index. If it doesn't ex ...

  8. java ZipOutputStream压缩文件,ZipInputStream解压缩

    java中实现zip的压缩与解压缩.java自带的 能实现的功能比较有限. 本程序功能:实现简单的压缩和解压缩,压缩文件夹下的所有文件(文件过滤的话需要对File进一步细节处理). 对中文的支持需要使 ...

  9. 大数据运算模型 MapReduce 原理

    大数据运算模型 MapReduce 原理 2016-01-24 杜亦舒 MapReduce 是一个大数据集合的并行运算模型,由google提出,现在流行的hadoop中也使用了MapReduce作为计 ...

  10. PHP Cookie Session

    这些都是基础知识,不过有必要做深入了解.先简单介绍一下. 二者的定义: 当你在浏览网站的时候,WEB 服务器会先送一小小资料放在你的计算机上,Cookie 会帮你在网站上所打的文字或是一些选择, 都纪 ...