有关从JavaScript中的闭包返回对象常量的详细信息 [英] Details on returning an object literal from a closure in JavaScript

查看:121
本文介绍了有关从JavaScript中的闭包返回对象常量的详细信息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景:我想重写一个库(我没有写),以避免Closure Compiler使用高级选项生成警告。根据此问题 JavaScriptthis关键字和Closure Compiler警告答案是使用闭包重写代码。目的是避免使用关键字 this (生成编译器警告)。

Background: I want to rewrite a library (which I did not write) to avoid having the Closure Compiler generate warnings with the advanced option. Per this question JavaScript "this" keyword and Closure Compiler warnings the answer was to rewrite the code using a closure. The intent is to avoid using the keyword this (which generates the compiler warnings).

数量的函数,我虽然最好的新闭包返回一个对象字面量。我想了解这是如何工作和任何可能的后果。因此,我将以下(无意义)示例作为学习体验(也在这里: jsFiddle ):

As the library has a number of functions, I though it would be best for the new closure to return an object literal. I want to understand how this works and any possible ramifications. I therefore wrote the following (meaningless) example as a learning expercise (also here: jsFiddle):

  var CurrencyObject = function(Amount) {
        var money = Amount;
        return {
              "toCents": function() {
                    money *= 100;
                    return money;
              },
              "toDollars": function() {
                    money /= 100;
                    return money;
              },
              "currentValue": money  // currentValue is always value of Amount
        };
  }; // end currencyObject

  var c1 = CurrencyObject(1.99); // what's the difference if the syntax includes `new`?

  alert('cents = ' + c1.toCents() + '\ncurrent money = ' + c1.currentValue + '\ndollars = ' + c1.toDollars() + '\ncurrent money = ' + c1.currentValue);

  var c2 = CurrencyObject(2.99);

  alert('cents = ' + c2.toCents() + '\ncurrent money = ' + c2.currentValue + '\ndollars = ' + c2.toDollars() + '\ncurrent money = ' + c2.currentValue);

  alert('cents = ' + c1.toCents() + '\ncurrent money = ' + c1.currentValue + '\ndollars = ' + c1.makeDollars() + '\ncurrent money = ' + c1.currentValue);

Q1 :为什么 currentValue 在呼叫 toCents 后更新? (我会猜测,因为 CurrentValue 是一个字面值(?),它在第一次执行CurrencyObject时被初始化,如果是这种情况,返回属性 > currentValue ?)

Q1: Why isn't currentValue updated after the call to toCents? (I'm going to guess that it is because currentValue is a literal(?) that it is initialized when CurrencyObject is first executed. If that's the case, what's the syntax for also returning the property currentValue?)

