通过原型对象或在构造函数中设置方法,区别? [英] Setting methods through prototype object or in constructor, difference?

查看:23
本文介绍了通过原型对象或在构造函数中设置方法,区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

能否解释一下构造函数中设置方法和原型对象设置方法的区别?以下代码显示了这两种设置方法的方式 - say_hellosay_bye 都可以正常工作:

Could you explain the difference between setting methods in the constructor and through prototype object? The following code shows these two ways of setting the methods - say_hello and say_bye both work fine:

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 美分.

foxxtrot and annakata are both correct, but I'll throw in my 2 cents.

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

If you use the prototype then each instance of the "MessageClass" is really referencing the same functions. The functions exist in memory only once and are used for all instances. If you declare the methods in the constructor (or otherwise add it to a specific instance) rather than the prototype then a new function is created for each instance of MessageClass.

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

That being said, there is probably not any noticeable performance difference for most cases and it is unlikely that you will see a memory usage difference either. I would go with the prototype method unless you have a compelling reason to do otherwise. The only reason I can thing that you might want to declare a method in the constructor is if you need a closure. For example, if you have event handlers or you wanted to simulate private properties with getters/setters you might do:

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 开发),否则我们不会讨论这个问题.

Because there has been discussion about how this effects objects extended by another object with functions assigned in the constructor I'm adding a bit more detail. I might use the term "class" to simplify the discussion, but it is important to note that js does not support classes (that doesn't mean we can't do good OO development) or we would not be discussing this issue.

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

Most javascript libraries call the constructor on the base class and the sub class. (e.g. Prototype.js's Object.extend) This means that methods assigned in the constructor of each will be available on the resulting objects. However, if you are extending objects yourself there can be unexpected consequences.

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

If I take the MessageClass above and extend it:

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

errorMsg = new ErrorMessageClass();

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

Then errorMsg will have a getPrivate and setPrivate method on it, but they may not behave as you would expect. Because those functions were scoped when they were assigned (i.e. at "ErrorMessageClass.prototype = new MessageClass()" not only are the get/setPrivate methods shared, the _private variable gets shared across all instances of ErrorMessageClass as well. This essentially makes _private a static property for ErrorMessageClass. For example:

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 函数和 someoneClickedMe 属性也是如此:

Likewise with the clickHandler function and someoneClickedMe property:

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

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

However, change those function definitions to use this._private:

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

并且 ErrorMessageClass 实例的行为变得更像您所期望的:

and behavior of instances of ErrorMessageClass becomes more of what you would expect:

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

这篇关于通过原型对象或在构造函数中设置方法,区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