在原型上声明属性根本不是反模式。当我看一个prototype
对象时,我会想“这就是这种类型的原型对象对数据和方法所拥有的东西”。
其他人警告不要在原型中给属性一个引用值,例如:Foo.prototype.bar = [];
--- 因为数组和对象是引用类型。引用类型是不可变的,因此“类”的每个实例都引用同一个数组或对象。只需null
在原型中设置它们,然后在构造函数中给它们一个值。
我总是在原型中包含所有属性,原因很明确:与其他程序员交流哪些属性是公开可用的以及它们的默认值是什么,而不需要他们筛选构造函数来弄清楚。
如果您正在创建需要文档的共享库,这将变得特别有用。
考虑这个例子:
/**
* class Point
*
* A simple X-Y coordinate class
*
* new Point(x, y)
* - x (Number): X coordinate
* - y (Number): Y coordinate
*
* Creates a new Point object
**/
function Point(x, y) {
/**
* Point#x -> Number
*
* The X or horizontal coordinate
**/
this.x = x;
/**
* Point#y -> Number
*
* The Y or vertical coordinate
**/
this.y = y;
}
Point.prototype = {
constructor: Point,
/**
* Point#isAbove(other) -> bool
* - other (Point): The point to compare this to
*
* Checks to see if this point is above another
**/
isAbove: function(other) {
return this.y > other.y;
}
};
(文档格式:PDoc)
在这里仅仅阅读文档有点尴尬,因为关于x
和y
属性的信息嵌入在构造函数中。将其与在原型中包含这些属性的“反模式”进行对比:
/**
* class Point
*
* A simple X-Y coordinate class
*
* new Point(x, y)
* - x (Number): X coordinate
* - y (Number): Y coordinate
*
* Creates a new Point object
**/
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype = {
/**
* Point#x -> Number
*
* The X or horizontal coordinate
**/
x: 0,
/**
* Point#y -> Number
*
* The Y or vertical coordinate
**/
y: 0,
constructor: Point,
/**
* Point#isAbove(other) -> bool
* - other (Point): The point to compare this to
*
* Checks to see if this point is above another
**/
isAbove: function(other) {
return this.y > other.y;
}
};
现在查看原型可以为您提供实际对象的快照,这更容易在您的脑海中可视化,并且作者更容易编写文档。构造函数也不会被文档弄得乱七八糟,并且坚持将Point
对象带入生活的业务。
Point
原型拥有一切,并且是关于“原型”对象对方法和数据都有什么的规范信息源。
我认为在原型中不包含数据属性是反模式。