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

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

问题描述

您能解释在构造函数和通过原型对象设置方法之间的区别吗?以下代码显示了设置方法的两种方法 - say_hello say_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都正确,



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



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

  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; };
}

EDIT:这会影响由另一个对象扩展的对象与在构造函数中分配的函数我添加了一些更多的细节。我可能使用术语类来简化讨论,但重要的是要注意,js不支持类(这并不意味着我们不能做好的OO开发),或者我们不会讨论这个问题。 / p>

大多数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 a对于ErrorMessageClass的静态属性,例如:

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

与clickHandler函数和someoneClickedMe属性类似:

  errorA.clickHandler(); 
console.log(errorA.someoneClickedMe); //打印'true'
console.log(errorB.someoneClickedMe); //输出'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'


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 and annakata are both correct, but I'll throw in my 2 cents.

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.

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; };
}

EDIT: 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.

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.

If I take the MessageClass above and extend it:

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

errorMsg = new 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'

Likewise with the clickHandler function and someoneClickedMe property:

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

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

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

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天全站免登陆