javascript - 通过原型(prototype)对象或构造函数设置方法,有什么区别?

标签 javascript constructor prototype

您能解释一下在构造函数中设置方法和通过原型(prototype)对象设置方法之间的区别吗?下面的代码展示了这两种设置方法的方式 - say_hellosay_bye两者都工作正常:

function MessageClass() {
  this.say_bye = function() { alert('see ya'); };
}

MessageClass.prototype.say_hello = function() { alert('hello'); };

x = new MessageClass();
x.say_hello();
x.say_bye();

最佳答案

foxxtrot 和 annakata 都是正确的,但我会投入 2 美分。

如果您使用原型(prototype),那么“MessageClass”的每个实例实际上都引用相同的函数。这些函数仅在内存中存在一次,并可用于所有实例。如果您在构造函数中声明方法(或以其他方式将其添加到特定实例)而不是原型(prototype)中,则将为 MessageClass 的每个实例创建一个新函数。

话虽这么说,在大多数情况下可能没有任何明显的性能差异,并且您也不太可能看到内存使用差异。我会使用原型(prototype)方法,除非你有令人信服的理由不这样做。我认为您可能想要在构造函数中声明方法的唯一原因是您是否需要闭包。例如,如果您有事件处理程序或者您想使用 getter/setter 模拟私有(private)属性,您可能会这样做:

function MessageClass() {
    var self = this;
    this.clickHander = function(e) { self.someoneClickedMe = true; };

    var _private = 0;
    this.getPrivate = function() { return _private; };
    this.setPrivate = function(val) { _private = val; };
}

编辑:因为已经讨论了这如何影响由另一个对象扩展的对象,并在构造函数中分配了函数,所以我添加了更多细节。我可能会使用术语“类”来简化讨论,但需要注意的是,js 不支持类(这并不意味着我们不能进行良好的 OO 开发),否则我们不会讨论这个问题。

大多数 javascript 库都会调用基类和子类的构造函数。 (例如 Prototype.js 的 Object.extend)这意味着在每个构造函数中分配的方法将在结果对象上可用。但是,如果您自己扩展对象,可能会出现意想不到的后果。

如果我采用上面的 MessageClass 并扩展它:

function ErrorMessageClass() {}
ErrorMessageClass.prototype = new MessageClass();

errorMsg = new ErrorMessageClass();

然后 errorMsg 将有一个 getPrivate 和 setPrivate 方法,但它们的行为可能不会如您所期望的那样。因为这些函数在分配时就已确定作用域(即在“ErrorMessageClass.prototype = new MessageClass()”处),不仅共享 get/setPrivate 方法,而且 _private 变量也在 ErrorMessageClass 的所有实例之间共享。这本质上使 _private 成为ErrorMessageClass 的静态属性。例如:

var errorA = new ErrorMessageClass();
var errorB = new ErrorMessageClass();
errorA.setPrivate('A');
console.log(errorA.getPrivate()); // prints 'A'
console.log(errorB.getPrivate()); // prints 'A'
errorB.setPrivate('B');
console.log(errorA.getPrivate()); // prints 'B'

与 clickHandler 函数和 personClickedMe 属性类似:

errorA.clickHandler();
console.log(errorA.someoneClickedMe); // prints 'true'
console.log(errorB.someoneClickedMe); // prints 'true'

但是,更改这些函数定义以使用 this._private:

this.getPrivate = function() { return this._private; };
this.setPrivate = function(val) { this._private = val; };

ErrorMessageClass 实例的行为变得更加符合您的预期:

errorA.setPrivate('A');
errorB.setPrivate('B');
console.log(errorA.getPrivate()); // prints 'A'
console.log(errorB.getPrivate()); // prints 'B'

关于javascript - 通过原型(prototype)对象或构造函数设置方法,有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31453440/

相关文章:

javascript - 主屏幕网络应用程序的 Facebook 身份验证已损坏!+

constructor - 未绑定(bind)变量或构造函数错误 ML

javascript - 如何实现这个继承模式: object. object.method

javascript - 将 sourceLocation 属性添加到函数中?

javascript - 如何存储/检索元素移动的最后位置?

javascript - GWT:弹出窗口阻止程序阻止 RPC 后打开窗口

javascript - 如果数组包含 2 个相同的对象,则改变第二个(或第三个、第四个)对象的值

Java默认构造函数没有初始化

在构造函数成员初始值设定项中抛出 C++ 异常?

javascript - `constructor` 属性的真正用途是什么?