我经常看到这种模式来定义JavaScript对象
function Person(name) {
this.name = name;
}
Person.prototype.describe = function () {
return "Person called "+this.name;
};
而在这篇文章中 ,它说的是直接添加属性原型objct被认为是一个反模式。
从“古典文学课以”语言的到来,不必从方法除了定义属性不健全的很正确,moreoever在JavaScript中,其中一个方法应该只是一个函数值属性(我说的对吗?)
我想知道如果任何人都可以解释这一点,甚至提出一个更好的方式来处理这些情况
在通常的面向对象的语言,你描述的成员,方法和构造函数的类的定义。
在JS的“类”的定义(这是不是真的喜欢其他语言类...有时使用术语伪类)的构造本身。 如果你的对象是由parametrised name
,它是有道理的写
function Person(name) {
this.name = name;
}
即该属性name
必须在构造函数中进行设置。
当然,你可以写
function Person(name) {
this.name = name;
this.describe = function() { ... };
}
正如你希望它会工作。
然而,在这种情况下,你与构造的每一个呼叫建立的方法的一个单独的实例。
在另一方面,在这里:
Person.prototype.describe = function () {
return "Person called "+this.name;
};
你只有一次定义方法。 的所有实例Person
将获得一个指针(称为__proto__
和在大多数浏览器不是程序员访问)来Person.prototype
。 所以,如果你打电话
var myPerson = new Person();
myPerson.describe();
它会工作,因为JS直接观察对象成员中的对象,然后在它的原型等,一路到Object.prototype
。
的一点是,在第二种情况下,只有一个函数的实例将存在。 你可能会同意,是一个更好的设计。 而且,即使你不这样做,它只是需要更少的内存。
这没有什么不对的代码。 推测这是什么意思:
function Person(name) {
this.name = name;
}
Person.prototype.age = 15; //<= adding a hardcoded property to the prototype
现在你会看到:
var pete = new Person('Pete'), mary = new Person('Mary');
pete.age; //=> 15
mary.age //=> 15
而大部分时间,这不是你想要的。 分配给一个构造的原型属性都实例之间共享,构造(内分配属性this.name
)特异于该实例。
作为arxanas说,文中提到的数据属性 。
究其原因,我认为,是该数据通常是特定于实例 ,所以它没有任何意义,将其添加到原型。
此外,如果你的数据是一个可变类型,例如数组的,你把它分配给了原形,那么这个数组实例的所有实例之间共享,你不能使用它,就好像每个实例有它自己的阵列。
例如:下面的导致不正确的行为:
function Set() {
}
// shared between instances
// each instance adds values to **the same** array
Set.prototype.elements = [];
Set.prototype.add = function(x) {
this.elements.push(x);
};
它应该是:
function Set() {
// each instance gets its own array
this.elements = [];
}
Set.prototype.add = function(x) {
this.elements.push(x);
};
把它们加起来:
- 添加应该对原型的所有实例之间共享的属性。
- 例如指定特定数据的构造函数中。
就像arxanas在他的评论中写道。 在原型数据属性都或多或少类似于类级变量在传统的OOP。 而这些未使用的日常基础上的,除非你有一个非常具体的需要。 就这样。
在原型声明的属性是不是在所有的反模式。 当我看到一个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
对象有两种方法和数据。
我认为,在原型不包括数据的属性是反模式。