Q2 :此语法( new var c1 = new CurrencyObject(1.99); 不会以我可以检测的方式更改代码的行为,但我认为有差别。是什么?

Q2: This syntax (with new) var c1 = new CurrencyObject(1.99); does not change the code's behavior in a way that I can detect, yet I assume there is a difference. What is it?

Q3 :当实例化 c2 时,是正在创建的函数的副本, em> c1 和 c2 共享相同的(功能)代码? (如果正在创建函数的副本,我会做哪些更改以避免这种情况?)

Q3: When c2 is instantiated, are copies of the functions being created or will c1 and c2 share the same (function) code? (If copies of the functions are being created, what changes do I make to avoid that?)

TIA

BTW:在有人想知道的情况下,引用对象字面量中的符号,以避免让Closure-Compiler重命名它们。

BTW: In the event someone is wondering, the symbols in the object literal are quoted to avoid having the Closure-Compiler rename them.

推荐答案

更新:

分支您的小提琴 a>,并添加了所有实例实际上共享的几个方法(即:不会为每个实例创建新的函数对象):将金额转换为欧元或英镑的方法。我也省略了 money 变量,因为它根本没有必要。为了避免必须尽可能地使用这个,我还将返回的对象分配给闭包范围内的一个变量,以便所有方法都可以通过而不是依赖 this
然而,共享方法仍然必须使用 this 偶尔,因为它们在较高的范围中声明,并且无法访问 returnObject 变量,不存在于其范围内。提升 returnObject 变量声明是没有解决方案,如果你想知道,因为然后你很快就会发现,你不能创建超过1个实例的货币对象。最后,我已更改构造函数的名称以小写开头。从技术上来说,你的函数不再是一个构造函数,而惯例是它不能以大写字母开头...让我知道,如果我在这里解释了,或任何我建议的更改仍然不清楚你

UPDATE:
I branched your fiddle, and added a couple of methods that all instances will in fact share (ie: no new function objects will be created for each instance): the methods that convert the amount into Euro's or Pounds, for example. I've also omitted the money variable, because it's simply not necessary. To avoid having to use this as much as possible, I've also assigned the returned object to a variable within the closure scope, so that all methods can reference their parent object via that variable name, rather than having to rely on this.
Shared methods, however, will still have to use this occasionally, because they were declared in a "higher" scope, and don't have access to the returnObject variable, simply because it doesn't exist in their scope. Lifting the returnObject variable declaration is no solution in case you were wondering, because then you'll soon find out that you can't create more than 1 instance of the currency object.
Lastly, I've changed the name of the "constructor" to start with a lower case. Technically, your function is not a constructor any longer, and convention is that it therefore can't start with an upper-case letter... Let me know if anything I explained here, or any of my suggested changes are still unclear to you.

currentValue 未更新,因为您更改了 money 变量的值通过: money * = 100; 。此语句乘以 money 并将其分配给同一个变量。由于这是一个原始语言, currentValue 有自己的 这个值,它们没有以任何方式链接。
建议:use return money / 100; 保持 money 的值不变。因为它现在调用 toCents 方法两次与将原始金额乘以10,000相同。要更新/设置每次调用任何你想要的 currentValue ,添加: this.currentValue = money * 100; ,这是一个有点危险,或者给你的闭包访问自己的文字通过使用一个命名的引用(更安全,但有点更冗长):

The currentValue isn't updated because you changed the money variable's value by doing: money *= 100;. This statement multiplies the money value and assigns it to the same variable. Since this is a primitive, currentValue has its own copy of this value, they're not linked in any way.
Suggestions: use return money/100; to keep the value of money constant. As it now stands calling the toCents method twice is the same as multiplying the original amount by 10,000. To update/set the currentValue on each call to whatever you want it to be, add: this.currentValue = money*100;, which is a little dangerous, or giving your closure access to its own literal by using a named reference (which is safer, but a bit more verbose):

var someClosure = function (amount)
{
    var money = amount;//redundant: you can use amount, it's preserved in this scope, too
    var me = {currentValue:amount,
              toCents: function()
              {
                  me.currentValue = money*100;//<-- use me to refer to the object itself
                  return amount/100;
              }
      };
      return me;
}

没有理由使用 code> keyword:这个构造函数创建的对象是一个对象常量,它只有一个原型( Object.prototype ,并且没有显式构造函数名称)。添加 new 会使这个指向函数本身中的一个新对象,但是由于你不使用它,你的函数返回另一个对象,对象从不returend。

There is no reason to use the new keyword: the object that is created by this "constructor" is an object literal, it has only 1 prototype (Object.prototype, and no explicit constructor name). Adding new will make this point to a new object in the function itself, but since you're not using it, and your function returns another object, the object is never returend.

严格地说,一些JS引擎将为每个新实例创建新的函数对象。一些现代对象优化这个,并且实际上将只创建1个函数对象。为了安全起见,你可以把另一个闭包围绕着东西,确保只有一个函数,不管什么引擎运行你的代码:

Strictly speaking: some JS engines will create new function objects for each new instance. Some modern objects optimize this, and will in fact only create 1 function object. To be on the safe side, you can wrap another closure around things, to make sure there is only 1 function, regardless of what engine runs your code:

var someObjectGenerator = (function()
{
    var oneOffFunction = function()
    {
        console.log('this function will only be created once');
    }
    return function(amount)
    {
        return {    foo:oneOffFunction,
                    toCents: function()
                    {
                        return amoutn/100;
                    }
                };
    };
};

当然,在 money 金额变量将无法访问该变量,因此在这种情况下,您必须创建新的函数...但JS对象是非常便宜,所以不要担心它 很多。
同样,大多数引擎都处理得很好。

Of course, functions that are created in a scope above the one that has the money or amount variable won't have access to that variable, so in that case you'll have to create new functions... but JS objects are very cheap, so don't worry about it that much.
Again, most engines deal with this rather well.

这篇关于有关从JavaScript中的闭包返回对象常量的详细信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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