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. SQL函数

    1,字符串截取拼接 CONCAT(),'****');SUBSTRING_INDEX(c.context,'}',1);SUBSTRING_INDEX(a.task_context,':',-1) a ...

  2. Bean熟悉替换,只替换部分属性,其他属性值不改变

    Bean熟悉替换,只替换部分属性,其他属性值不改变 需要加入:asm.jar  cglib-2.1.jar,用来map和bean之间的转换(比spring和反射的效率好,因为加入了缓存) packag ...

  3. 有关uploadifive的使用经验

    这段时间做了一个项目用到uploadifive上传控件,和uploadify不同,这个控件是基于HTML5的版本而不用支持falsh,因而移动端也可以使用. 整理用过的相关属性与方法: 属性 作用 a ...

  4. ajax post 请求415\ 400 错误

    今天用ajax 向后台发送 post请求时,出现了两个问题: 1, 发送请求后,控制台 返回  Unsupported media type-415(不支持的媒体类型),这时突然想起来,post 请求 ...

  5. Oracle 新增删除账户

    新增用户: create user test identified by 123456;grant dba,connect,resource to test; 删除账户: drop user xxx ...

  6. PacBio三代全长转录组/Iso-Seq技术及案例分析

    参考:产品手册 PacBio三代全长转录组有什么优势? 近年来,随着高通量测序技术的发展,转录组测序已经成为研究基因表达调控的主要手段.但二代的转录本重构准确率很低,三代可以直接得到全长转录本,无需组 ...

  7. Result Maps collection already contains value for

    Result Maps collection already contains value for select s.id,s.branch_name from t_wx_shop s left jo ...

  8. 效率最高的Excel数据导入---(c#调用SSIS Package将数据库数据导入到Excel文件中【附源代码下载】) 转

    效率最高的Excel数据导入---(c#调用SSIS Package将数据库数据导入到Excel文件中[附源代码下载])    本文目录: (一)背景 (二)数据库数据导入到Excel的方法比较   ...

  9. Centos screen远程会话管理命令

    screen参数 -A 将所有的视窗都调整为目前终端机的大小. -d<作业名称> 将指定的screen作业离线. -h<行数> 指定视窗的缓冲区行数. -m 即使目前已在作业中 ...

  10. html/css 浮动练习之井字形布局

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...