有关在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;
}
};
};
};