为什么实例方法定义在原型中,而实例字段定义在构造函数中?

Why are instance methods defined in the prototype but instance fields are defined in the constructor?

本文关键字:定义 字段 构造函数 实例 原型 为什么 实例方法      更新时间:2023-09-26

在JavaScript中进行继承时,我经常看到的模式是在原型中定义实例方法,但在构造函数中定义实例字段(参见下面的示例)。这样做的动机是什么?为什么不保持一致,并在原型中定义两者呢?

function MyClass() {
    this.myField = 0; // why this...
}
MyClass.prototype.myField = 0; // ...instead of this?

说明

因为原型属性在所有实例之间是共享的,因为每个实例都有对同一个原型对象的引用。

这不是不可变类型的问题,你可以这样做:

MyClass.prototype.myField = 0;
var a = new MyClass();
a.myField = 42;

,只有a有这个值。这是因为赋值为a创建了属性myField。您可以在赋值前后调用a.hasOwnProperty('myField')来测试这一点。

但是如果你有对象或数组

MyClass.prototype.myField = [];

,你只是附加到该数组,不分配一个新的数组(如a.myField = []),那么每个实例在该数组中具有新值。


解决方案

必须在构造函数中初始化数组和对象,以便每个实例获得自己的对象或数组实例。一些风格指南建议你仍然在原型上创建属性,但是用null初始化它。这除了在代码中添加一些概念性结构(如果存在的话)之外,没有任何好处。

例如:

function MyClass() {
    this.myField = [];
}
/**
 * @type {Array}
 */
MyClass.prototype.myField = null;