在构造函数中*内部*分配原型方法 - 为什么不呢? [英] Assigning prototype methods *inside* the constructor function - why not?

查看:19
本文介绍了在构造函数中*内部*分配原型方法 - 为什么不呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在风格上,我更喜欢这种结构:

Stylistically, I prefer this structure:

var Filter = function( category, value ){
  this.category = category;
  this.value = value;

  // product is a JSON object
  Filter.prototype.checkProduct = function( product ){
    // run some checks
    return is_match;
  }

};

对于这个结构:

var Filter = function( category, value ){
  this.category = category;
  this.value = value;
};// var Filter = function(){...}

Filter.prototype.checkProduct = function( product ){
  // run some checks
  return is_match;
}

在功能上,以这种方式构建我的代码有什么缺点吗?将原型方法添加到构造函数体内的原型对象中(即在构造函数的表达式语句关闭之前)会导致意外的作用域问题吗?

Functionally, are there any drawbacks to structuring my code this way? Will adding a prototypical method to a prototype object inside the constructor function's body (i.e. before the constructor function's expression statement closes) cause unexpected scoping issues?

我之前成功地使用了第一个结构,但我想确保我不会让自己为调试头疼,或者由于糟糕的编码实践而导致其他开发人员悲伤和恶化.

I've used the first structure before with success, but I want to make sure I'm not setting myself for a debugging headache, or causing a fellow developer grief and aggravation due to bad coding practices.

推荐答案

在功能上,以这种方式构建我的代码有什么缺点吗?将原型方法添加到原型对象内部构造函数的主体(即在构造函数之前表达式语句关闭)导致意外的范围问题?

Functionally, are there any drawbacks to structuring my code this way? Will adding a prototypical method to a prototype object inside the constructor function's body (i.e. before the constructor function's expression statement closes) cause unexpected scoping issues?

是的,存在缺点和意外的范围界定问题.

Yes, there are drawbacks and unexpected scoping issues.

  1. 一遍又一遍地将原型分配给本地定义的函数,每次都重复该分配并创建一个新的函数对象.较早的分配将被垃圾收集,因为它们不再被引用,但与第二个代码块相比,在构造函数的运行时执行和垃圾收集方面都是不必要的工作.

  1. Assigning the prototype over and over to a locally defined function, both repeats that assignment and creates a new function object each time. The earlier assignments will be garbage collected since they are no longer referenced, but it's unnecessary work in both runtime execution of the constructor and in terms of garbage collection compared to the second code block.

在某些情况下会出现意外的范围界定问题.有关明确示例,请参阅我回答末尾的 Counter 示例.如果您从原型方法中引用构造函数的局部变量,那么您的第一个示例会在您的代码中创建一个潜在的令人讨厌的错误.

There are unexpected scoping issues in some circumstances. See the Counter example at the end of my answer for an explicit example. If you refer to a local variable of the constructor from the prototype method, then your first example creates a potentially nasty bug in your code.

还有一些其他(更小的)差异.您的第一个方案禁止在构造函数之外使用原型,如下所示:

There are some other (more minor) differences. Your first scheme prohibits the use of the prototype outside the constructor as in:

Filter.prototype.checkProduct.apply(someFilterLikeObject, ...)

当然,如果有人使用过:

And, of course, if someone used:

Object.create(Filter.prototype) 

如果不运行 Filter 构造函数,也会产生不同的结果,这可能不太可能,因为期望使用 Filter 原型的东西应该运行是合理的Filter 构造函数以达到预期的结果.

without running the Filter constructor, that would also create a different result which is probably not as likely since it's reasonable to expect that something that uses the Filter prototype should run the Filter constructor in order to achieve expected results.

从运行时性能的角度(在对象上调用方法的性能),您最好这样做:

From a run-time performance point of view (performance of calling methods on the object), you would be better off with this:

var Filter = function( category, value ){
  this.category = category;
  this.value = value;

  // product is a JSON object
  this.checkProduct = function( product ){
    // run some checks
    return is_match;
  }

};

有一些 Javascript专家"声称不再需要使用原型节省的内存(我几天前看过一个关于这个的视频讲座)所以是时候开始直接使用方法的更好性能了对象而不是原型.我不知道我是否准备好自己倡导这一点,但这是一个有趣的思考点.

There are some Javascript "experts" who claim that the memory savings of using the prototype is no longer needed (I watched a video lecture about that a few days ago) so it's time to start using the better performance of methods directly on the object rather than the prototype. I don't know if I'm ready to advocate that myself yet, but it was an interesting point to think about.

我能想到的第一种方法的最大缺点是它真的非常容易犯下令人讨厌的编程错误.如果您碰巧认为您可以利用原型方法现在可以看到构造函数的局部变量这一事实,那么一旦您拥有多个对象的实例,您就会迅速地射中自己的脚.想象一下这种情况:

The biggest disadvantage of your first method I can think of is that it's really, really easy to make a nasty programming mistake. If you happen to think you can take advantage of the fact that the prototype method can now see local variables of the constructor, you will quickly shoot yourself in the foot as soon as you have more than one instance of your object. Imagine this circumstance:

var Counter = function(initialValue){
  var value = initialValue;

  // product is a JSON object
  Counter.prototype.get = function() {
      return value++;
  }

};

var c1 = new Counter(0);
var c2 = new Counter(10);
console.log(c1.get());    // outputs 10, should output 0

问题演示:http://jsfiddle.net/jfriend00/c7natr3d/

这是因为,虽然看起来 get 方法形成了一个闭包并且可以访问作为构造函数的局部变量的实例变量,但它在实践中并不是这样工作的.因为所有实例共享同一个原型对象,Counter 对象的每个新实例都会创建一个 get 函数的新实例(它可以访问刚刚created instance) 并将其分配给原型,因此现在所有实例都有一个 get 方法,该方法访问最后创建的实例的构造函数的局部变量.这是一场编程灾难,因为这可能从来都不是预期的,而且很容易让人头疼地找出哪里出了问题以及为什么.

This is because, while it looks like the get method forms a closure and has access to the instance variables that are local variables of the constructor, it doesn't work that way in practice. Because all instances share the same prototype object, each new instance of the Counter object creates a new instance of the get function (which has access to the constructor local variables of the just created instance) and assigns it to the prototype, so now all instances have a get method that accesses the local variables of the constructor of the last instance created. It's a programming disaster as this is likely never what was intended and could easily be a head scratcher to figure out what went wrong and why.

这篇关于在构造函数中*内部*分配原型方法 - 为什么不呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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