1

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

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

这个想法是从单击事件中调用具有大小的 makeSizer 并更改字体大小。但是,如果您删除无名函数并执行操作:

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

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

(如果不清楚我在说什么,请单击示例上方的链接,他们有小提琴)

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

4

6 回答 6

2

没有回调的情况是,随着脚本加载,大小被快速连续设置为 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;
于 2013-10-02T09:50:58.273 回答
1

您分配的值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'.

于 2013-10-02T09:58:18.123 回答
1

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

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

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

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

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

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

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

于 2013-10-02T10:00:13.760 回答
0

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

于 2013-10-02T09:55:03.240 回答
0

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

var size12 = makeSizer(12);

您正在调用makeSizer(12)哪个执行函数并更改大小。

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

var size12 = makeSizer(12);

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

于 2013-10-02T09:55:25.997 回答
0

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

在代码示例中,函数存储在变量中,并被分配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);
};
于 2013-10-02T09:59:20.320 回答