Kar*_*arl 5 javascript closures google-closure-compiler
背景:我想重写一个库(我没有写过),以避免Closure Compiler使用Advanced选项生成警告。对于这个问题,JavaScript“ this”关键字和Closure Compiler警告,答案是使用闭包重写代码。目的是避免使用关键字this(生成编译器警告)。
由于该库具有许多函数,所以我最好使新闭包返回一个对象文字。我想了解这是如何工作的以及可能产生的后果。因此,我编写了以下(无意义的)示例作为学习技巧(也在此处: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);
Run Code Online (Sandbox Code Playgroud)
问题1:为什么在toCents调用后currentValue没有更新?(我想这是因为currentValue是一个literal(?),它是在第一次执行CurrencyObject时初始化的。如果是这种情况,还返回属性currentValue的语法是什么?)
问题2:此语法(带有new)var c1 = new CurrencyObject(1.99);不会以我可以检测到的方式更改代码的行为,但我认为存在区别。它是什么?
Q3:实例化c2时,正在创建的函数副本还是c1和c2共享相同的(函数)代码?(如果正在创建功能的副本,我应该做哪些更改以避免这种情况?)
TIA
顺便说一句:如果有人想知道,对象文字中的符号会加引号,以避免Closure-Compiler重命名它们。
更新:
我对你的 fiddle 进行了分支,并添加了一些所有实例实际上共享的方法(即:不会为每个实例创建新的函数对象):例如,将金额转换为欧元或英镑的方法。我还省略了该money变量,因为它根本没有必要。为了避免必须尽可能多地使用this,我还将返回的对象分配给闭包范围内的变量,以便所有方法都可以通过该变量名称引用其父对象,而不必依赖于this.
然而,共享方法仍然需要this偶尔使用,因为它们是在“更高”的作用域中声明的,并且无法访问该returnObject变量,仅仅是因为它不存在于它们的作用域中。如果您想知道,取消returnObject变量声明并不是解决方案,因为您很快就会发现无法创建超过 1 个货币对象实例。最后,我将“构造函数”
的名称更改为以小写字母开头。从技术上讲,您的函数不再是构造函数,并且约定是它因此不能以大写字母开头...如果您仍然不清楚我在这里解释的任何内容或我建议的任何更改,请告诉我。
未currentValue更新,因为您money通过执行以下操作更改了变量的值:money *= 100;。该语句将money值相乘并将其分配给同一个变量。由于这是一个原语,currentValue有它自己的该值的副本,因此它们不以任何方式链接。
建议:用于return money/100;保持值money恒定。现在看来,调用该toCents方法两次相当于将原始金额乘以 10,000。要将每次调用更新/设置currentValue为您想要的任何内容,请添加:this.currentValue = money*100;,这有点危险,或者通过使用命名引用让您的闭包访问其自己的文字(这更安全,但更冗长) :
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;
}
Run Code Online (Sandbox Code Playgroud)
没有理由使用关键字:由这个“构造函数”new创建的对象是一个对象文字,它只有 1 个原型(,并且没有显式构造函数名称)。添加将指向函数本身中的一个新对象,但由于您没有使用它,并且您的函数返回另一个对象,因此该对象永远不会返回。Object.prototypenewthis
严格来说:一些JS引擎会为每个新实例创建新的函数对象。一些现代对象对此进行了优化,实际上只会创建 1 个函数对象。为了安全起见,您可以在事物周围包装另一个闭包,以确保只有 1 个函数,无论什么引擎运行您的代码:
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;
}
};
};
};
Run Code Online (Sandbox Code Playgroud)
money当然,在具有or变量的作用域之上创建的函数amount将无法访问该变量,因此在这种情况下,您将不得不创建新函数...但是 JS 对象非常便宜,所以不用太担心。
同样,大多数引擎都能很好地处理这个问题。