<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-cn">
		<id>http://wiki.tomtalk.net/index.php?action=history&amp;feed=atom&amp;title=%E5%86%8D%E8%B0%88javascript%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%BC%96%E7%A8%8B</id>
		<title>再谈javascript面向对象编程 - 版本历史</title>
		<link rel="self" type="application/atom+xml" href="http://wiki.tomtalk.net/index.php?action=history&amp;feed=atom&amp;title=%E5%86%8D%E8%B0%88javascript%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%BC%96%E7%A8%8B"/>
		<link rel="alternate" type="text/html" href="http://wiki.tomtalk.net/index.php?title=%E5%86%8D%E8%B0%88javascript%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%BC%96%E7%A8%8B&amp;action=history"/>
		<updated>2026-04-24T14:42:43Z</updated>
		<subtitle>本wiki的该页面的版本历史</subtitle>
		<generator>MediaWiki 1.24.2</generator>

	<entry>
		<id>http://wiki.tomtalk.net/index.php?title=%E5%86%8D%E8%B0%88javascript%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%BC%96%E7%A8%8B&amp;diff=3364&amp;oldid=prev</id>
		<title>2013年3月24日 (日) 02:29 Tom</title>
		<link rel="alternate" type="text/html" href="http://wiki.tomtalk.net/index.php?title=%E5%86%8D%E8%B0%88javascript%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%BC%96%E7%A8%8B&amp;diff=3364&amp;oldid=prev"/>
				<updated>2013-03-24T02:29:00Z</updated>
		
		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;==吐槽Javascript==&lt;br /&gt;
