我应该使用原型还是不?
我正在创build一个Vector类,它基本上可以保存三个数值。 然而,可以对这样一个向量进行很多操作 – 例如获取数量级,增加或减less另一个向量等。
我想知道这些函数是否应该被编码为Vector类的原型函数,或者我应该在构造函数中定义它们。
那么这两种方法哪一种更可取?
function Vector3D(x, y, z) { this.x = x; this.y = y this.z = z; } Vector3D.prototype.magnitude = function() { return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); };
要么
function Vector3D(x, y, z) { this.x = x; this.y = y; this.z = z; this.magnitude = function() { return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); }; }
这正是使用原型的情况。 我看到这样做的两个主要好处:
- 函数不会多次创build 。 如果您在构造函数中定义函数,则每次调用构造函数时都会为您定义的每个函数创build一个新的匿名函数。 原型是静态对象,Vector3D的每个实例将只是引用原型函数。
- 原型是一个可以轻松操作的单个对象 。 这提供了很大的灵活性; 不幸的是,我只能提供一些可以提供的例子:
- 如果你想创build一个子类,例如Vector3DSpecial,你可以简单地克隆
Vector3D.prototype
并将其分配给Vector3DSpecial.prototype
。 虽然你也可以通过Vector3DSpecial.prototype = new Vector3D();
来使用构造函数Vector3DSpecial.prototype = new Vector3D();
,构造函数可能包含将在该简单原型分配中执行的副作用,因此应该避免。 通过原型,您甚至可以只select原型中的特定function以复制到新的类中。 - 向
Vector3D
添加方法只需要向原型添加属性,并允许将代码更容易地拆分/组织成多个文件,或允许dynamic地在代码的其他部分添加方法。 当然,您可以在构造函数和原型中添加方法的组合,但这是不一致的,可能导致更复杂的进一步下降。
- 如果你想创build一个子类,例如Vector3DSpecial,你可以简单地克隆
我什么时候不使用原型? 对于单身对象,例如与页面交互的控制器,可以将工作委托给其他对象。 全球“通知”对象就是这样一个例子。 在这里,扩展是不太可能的,并且该对象只创build一次,使原型成为一个额外的(概念上的)复杂性。
原型方法只适用于公共属性,如果您将x,y,z追踪为“私有”variables,则原型将无法工作。
我会使用后者,因为您可能需要只使用私有/内部variables的方法,但这一切都取决于上下文。
function Vector3D(x, y, z) { // x, y, z is automatically in this scope now, but as private members. this.magnitude = function() { return Math.sqrt(x * x + y * y + z *z); } }
ECMA 6 http://es6-features.org/#BaseClassAccess
class Shape { … toString () { return `Shape(${this.id})` } } class Rectangle extends Shape { constructor (id, x, y, width, height) { super(id, x, y) … } toString () { return "Rectangle > " + super.toString() } } class Circle extends Shape { constructor (id, x, y, radius) { super(id, x, y) … } toString () { return "Circle > " + super.toString() } }
ECMA 5
var Shape = function (id, x, y) { … }; Shape.prototype.toString = function (x, y) { return "Shape(" + this.id + ")" }; var Rectangle = function (id, x, y, width, height) { Shape.call(this, id, x, y); … }; Rectangle.prototype.toString = function () { return "Rectangle > " + Shape.prototype.toString.call(this); }; var Circle = function (id, x, y, radius) { Shape.call(this, id, x, y); … }; Circle.prototype.toString = function () { return "Circle > " + Shape.prototype.toString.call(this); };