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. 读《编写可维护的JavaScript》第11章总结

    这周也是拿到了同程的offer,从此走上了前端之路!感谢我的贵人们.再次纪念一下~! 第11章 不是你的对象不要动 11.1 什么是你的 你的对象:当你的代码创建了这些对象或者你有职责维护其他人的代码 ...

  2. 解决iphone5s,iphone6不能使用luajit及luac的问题

    做手游有小段时间了,感觉坤哥给这么多的机会.一直都比较忙项目的事,比较没时间去写点东西做点记录.想想还是写点开发问题记录比较好,可以很简短,也可以很有用. 我们项目采用的cocos2d-x的引擎,之前 ...

  3. 团队作业week14

    0 如果你的团队来了一个新队员,有一台全新的机器,你们是否有一个文档,只要设置了相应的权限,她就可以根据文档,从头开始搭建环境, 并成功地把最新.最稳定版本的软件编译出来,并运行必要的单元测试?(在这 ...

  4. 学习UFT11.5历程(一)

    博主三年来测试都是功能测试 看了虫师的文章,感觉是要学点东西.所以,听从虫师的话,不被眼花瞭乱的测试技术打扰,先学习UFT,再学习python. 再不学习感觉要被淘汰了...... 也不想有谈工资的时 ...

  5. SQL查出异常数据(ORA-01722: 无效数字)

    -- Created on 2015/4/29 by MENGHU DECLARE -- Local variables here I INTEGER; BEGIN FOR OPEN_DATA IN ...

  6. G将军的敢死队——树状DP

    当前节点的两种情况: 1.beChoosed = {son.beAbandoned乘积} //当前节点选中的情况下,子节点都不能选 2.beAbandoned = {(son.beAbandoned ...

  7. mysql字符串函数(转载)

    对于针对字符串位置的操作,第一个位置被标记为1. ASCII(str) 返回字符串str的 最左面字符的ASCII代码值.如果str是空字符串, 返回0.如果str是NULL,返回NULL. mysq ...

  8. MySQL查询分析器EXPLAIN或DESC

    转载:http://chenzehe.iteye.com/blog/1682081 MySQL可以通过EXPLAIN或DESC来查看并分析SQL语句的执行情况,如下需要计算2006年所有公司的销售额, ...

  9. java 计算 1到10 的 阶层的和(采用递归的方法)

    package hibernate; public class t { public static void main(String[] args) { System.out.println(jiec ...

  10. Microsoft Office Project 相关教程 收集

    Project教程 如何建立任务间链接 Project教程:[10]如何将项目插入主项目 如何有效使用Project(1)——编制进度计划.保存基准 如何有效使用Project(2)——进度计划的执行 ...