有关在JavaScript中从闭包返回对象文字的详细信息

有关在JavaScript中从闭包返回对象文字的详细信息,javascript,closures,google-closure-compiler,Javascript,Closures,Google Closure Compiler,背景:我想重写一个库(我没有编写),以避免闭包编译器使用高级选项生成警告。根据这个问题,答案是使用闭包重写代码。其目的是避免使用关键字this(它会生成编译器警告) 由于库有许多函数,我认为新闭包最好返回一个对象文本。我想了解这是如何工作的以及任何可能的后果。因此,我写了以下(毫无意义的)示例作为学习体验(也在这里:): Q1:为什么调用TOCENT后currentValue没有更新?(我猜是因为currentValue是一个文本(?),它在第一次执行CurrencyObject时被初始化。如果

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

由于库有许多函数,我认为新闭包最好返回一个对象文本。我想了解这是如何工作的以及任何可能的后果。因此,我写了以下(毫无意义的)示例作为学习体验(也在这里:):

Q1:为什么调用TOCENT后currentValue没有更新?(我猜是因为currentValue是一个文本(?),它在第一次执行CurrencyObject时被初始化。如果是这样,那么返回属性currentValue的语法是什么?)

Q2:此语法(带有
new
var c1=new CurrencyObject(1.99)
不会以我可以检测到的方式更改代码的行为,但我假设存在差异。这是什么

Q3:c2实例化时,是创建函数的副本,还是c1和c2共享相同的(函数)代码?(如果正在创建函数的副本,我应该做哪些更改来避免这种情况?)

短暂性脑缺血发作


顺便说一句:如果有人想知道,会引用对象文本中的符号,以避免闭包编译器重命名它们。

Q1:您创建了两个变量,其中包含
数量的独立副本。一个是在闭包中捕获的
money
变量中。另一个副本位于返回对象的
currentValue
属性中。这些是彼此没有联系的独立变量,除了用
money
变量的值初始化
currentValue
的初始值之外

要解决这个问题,您必须只在一个地方存储您的
currentValue
,并在那里引用它。您只能在闭包中使用
money
局部变量,但这需要将
currentValue
属性更改为getter函数(检索
money
值),而不是直接数据属性

或者,您可以去掉
money
闭包变量,只使用
currentValue
属性。这将要求您使用
this
toCents
toDollars
方法中获取该属性。在我看来,更干净的方法是后者(使用
this
引用对象自身的属性)。我不知道为什么Close不想让你这么做

Q2:当您从构造函数显式返回对象时,构造函数是作为函数直接调用还是使用
new
操作符调用就不再重要了。正如您所观察到的,两者都会产生相同的结果


Q3:由于您的函数是匿名的,因此每个新的实例化将创建一个新的匿名函数对象。效率的高低取决于javascript实现。通过将函数声明为本地命名函数并引用该名称,可以使函数只有一个。然后,您可以保证没有创建新函数。

更新:
I,并添加了两个所有实例实际上都将共享的方法(即:不会为每个实例创建新的函数对象):例如,将金额转换为欧元或英镑的方法。我还省略了
money
变量,因为它根本不是必需的。为了避免尽可能多地使用
this
,我还将返回的对象分配给闭包范围内的一个变量,以便所有方法都可以通过该变量名引用其父对象,而不必依赖
this

共享方法,仍然需要偶尔使用
this
,因为它们被声明在“更高”的范围内,并且不能访问
returnObject
变量,因为它不在它们的范围内。如果您想知道,取消
returnObject
变量声明并不是解决方案,因为您很快就会发现不能创建超过1个currency对象实例。
最后,我更改了“构造函数”的名称,以小写开头。从技术上讲,您的函数不再是构造函数,惯例是它不能以大写字母开头。。。如果您对我在这里解释的任何内容或我建议的任何更改仍不清楚,请告诉我

currentValue
未更新,因为您通过执行以下操作更改了
money
变量的值:
money*=100。此语句将
money
值相乘,并将其分配给同一个变量。由于这是一个原语,
currentValue
有它自己的此值副本,因此它们没有任何链接。
建议:使用
return money/100
使
货币的价值保持不变。现在,两次调用
toCents
方法等于将原始金额乘以10000。要更新/设置每次调用的
currentValue
,请添加:
this.currentValue=money*100,这有点危险,或者通过使用命名引用(更安全,但更详细)让闭包访问自己的文本:

当然,在具有
money
amount
变量的范围之上创建的函数将无法访问该变量,因此在这种情况下,您必须创建新函数
  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);
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;
}
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;
                    }
                };
    };
};