为什么在原型中定义属性被认为是反模式

ope*_*sas 7 javascript prototype anti-patterns prototypal-inheritance prototype-programming

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

function Person(name) {
    this.name = name;
}
Person.prototype.describe = function () {
    return "Person called "+this.name;
};
Run Code Online (Sandbox Code Playgroud)

本文中,它表示直接向原型对象添加属性被视为反模式.

来自"基于经典类"的语言,除了方法之外必须定义属性听起来不太正确,不过在javascript中,方法应该只是具有函数值的属性(我在这里吗?)

我想知道是否有人可以解释这个,甚至建议一个更好的方法来处理这些情况

Imp*_*Imp 6

在通常的面向对象语言中,您有一个描述成员,方法和构造函数的类的定义.

在JS中,"类"的定义(它实际上并不像其他语言中的类......有时使用术语伪类)是构造函数本身.如果您的对象是参数化的name,那么写入是有意义的

function Person(name) {
    this.name = name;
}
Run Code Online (Sandbox Code Playgroud)

name必须在构造函数中设置属性.

当然,你可以写

function Person(name) {
    this.name = name;
    this.describe = function() { ... };
}
Run Code Online (Sandbox Code Playgroud)

它会像你期望的那样工作.

但是,在这种情况下,您每次调用构造函数时都会创建一个单独的方法实例.

另一方面,这里:

Person.prototype.describe = function () {
    return "Person called "+this.name;
};
Run Code Online (Sandbox Code Playgroud)

你只定义一次方法.所有实例Person都会收到一个指针(__proto__在大多数浏览器中被程序员调用并且无法访问)Person.prototype.所以,如果你打电话

var myPerson = new Person();
myPerson.describe();
Run Code Online (Sandbox Code Playgroud)

它会工作,因为JS直接在对象中查找对象成员,然后在其原型等中查找对象成员Object.prototype.

关键是在第二种情况下,只存在一个函数实例.你可能会认为这是一个更好的设计.即使你不这样做,也只需要更少的内存.


Koo*_*Inc 6

这段代码没有错.据说这意味着:

function Person(name) {
    this.name = name;
}
Person.prototype.age = 15; //<= adding a hardcoded property to the prototype
Run Code Online (Sandbox Code Playgroud)

现在你会看到这个:

var pete = new Person('Pete'), mary = new Person('Mary');
pete.age; //=> 15
mary.age  //=> 15
Run Code Online (Sandbox Code Playgroud)

大多数时候,这不是你想要的.分配给构造函数原型的属性在所有实例之间共享,构造函数(this.name)中分配的属性特定于实例.