&lt;br /&gt;
初次接触Javascript，这门语言的确会让很多正规军感到诸多的不适，这种不适来自于Javascript的语法的简练和不严谨，这种不适也来自Javascript这个悲催的名称，我在想网景公司的Javascript设计者在给他起名称那天一定是脑壳进水了,让Javascript这么多年来受了这么多不白之冤，人们都认为他是Java的附属物，一个WEB玩具语言。因此才会有些人会对Javascript不屑，认为Javascript不是一门真正的语言，但是这此他们真的错了。Javascript不仅是一门语言，是一门真真正正的语言，而且他还是一门里程碑式的语言，他独创多种新的编程模式原型继承，闭包（作者注：闭包不是JS首创，应该Scheme首创，prototypal inheritance 和 dynamic objects 是self语言首创，Javascript的首创并不精彩,谢谢网友的指正。），对后来的动态语言产生了巨大的影响。做为当今最流行的语言（没有之一），看看git上提交的最多的语言类型就能明白。随着HTML5的登场，浏览器将在个人电脑上将大显身手，完全有替换OS的趋势的时候，Javascript做为浏览器上的一门唯一真真的语言，如同C之于 unix/linux，java之于JVM，Cobol之于MainFrame，我们也需要来重新的认真地认识和审视这门语言。另外Javascript的正式名称是：ECMAScript，这个名字明显比Javascript帅太多了！&lt;br /&gt;
&lt;br /&gt;
言归正传，我们切入主题——Javascript的面向对象编程。要谈Javascript的面向对象编程，我们第一步要做的事情就是忘记我们所学的面向对象编程。传统C++或Java的面向对象思维来学习Javascript的面向对象会给你带来不少困惑，让我们先忘记我们所学的，从新开始学习这门特殊的面向对象编程。既然是OO编程，要如何来理解OO编程呢，记得以前学C++，学了很久都不入门，后来有幸读了《Inside The C++ Object Model》这本大作，顿时豁然开朗，因此本文也将以对象模型的方式来探讨的Javascript的OO编程。因为Javascript 对象模型的特殊性，所以使得Javascript的继承和传统的继承非常不一样，同时也因为Javascript里面没有类，这意味着Javascript里面没有extends,implements。那么Javascript到底是如何来实现OO编程的呢？好吧，让我们开始吧，一起在Javascript的OO世界里来一次漫游&lt;br /&gt;
&lt;br /&gt;
首先，我们需要先看看Javascript如何定义一个对象。下面是我们的一个对象定义：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var o = {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
还可以这样定义一个对象 &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
function f() {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
对，你们没有看错，在Javascript里面，函数也是对象。 当然还可以&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var array1= [ 1,2,3]; //数组也是一个对象&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
其他关于对象的基本的概念的描述，还是请各位亲们参见陈皓《Javascript 面向对象编程》文章。&lt;br /&gt;
&lt;br /&gt;
对象都有了，唯一没有的就是class，因为在Javascript里面是没有class关键字的，算好还有function，function的存在让我们可以变通的定义类，在扩展这个主题前，我们还需要了解一个Javascript对象最重要的属性，__proto__成员。&lt;br /&gt;
&lt;br /&gt;
==__proto__成员==&lt;br /&gt;
&lt;br /&gt;
严格的说这个成员不应该叫这个名字，__proto__是Firefox中的称呼，__proto__只有在Firefox浏览器中才能被访问到。做为一个对象，当你访问其中的一个成员或方法的时候，如果这个对象中没有这个方法或成员，那么Javascript引擎将会访问这个对象的__proto__成员所指向的另外的一个对象，并在那个对象中查找指定的方法或成员，如果不能找到，那就会继续通过那个对象的__proto__成员指向的对象进行递归查找，直到这个链表结束。好了，让我们举一个例子。&lt;br /&gt;
&lt;br /&gt;
比如上上面定义的数组对象array1。当我们创建出array1这个对象的时候，array1实际在Javascript引擎中的对象模型如下：&lt;br /&gt;
&lt;br /&gt;
http://coolshell.cn/wp-content/uploads/2012/02/joo_1.png&lt;br /&gt;
&lt;br /&gt;
array1对象具有一个length属性值为3，但是我们可以通过如下的方法来为array1增加元素：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
array1.push(4);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
push这个方法来自于array1的__proto__成员指向对象的一个方法(Array.prototye.push())。正是因为所有的数组对象（通过[]来创建的）都包含有一个指向同一个具有push,reverse等方法对象(Array.prototype)的__proto__成员，才使得这些数组对象可以使用push,reverse等方法。&lt;br /&gt;
&lt;br /&gt;
那么这个__proto__这个属性就相当于面向对象中的”has a”关系，这样的的话，只要我们有一个模板对象比如Array.prototype这个对象，然后把其他的对象__proto__属性指向这个对象的话就完成了一种继承的模式。不错！我们完全可以这么干。但是别高兴的太早，这个属性只在FireFox中有效，其他的浏览器虽然也有属性，但是不能通过__proto__来访问，只能通过getPrototypeOf方法进行访问，而且这个属性是只读的。看来我们要在Javascript实现继承并不是很容易的事情啊。&lt;br /&gt;
&lt;br /&gt;
==函数对象prototype成员==&lt;br /&gt;
&lt;br /&gt;
首先我们先来看一段函数prototype成员的定义，&lt;br /&gt;
&lt;br /&gt;
;When a function object is created, it is given a prototype member which is an object containing a constructor member which is a reference to the function object. 当一个函数对象被创建时，这个函数对象就具有一个prototype成员，这个成员是一个对象，这个对象包含了一个构造子成员，这个构造子成员会指向这个函数对象。&lt;br /&gt;
&lt;br /&gt;
例如：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
function Base() {&lt;br /&gt;
    this.id = &amp;quot;base&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Base这个函数对象就具有一个prototype成员，关于构造子其实Base函数对象自身，为什么我们将这类函数称为构造子呢？原因是因为这类函数设计来和new 操作符一起使用的。为了和一般的函数对象有所区别，这类函数的首字母一般都大写。构造子的主要作用就是来创建一类相似的对象。&lt;br /&gt;
&lt;br /&gt;
上面这段代码在Javascript引擎的对象模型是这样的&lt;br /&gt;
&lt;br /&gt;
http://coolshell.cn/wp-content/uploads/2012/02/joo_2.png&lt;br /&gt;
&lt;br /&gt;
==new 操作符==&lt;br /&gt;
&lt;br /&gt;
在有上面的基础概念的介绍之后，在加上new操作符，我们就能完成传统面向对象的class + new的方式创建对象，在Javascript中，我们将这类方式成为Pseudoclassical。&lt;br /&gt;
&lt;br /&gt;
基于上面的例子，我们执行如下代码&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var obj = new Base();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
这样代码的结果是什么，我们在Javascript引擎中看到的对象模型是：&lt;br /&gt;
&lt;br /&gt;
http://coolshell.cn/wp-content/uploads/2012/02/joo_3.png&lt;br /&gt;
&lt;br /&gt;
new操作符具体干了什么呢?其实很简单，就干了三件事情。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var obj  = {};&lt;br /&gt;
obj.__proto__ = Base.prototype;&lt;br /&gt;
Base.call(obj);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 第一行，我们创建了一个空对象obj&lt;br /&gt;
* 第二行，我们将这个空对象的__proto__成员指向了Base函数对象prototype成员对象&lt;br /&gt;
* 第三行，我们将Base函数对象的this指针替换成obj，然后再调用Base函数，于是我们就给obj对象赋值了一个id成员变量，这个成员变量的值是”base”，关于call函数的用法，请参看陈皓《Javascript 面向对象编程》文章&lt;br /&gt;
&lt;br /&gt;
如果我们给Base.prototype的对象添加一些函数会有什么效果呢？ 如代码如下：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
Base.prototype.toString = function() {&lt;br /&gt;
    return this.id;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
那么当我们使用new创建一个新对象的时候，根据__proto__的特性，toString这个方法也可以做新对象的方法被访问到。于是我们看到了：&lt;br /&gt;
&lt;br /&gt;
构造子中，我们来设置‘类’的成员变量（例如：例子中的id），构造子对象prototype中我们来设置‘类’的公共方法。于是通过函数对象和Javascript特有的__proto__与prototype成员及new操作符，模拟出类和类实例化的效果。&lt;br /&gt;
&lt;br /&gt;
==Pseudoclassical 继承==&lt;br /&gt;
&lt;br /&gt;
我们模拟类，那么继承又该怎么做呢？其实很简单，我们只要将构造子的prototype指向父类即可。例如我们设计一个Derive 类。如下&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
function Derive(id) {&lt;br /&gt;
    this.id = id;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Derive.prototype = new Base();&lt;br /&gt;
Derive.prototype.test = function(id){&lt;br /&gt;
    return this.id === id;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var newObj = new Derive(&amp;quot;derive&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
这段代码执行后的对象模型又是怎么样的呢？根据之前的推导，应该是如下的对象模型&lt;br /&gt;
&lt;br /&gt;
http://coolshell.cn/wp-content/uploads/2012/02/joo_4.png&lt;br /&gt;
&lt;br /&gt;
这样我们的newObj也继承了基类Base的toString方法，并且具有自身的成员id。关于这个对象模型是如何被推导出来的就留给各位同学了，参照前面的描述，推导这个对象模型应该不难。&lt;br /&gt;
&lt;br /&gt;
Pseudoclassical继承会让学过C++/Java的同学略微的感受到一点舒服，特别是new关键字，看到都特亲切，不过两者虽然相似，但是机理完全不同。当然不关什么样继承都是不能离不开__proto__成员的。&lt;br /&gt;
&lt;br /&gt;
==Prototype继承==&lt;br /&gt;
&lt;br /&gt;
这是Javascript的另外一种继承方式，这个继承也就是之前陈皓文章《Javascript 面向对象编程》中create函数，非常可惜的是这个是ECMAScript V5的标准，支持V5的浏览器目前看来也就是IE9，Chrome最新版本和Firefox。虽然看着多，但是做为IE6的重灾区的中国，我建议各位还是避免使用create函数。好在没有create函数之前，Javascript的使用者已经设计出了等同于这个函数的。例如：我们看看Douglas Crockford的object函数。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
function object(old) {&lt;br /&gt;
    function F() {};&lt;br /&gt;
    F.prototype = old;&lt;br /&gt;
    return new F();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var newObj = object(oldObject);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
例如如下代码段&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var base ={&lt;br /&gt;
id:&amp;quot;base&amp;quot;,&lt;br /&gt;
   toString:function(){&lt;br /&gt;
       return this.id;&lt;br /&gt;
   }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var derive = object(base);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
上面函数的执行后的对象模型是：&lt;br /&gt;
&lt;br /&gt;
http://coolshell.cn/wp-content/uploads/2012/02/joo_5.png&lt;br /&gt;
&lt;br /&gt;
如何形成这样的对象模型，原理也很简单，只要把object这个函数扩展一下，就能画出这个模型，怎么画留给读者自己去画吧。&lt;br /&gt;
&lt;br /&gt;
这样的继承方式被称为原型继承。相对来说要比Pseudoclassical继承来的简单方便。ECMAScript V5正是因为这原因也才增加create函数，让开发者可以快速的实现原型继承。&lt;br /&gt;
&lt;br /&gt;
上述两种继承方式是Javascript中最常用的继承方式。通过本文的讲解，你应该对Javascript的OO编程有了一些‘原理’级的了解了吧&lt;br /&gt;
&lt;br /&gt;
==参考==&lt;br /&gt;
&lt;br /&gt;
《Prototypes and Inheritance in JavaScript Prototypes and Inheritance in JavaScript》Advance Javascript （Douglas Crockford 大神的视频，一定要看啊）&lt;br /&gt;
&lt;br /&gt;
==题外话==&lt;br /&gt;
&lt;br /&gt;
web2.0后，web应用可谓飞速发展，如今在HTML5发布之际，浏览器的功能被大大强化，我感觉Browser远远在不是一个Browser那么简单了。记得C++之父曾经这样说过JAVA，JAVA不是跨平台，JAVA本身就是一个平台。如今的Browser也本身就是一个平台了，好在这个平台是基于标准的。如果Browser是平台，由于Browser安全沙箱的限制，个人电脑的资源被使用的很少，感觉Browser就是一个NC（Network Computer）？我们居然又回到了Sun最初提出的构想，Sun是不是太强大了些？&lt;/div&gt;</summary>
		<author><name>Tom</name></author>	</entry>

	</feed>