请在此暂时忘记之前学到的面向对象的一切知识。这里只需要考虑赛车的情况。是的,就是赛车。
最近我正在观看 24 Hours of Le Mans ,这是法国流行的一项赛事。最快的车被称为 Le Mans 原型车。这些车虽然是由“奥迪”或“标致”这些厂商制造的,可它们并不是你在街上或速公路上所见到的那类汽车。它们是专为参加高速耐力赛事而制造出来的。
厂家投入巨额资金,用于研发、设计、制造这些原型车,而工程师们总是努力尝试将这项工程做到极致。他们在合金、生物燃料、制动技术、轮胎的化合物成分和安全特性上进行了各种实验。随着时间的推移,这些实验中的某些技术经过反复改进,随之进入到车辆的主流产品线中。你所驾驶车辆的某些技术,有可能是在赛车原型上第一次亮相的。
你也可以说,这些主流车辆继承了来自赛车的技术原型。
到现在,我们就有讨论 JavaScript 中的原型和继承问题的基础了。它虽然并不像你在 C++、Java 或 C# 中了解的经典继承模式一样,但这种方式同样强大,并且有可能会更加灵活。
有关对象和类JavaScript 中全是对象,这指的是传统意义上的对象,也就是“一个包含了状态和行为的单一实体”。例如,JavaScript 中的数组是含有数个值,并且包含 push、reverse 和 pop 方法的对象。
var myArray = [1, 2]; myArray.push(3); myArray.reverse(); myArray.pop(); var length = myArray.length;现在问题是,push 这样的方法是从何而来的呢?我们前面提到的那些静态语言使用“类语法”来定义对象的结构,但是 JavaScript 是一个没有“类语法”的语言,无法用 Array“类”的语法来定义每个数组对象。而因为 JavaScript 是动态语言,我们可以在实际需要的情况下,将方法任意放置到对象上。例如下面的代码,就在二维空间中,定义了用来表示一个点的点对象,同时还定义了一个 add 方法。
var point = { x : 10, y : 5, add: function(otherPoint) { this.x += otherPoint.x; this.y += otherPoint.y; } };但是上面的做法可扩展性并不好。我们需要确保每一个点对象都含有一个 add 方法,同时也希望所有点对象都共享同一个 add 方法的实现,而不是这个方法手工添加每一个点对象上。这就是原型发挥它作用的地方。
有关原型在 JavaScript 中,每个对象都保持着一块隐藏的状态 —— 一个对另一个对象的引用,也被称作原型。我们之前创建的数组引用了一个原型对象,我们自行创建的点对象也是如此。上面说原型引用是隐藏的,但也有 ECMAScript(JavaScript 的正式名称)的实现可以通过一个对象的__proto__属性(例如谷歌浏览器)访问到这个原型引用。从概念上讲,我们可以将对象当作类似于 图1 所表示的对象 —— 原型的关系。
图 1
展望未来,开发者将能够使用 Object.getPrototypeOf 函数,代替__proto__属性,取得对象原型的引用。在本文写出的时候,已经可以在 Google Chrome,FIrefox 和 IE9 浏览器中使用 Object.getPrototypeOf 函数。更多浏览器在未来会实现此功能,因为它已经是 ECMAScript 标准的一部分了。我们可以使用下面的代码,来证明我们建立的 myArray 和点对象引用的是两个不同的原型对象。
Object.getPrototypeOf(point) != Object.getPrototypeOf(myArray);
对于本文的其余部分,我将交叉使用 __proto__和Object.getPrototypeOf 函数,主要是因为 __proto__ 在图和句子中更容易识别。需要记住的是它(__proto__)不是标准,而 Object.getPrototypeOf 函数才是查看对象原型的推荐方法。
是什么让原型如此特别?
我们还没有回答这个问题:数组中 push 这样的方法是从何而来的呢?答案是:它来源于 myArray 原型对象。图 2 是 Chrome 浏览器中脚本调试器的屏幕截图。我们已经调用 Object.getPrototypeOf 方法查看 myArray 的原型对象。
图 2
注意 myArray 的原型对象中有许多方法,包括那些在代码示例中调用的 push、pop 和 reverse 方法。因此,原型对象中的确包括 push 方法,但是 myArray 方法如何引用到呢?
myArray.push(3);了解其工作原理的第一步,是要认识到原型并不是特别的。原型只是普通的对象。可以给原型添加方法,属性,并把他们当作其他 JavaScript 对象一样看待。然而,套用乔治·奥威尔的小说《动物农场》中“猪”的说法 —— 所有的对象应当是平等的,但有些对象(遵守规则的)比其他人更加平等。