为什么要定义在原型属性被认为是一个反模式(Why defining properties in th

2019-06-26 23:36发布

我经常看到这种模式来定义JavaScript对象

function Person(name) {
    this.name = name;
}
Person.prototype.describe = function () {
    return "Person called "+this.name;
};

而在这篇文章中 ,它说的是直接添加属性原型objct被认为是一个反模式。

从“古典文学课以”语言的到来,不必从方法除了定义属性不健全的很正确,moreoever在JavaScript中,其中一个方法应该只是一个函数值属性(我说的对吗?)

我想知道如果任何人都可以解释这一点,甚至提出一个更好的方式来处理这些情况

Answer 1:

在通常的面向对象的语言,你描述的成员,方法和构造函数的类的定义。

在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

的一点是,在第二种情况下,只有一个函数的实例将存在。 你可能会同意,是一个更好的设计。 而且,即使你不这样做,它只是需要更少的内存。



Answer 2:

这没有什么不对的代码。 推测这是什么意思:

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 )特异于该实例。



Answer 3:

作为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);
};

把它们加起来:

  • 添加应该对原型的所有实例之间共享的属性。
  • 例如指定特定数据的构造函数中。


Answer 4:

就像arxanas在他的评论中写道。 在原型数据属性都或多或少类似于类级变量在传统的OOP。 而这些未使用的日常基础上的,除非你有一个非常具体的需要。 就这样。



Answer 5:

在原型声明的属性是不是在所有的反模式。 当我看到一个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 )

只要阅读文档这里是一个有点尴尬,因为有关的信息xy属性嵌入在构造函数中。 对比,与包括在原型这些属性的“反模式”:

/**
 * 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对象有两种方法数据。

我认为,在原型包括数据的属性是反模式。



文章来源: Why defining properties in the prototype is considered an antipattern