Javascript 对使用实际闭包的质疑

Javascript 对使用实际闭包的质疑,javascript,closures,Javascript,Closures,我试图了解更多关于Javascript中闭包的信息,并经历了以下过程: 根据本文,通过使用此函数: function makeSizer(size) { return function() { document.body.style.fontSize = size + 'px'; }; } var size12 = makeSizer(12); var size14 = makeSizer(14); var size16 = make

我试图了解更多关于Javascript中闭包的信息,并经历了以下过程:

根据本文,通过使用此函数:

function makeSizer(size) {  
    return function() {  
        document.body.style.fontSize = size + 'px';  
    };  
}  

var size12 = makeSizer(12);  
var size14 = makeSizer(14);  
var size16 = makeSizer(16); 
然后,我们可以利用这些语句来增加/减少页面上文本的字体大小:

document.getElementById('size-12').onclick = size12;  
document.getElementById('size-14').onclick = size14; 
document.getElementById('size-16').onclick = size16;
虽然我理解这里的概念——即size12、size14和size16成为允许访问内部函数的闭包,但我还是忍不住觉得这是不必要的。仅仅拥有:

function makeSizer(size) {  
    document.body.style.fontSize = size + 'px';  
}   
,然后用这些调用它

document.getElementById('size-12').onclick = makeSizer(12);  
document.getElementById('size-14').onclick = makeSizer(14); 
document.getElementById('size-16').onclick = makeSizer(16);
有人能告诉我我的想法是否正确吗?或者我只是一个Javascript新手,不了解在这个场景中使用闭包的好处,在这种情况下,如果你能解释这样做的好处,我将非常高兴

提前谢谢各位。

不,你们不能那样做

就好像你写过:

document.getElementById('size-12').onclick = (function(size) {  
    document.body.style.fontSize = size + 'px';  
})(12);
函数立即被调用,样式将立即应用,并且不会注册任何
。onclick
处理程序,因为函数的返回值是
未定义的

该示例的真正意义在于显示您可以从另一个函数返回一个函数,然后可以将该结果分配给事件处理程序


如果未修改
makeSizer()
,则可以按照建议分配处理程序,而不使用中间变量,即:

document.getElementById('size-12').onclick = makeSizer(12);
但是,如果您按照您描述的方式更改
makeSizer()
,则该将不起作用

如果您多次使用同一大小码器,则将“大小码器”存储在变量中的效率也较低。

是的,这些变量(
sizeN
)是不必要的。您可以直接将
makeSizer()
的结果指定为处理程序,这样看起来更好

但是,这些变量的使用不是闭包的概念。本例中的闭包是函数
makeSizer
,它返回一个函数(即使没有参数),该函数仍然可以访问
size
变量

不过,您需要看到

function makeSizer(size) {  
    return function resize() {  
        document.body.style.fontSize = size + 'px';  
    };  
}


执行
makeSizer(5)
不会执行任何操作,它会返回一个函数,在调用时将大小设置为预定义的大小。相反,执行
resize(5)
会直接设置大小。您不能将后一个函数的结果用作事件处理程序。

对于您介绍的示例,当然不需要闭包,但我想这只是为了简化概念的介绍。在某些情况下,闭包是最好的解决方案:考虑如何在javascript中实现“private”属性,或者何时需要封装参数(即回调函数)

我希望下面的例子能有所帮助:


@Joseph:Na,这是闭包的一个非常有效的用法。闭包在这里是非常合理和有效的用法,因为它绑定了提供的参数,尽管同一个函数要与不同的值一起使用。好的,我想我知道你的意思:所以_count是一个私有变量,只能由sequencer函数访问(如
var v0=fnext();
)中所示。您认为使用
var v0=makeSequencer();
,从而跳过fnext是明智的吗?@anthonyteo:这没有意义;您可以将
makeSequencer
函数看作是一个创建并返回新函数(序列器本身)的工厂每次调用它。也许闭包对于像我这样的javascript新手来说还是太高级了?我似乎不明白为什么我们要让一个函数返回一个函数,然后将一个单独的变量设置为这个返回函数,并使用这个单独的变量调用这个返回函数。对我来说似乎是一个可怕的工作量。尽管我确实这样做了a了解本节关于私有方法的基本原理:闭包有时被视为一个复杂的概念,但我认为这只是另一个概念,它可能非常有用。不要放弃小蚱蜢:)嗨@Alnitak,谢谢你的清晰解释。我现在明白你的意思了。有一件事我不明白——为什么每次需要时将“sizer”存储在变量中比调用makeSizer函数更有效?在后一种情况下,您使用的是已定义的函数,而在前一种情况下,您必须声明新变量,然后调用该函数。使用变量对我来说似乎更麻烦,至少是这样。@anthonyteo因为每次调用
makeSizer(n)
实际上是返回一个新的(函数)对象。所以我收集到一个新的函数对象在效率方面比一个新的变量花费更多,对吗?@anthonyteo每个函数都需要创建一个“作用域”,它本身也是一个对象。变量大多只是解析器使用的东西——一旦代码被解析,它们基本上是免费的,但是对象创建有一个运行时惩罚。我并不完全理解你上面所说的一切,但我一定会在以后更熟悉JS的时候再回到你的评论。无论如何,非常感谢你的帮助。干杯。嗨@Bergi,谢谢你的解释。阿尔尼塔克还提到了处理者——遗憾的是,我对处理者的概念相当模糊,所以我不确定你们的意思。特别是,当您真正想要的只是相应地调整文本的大小时,为什么需要注册
onclick
处理程序?您可能需要阅读以下内容。如果要直接调整文本大小(现在是在运行时),请执行该函数。但是如果你想在用户点击一个元素时发生这种情况,你需要让函数在事件发生时执行。啊-我想我明白你的意思了。这就像等待用户在响应之前采取行动。
function resize(size) {  
    document.body.style.fontSize = size + 'px';  
}
var makeSequencer = function() {
    var _count = 0; // not accessible outside this function
    var sequencer = function () {
        return _count++;
    }
    return sequencer;
}

var fnext = makeSequencer();
var v0 = fnext();     // v0 = 0;
var v1 = fnext();     // v1 = 1;
var vz = fnext._count // vz = undefined