【问题标题】:Why does changing font size with an event through javascript require closures?为什么通过 javascript 通过事件更改字体大小需要闭包?
【发布时间】:2013-10-08 16:02:55
【问题描述】:

我一直在阅读关于闭包的 mozdev 文章,它有 this 小提琴示例:

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

这个想法是从点击事件中调用具有大小的 makeSizer 并更改字体大小。但如果你去掉无名函数,只做this

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

可点击的链接不再有任何效果,字体大小直接变为最大,就好像点击了 size16 链接并且链接不再有点击事件一样。添加 return 不会改变行为。

(如果不清楚我在说什么,请单击示例上方的链接,它们有问题)

我的问题是,为什么这需要闭包/回调?一个简单的陈述不应该起作用吗?如果是关于调用函数,为什么在脚本加载后它不起作用?我明白为什么它会默认为最后一个大小,因为函数调用现在直接改变大小(最后调用 size16),而不是等待调用,但是,为什么它在页面加载后不起作用?

【问题讨论】:

  • 你的两个小提琴链接都指向同一个地方
  • 哎呀抱歉,现在修复它 - 编辑:修复

标签: javascript html css dom closures


【解决方案1】:

由于您在单击事件上切换字体大小,因此您需要分配一个函数以在执行单击事件时充当事件处理程序。

在代码示例中,函数存储在变量中,并被分配了makeSizer函数的返回值。

var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);

这需要makeSizer 保留提供的参数的值,以便在实际触发事件时可以引用它。闭包是一种用于在调用内部函数时保留外部函数范围的机制。在这种情况下,内部函数存储在您已声明的变量中,这些变量被称为每个锚标记的onclick。这些闭包包含在声明函数时提供的 size 参数,这要归功于闭包。

老实说,我认为这只是一个糟糕的例子。如果我通过 Javascript 设置字体大小,我会简单地使用匿名函数:

document.getElementById("something").onclick = function(){
   document.body.style.fontSize = '16px';
};

或者用函数:

document.getElementById("something").onclick = function(){
   makeSizer(12);
};

【讨论】:

    【解决方案2】:

    因为onclick 事件需要一个函数。所以当你只返回document.body.style.fontSize = size + 'px'; 时,它不会被执行。

    【讨论】:

    • 还是错了。返回document.body.style.fontSize = size + 'px' 仍然会将值分配给fontSize,因此它具有效果/被执行。看看其他可以清楚地解释问题的答案。
    【解决方案3】:

    回答您的问题:更改字体大小不需要闭包。

    现在来看看为什么删除内部函数不起作用:

    makeSizer 不是事件处理程序。它是一个创建函数并返回它们的函数。这些函数是事件处理程序。让我们分解一下:

    var size12 = makeSizer(12);
    document.getElementById("size-12").onclick = size12;
    

    第一行以12为参数执行函数makeSizer。它创建了另一个无名函数,将 body 的 font-size 设置为 12 并返回它。这意味着,变量size12 现在包含由makeSizer 创建的函数。 size12 拥有函数 makeSizer 本身。

    在第二行中,您将size12 分配给可点击元素的onclick-Event。因此,该事件的事件处理程序现在是将 font-size 设置为 12 的函数。它执行函数 makeSizer!

    如果您更改函数makeSizer 使得不再有内部函数,它不会返回任何内容,因此变量size12 是“空的”。然后,当您分配size12 onclick-Event 时,您将“nothing”分配给 onclick-Event。这就是为什么什么都没发生的原因。

    【讨论】:

    • 非常感谢 - 这与 bhb 一起为我澄清了这一点。我没有使用基于事件的语言的经验,所以它对我来说看起来很奇怪,但我现在明白了,不是闭包起作用,而是将实际函数分配给事件,而在没有返回函数的情况下,事件处理程序实际上是空的。
    • @IvyLynx 奇怪的是,一个完全错误的答案 (bhb) 如何帮助您理解。另外,你的遗言让我明白你可能有一个稍微错误的想法。如果您了解此代码可以完美运行,那么您的想法是正确的:var changeTo12Px = function() { document.body.style.fontSize = '12px' }; document.getElementById('size-12').onclick = changeTo12Px;
    • 好吧,他说事件处理程序需要一个函数——这确实是我脑子里想的。该示例之所以有效,是因为您将一个函数分配给一个变量,并将该变量分配给事件,从而使其成为事件处理程序。本质上,它需要一个函数对象。不起作用的示例没有返回函数,因此出现了问题。我想我做得很好:P
    【解决方案4】:

    您分配给onclick 的值必须是一个函数,该函数将被浏览器以点击事件作为参数调用。 您希望使用 size 参数调用您的函数。那是行不通的。

    解决方案是找到一种方法将大小绑定到传递给 onclick 的函数中,并为此使用闭包。

    如果您仔细查看 mozdev 代码,您会发现作为 onclick 处理程序,它们分配了一个不需要任何参数的函数:

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

    该函数确实使用了size 变量,但它没有在其范围内定义。相反,他们在定义了 size 变量的函数上创建了一个闭包。他们将您希望提供的参数传递给此闭包:

    function makeSizer(size) {
      // size is defined here, because it is a parameter
      return function() {
        // same size is here
        document.body.style.fontSize = size + 'px';
      };
    }
    

    makeSizer('12px')的返回值就是上面那个改变fontSize的函数,不带参数,size变量绑定到'12px'

    【讨论】:

      【解决方案5】:

      在非工作示例中,只要定义变量

      var size12 = makeSizer(12);
      

      您正在调用makeSizer(12),它会执行函数并更改大小。

      相比之下,在工作示例中,当您定义变量时

      var size12 = makeSizer(12);
      

      您正在使用参数 12 创建一个函数(在这种情况下,这就是 makeSixer() 返回的内容),但是由于您只是返回了该函数,因此您没有执行它。

      【讨论】:

        【解决方案6】:

        没有回调的情况是,随着脚本加载,大小被快速连续设置为 12,然后是 14,然后是 16。

        需要回调,因为您正在定义点击链接时会发生什么。

        要理解带有makeSizer的版本,首先要理解下面的版本,它应该做同样的事情:

        var setSize12 = function() {  document.body.style.fontSize = '12px'; };
        var setSize14 = function() {  document.body.style.fontSize = '14px'; };
        var setSize16 = function() {  document.body.style.fontSize = '16px'; };
        
        document.getElementById('size-12').onclick = setSize12;
        document.getElementById('size-14').onclick = setSize14;
        document.getElementById('size-16').onclick = setSize16;
        

        【讨论】:

        • 这似乎很明显,因为您将变量链接到函数文本,就像您给它们命名一样。但是为什么这个:function makeSizer(size) { return document.body.style.fontSize = size + 'px'; }var size12 = makeSizer(12); 不能正常工作呢?是因为 makeSizer 已经有了名字吗?编辑 - 当然,我只是在 页面加载并且 size12 链接到用户事件之后询问。
        • @IvyLynx var size12 = makeSizer(12)12px 分配给...fontSize 并将12px 返回给size12 变量。你想要的 size12 变量是一个函数,当点击某个元素时浏览器可以调用它。
        • 是的,现在很明显了——我想我更多是根据 C 指针而不是评估来考虑代码,这让我很困惑。
        猜你喜欢
        • 2011-07-31
        • 2017-10-25
        • 2012-07-06
        • 1970-01-01
        • 2017-11-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-22
        相关资源
        最近更新 更多