我最近进入了闭包和匿名函数,我想知道我的代码是否是正确的方法(它有效!):
newInput.onchange = function(x){
return function(){
PassFileName(x);
}
}(counter);
所以这是一个“保存”当前“计数器”值(1,2,3 ...)的循环。如果我没有返回函数,那么'counter'将始终是'counter'的最后一个值。
我是否正确使用该代码?或者是否有更好的方法来“捕获”当前计数器并将其附加到onchange事件?
谢谢你!答案 0 :(得分:5)
是的,您正确地接近它,但为了最大程度地兼容实现,您需要在函数周围添加括号:
newInput.onchange = (function(x){
// ^--- here
return function(){
PassFileName(x);
}
})(counter);
// ^--- and here
每当你做一个函数表达式并立即调用它时,你需要那些parens,因为否则会有解析歧义。
<强>更新强>:
虽然你的方法很好,但值得指出的是它有点挥霍。 ;-)它在循环的每次迭代中创建两个函数,外部匿名函数和内部匿名函数。这两个功能都存在(除非实现优化,你知道一些引擎不会有)。相反,你可以只有一个循环加上一个工厂函数:
// In the loop
newInput.onchange = makeHandler(x);
// Outside the loop
function makeHandler(x){
return function(){
PassFileName(x);
};
}
有些人可能会认为它更容易阅读(我当然这样做),前提是makeHandler
仍然足够接近您不会失去跟踪的循环。
使用工厂功能还为您提供了不关闭范围内任何 else 的机会,尽管您必须将工厂功能放得更远(例如,在一个包含良好的范围内)。
您可能还会考虑通用curry功能,例如the one provided by Prototype。 未传递调用时参数的通用curry
如下所示:
function curry(f) {
var args = arguments;
return function() {
f.apply(undefined, args);
};
}
但是,让 传递一个运行时参数的通常更有帮助(但更昂贵)。这是一个廉价和肮脏(未优化;优化调用时间开销可以显着减少):
function curry(f) {
var args = Array.prototype.slice.call(arguments, 1);
return function() {
f.apply(undefined,
args.concat(Array.prototype.slice.call(arguments)));
};
}
两种情况下的优势在于,您不会关闭任何可以避免的新内容。
偏离主题:另外,技术上,你依赖于分号插入的恐怖(你{{1}末尾应该有一个分号声明),我一直主张不依赖。但是,在这个例子中,相当安全。 ; - )
答案 1 :(得分:3)
你所做的是相当标准的,并没有任何问题。但是,我更喜欢类似的方法:
(function (x) {
newInput.onchange = function () {
PassFileName(x);
};
})(counter);
对我而言,通过包装整个块(以及缩进)更清楚我正在考虑创建一个新的范围以捕获变量的值。