我想了解什么时候适合在js中使用原型(prototype)方法。是否应该始终使用它们?或者是否存在不优选使用它们和/或导致性能损失的情况?
在本网站搜索 js 中命名空间的常用方法时,似乎大多数都使用基于非原型(prototype)的实现:简单地使用对象或函数对象来封装命名空间。
来自基于类的语言,很难不尝试进行相似之处并认为原型(prototype)就像“类”,而我提到的命名空间实现就像静态方法。
最佳答案
原型(prototype)是一种优化。
jQuery 库是很好地使用它们的一个很好的例子。每次使用 $('.someClass')
获取 jQuery 对象时,该对象都有数十个“方法”。该库可以通过返回一个对象来实现这一点:
return {
show: function() { ... },
hide: function() { ... },
css: function() { ... },
animate: function() { ... },
// etc...
};
但这意味着内存中的每个 jQuery 对象都会有数十个包含相同方法的命名槽,一遍又一遍。
相反,这些方法是在原型(prototype)上定义的,并且所有 jQuery 对象都“继承”该原型(prototype),以便以很少的运行时成本获得所有这些方法。
jQuery 如何正确实现这一点的一个至关重要的部分是,它对程序员是隐藏的。它纯粹被视为一种优化,而不是您在使用该库时必须担心的事情。
JavaScript 的问题在于,裸构造函数要求调用者记住在它们前面加上 new
前缀,否则它们通常无法工作。这没有充分的理由。 jQuery 通过将这些废话隐藏在普通函数 $
后面来实现这一点,因此您不必关心对象是如何实现的。
为了方便您创建具有指定原型(prototype)的对象,ECMAScript 5 包含一个标准函数 Object.create
。它的一个大大简化的版本如下所示:
Object.create = function(prototype) {
var Type = function () {};
Type.prototype = prototype;
return new Type();
};
它只是解决了编写构造函数然后使用 new
调用它的痛苦。
什么时候你会避免使用原型(prototype)?
与流行的 OO 语言(例如 Java 和 C#)进行有用的比较。它们支持两种继承:
- 接口(interface)继承,您在其中
实现
一个接口(interface)
,以便该类为该接口(interface)的每个成员提供自己独特的实现。< - 实现继承,您可以在其中
扩展
提供某些方法的默认实现的类
。
在 JavaScript 中,原型(prototype)继承是一种实现继承。因此,在这些情况下(在 C# 或 Java 中),您将从基类派生以获得默认行为,然后通过覆盖对其进行少量修改,那么在 JavaScript 中,原型(prototype)继承就有意义了。
但是,如果您在 C# 或 Java 中使用接口(interface),那么您不需要 JavaScript 中的任何特定语言功能。无需显式声明表示接口(interface)的内容,也无需将对象标记为“实现”该接口(interface):
var duck = {
quack: function() { ... }
};
duck.quack(); // we're satisfied it's a duck!
换句话说,如果对象的每个“类型”都有自己的“方法”定义,那么从原型(prototype)继承就没有任何值(value)。之后,这取决于您为每种类型分配的实例数量。但在许多模块化设计中,给定类型只有一个实例。
事实上,it has been suggested by many people that implementation inheritance is evil 。也就是说,如果某个类型有一些常见的操作,那么如果它们不放入基类/父类(super class)中,而是仅在某个模块中作为普通函数公开,并将对象传递给该模块,那么可能会更清楚您希望它们进行操作。
关于Javascript 何时使用原型(prototype),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31308283/