jjzjj

javascript - 在构造函数*内部*分配原型(prototype)方法——为什么不呢?

coder 2025-01-30 原文

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

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

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

我以前成功使用过第一个结构,但我想确保我不会让自己陷入调试的困境,或者因为糟糕的编码实践而导致其他开发人员的悲伤和恼怒。

最佳答案

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?

是的,存在缺点和意想不到的范围界定问题。

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

  2. 在某些情况下会出现意想不到的范围界定问题。有关明确示例,请参阅我的答案末尾的 Counter 示例。如果您从原型(prototype)方法中引用构造函数的局部变量,那么您的第一个示例会在您的代码中创建一个潜在的严重错误。

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

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

当然,如果有人使用:

Object.create(Filter.prototype) 

如果不运行 Filter 构造函数,那也会产生不同的结果,这可能不太可能,因为可以合理地期望使用 Filter 原型(prototype)的东西应该运行Filter 构造函数以获得预期结果。


从运行时性能的 Angular (对象上调用方法的性能),你最好这样做:

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 “专家”声称不再需要使用原型(prototype)节省的内存(我几天前看了一个关于那个的视频讲座)所以是时候开始直接使用性能更好的方法了对象而不是原型(prototype)。我不知道我自己是否准备好提倡这一点,但这是一个值得思考的有趣观点。


我能想到的第一种方法的最大缺点是它真的非常容易犯严重的编程错误。如果您碰巧认为您可以利用原型(prototype)方法现在可以看到构造函数的局部变量这一事实,那么一旦您拥有多个对象实例,您就会很快搬起石头砸自己的脚。想象一下这种情况:

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 方法形成了一个闭包,并且可以访问作为构造函数局部变量的实例变量,但实际上并不是这样工作的。因为所有实例共享同一个原型(prototype)对象,Counter 对象的每个新实例都会创建一个新的 get 函数实例(它可以访问刚才的构造函数局部变量)创建的实例)并将其分配给原型(prototype),所以现在所有实例都有一个 get 方法来访问最后创建的实例的构造函数的局部变量。这是一场编程灾难,因为这可能从来都不是预期的,并且很容易让人头疼,弄清楚出了什么问题和原因。

关于javascript - 在构造函数*内部*分配原型(prototype)方法——为什么不呢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28255957/

有关javascript - 在构造函数*内部*分配原型(prototype)方法——为什么不呢?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  3. Ruby Koans about_array_assignment - 非平行与平行分配歧视 - 2

    通过ruby​​koans.com,我在about_array_assignment.rb中遇到了这两段代码你怎么知道第一个是非并行赋值,第二个是一个变量的并行赋值?在我看来,除了命名差异之外,代码几乎完全相同。4deftest_non_parallel_assignment5names=["John","Smith"]6assert_equal["John","Smith"],names7end45deftest_parallel_assignment_with_one_variable46first_name,=["John","Smith"]47assert_equal'John

  4. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  5. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  6. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

  7. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  8. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  9. ruby - 当使用::指定模块时,为什么 Ruby 不在更高范围内查找类? - 2

    我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or

  10. ruby - 为什么人们使用 `Module.send(:prepend, …)` ? - 2

    我正在学习如何在我的Ruby代码中使用Module.prepend而不是alias_method_chain,我注意到有些人使用send调用它(example):ActionView::TemplateRenderer.send(:prepend,ActionViewTemplateRendererWithCurrentTemplate)而其他人直接调用它(example):ActionView::TemplateRenderer.prepend(ActionViewTemplateRendererWithCurrentTemplate)而且,虽然我还没有看到任何人使用这种风格,但我从

随机推荐