这是闭包的一个很好的例子吗?

is this a good example of a closure?

本文关键字:很好 一个 闭包      更新时间:2023-09-26

我在MDN上看到了一个例子,不明白为什么这是一件好事(TM)。

function makeSizer(size) {  
      return function() {  
        document.body.style.fontSize = size + 'px';  
      };  
    }  
    var size12 = makeSizer(12);  
    var size14 = makeSizer(14);  
    var size16 = makeSizer(16);  

为什么上面比下面更好?

function makeSizer(size) {  
        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;  
<a href="#" id="size-12">12</a>  
<a href="#" id="size-14">14</a>  
<a href="#" id="size-16">16</a>  

在这种情况下size是封闭的变量。调用 makeSizer(12) 将返回一个"记住"12 的函数引用。此函数引用分配给元素上的单击处理程序(请参阅 MDN 示例中的其余代码)。它说:如果你点击我,调用(执行)size12。因此,单击时,正文的字体大小变为"12px",因为执行从makeSizer(12)返回的函数引用(包含的值为 12)。

如果您使用该功能,您将立即调整字体大小。

function makeSizer(size) {  
        document.body.style.fontSize = size + 'px';  
}
var size12 = makeSizer(12);  
var size14 = makeSizer(14);  
var size16 = makeSizer(16); //=> now the font-size of the body is '16px'

想想当你这样做时,在这种情况下会发生什么:

document.getElementById('size-12').onclick = size12; 

如果你点击#size-12会发生什么吗?

您链接到的 MDN 页面链接到一个 jsfiddle 示例。试试吧!

是我很乐意留给社区中更虔诚的部分的事情。我会说这个关闭是有用的,甚至可能很方便。

它们都不是更好的,但它们的行为不同。

在调用返回的函数之前,第一个不会实际大小,如下所示:

size12();

第二个示例首先声明一个函数,然后调用它 3 次。您立即将大小设置为 12px,然后是 14px,最后是 16px。

你对"好"的标准是什么?

在第一个示例中,您将创建一些函数,然后必须调用这些函数才能完成工作。大小被固定在封闭中,很难看到任何好处。您可能希望执行以下操作:

function makeSizer(size) {
    return function() {
        document.body.style.fontSize = size + 'px';
    };
}
var setSmall = makeSizer(8);
var setMedium = makeSizer(10);
var setLarge = makeSizer(14);

或类似,所以现在您只需调用:

setSmall();

第二种情况下的函数应该称为 setSize 之类的函数。

闭包的另一个用途是:

var setSize = (function() {
  var sizes = {small: 8, medium: 10, large: 14};
  return function(size) {
    if (sizes.hasOwnProperty(size)) {
      document.body.style.fontSize = sizes[size] + 'px';
    }
  }
}());
setSize('small');

它们是"好"、"坏"还是其他什么,取决于您对它们进行分类的标准。

在第一个示例中,makeSizer返回一个函数。在第二个示例中,它不返回任何内容,并且具有误导性名称。两者完全不同。

第一个例子中的推理是makeSizer是一个函数工厂;它产生"sizer"函数。 size12size14size16是特殊的"大小"函数,由makeSizer产生。如果稍后调用其中一个,它将设置字体大小。

在第二个示例中,首先将字体大小设置为 12,然后设置为 14,然后设置为 16,并在每个阶段将不感兴趣的返回值保存到变量中。

实际上,您那里没有闭包的例子。

维基百科告诉我们,闭包的定义是"函数以及该函数的非局部变量的引用环境"。

更简单地说,它是一个"包围"周围范围的变量的函数。

一个很好的例子是这样的:

public Func<int> ClosureExample()
{
    int a = 1,
        b = 2;
    Func<int> closeIt = () => a + b;
    return closeIt;
}

让我们真正看看这其中发生了什么。 我们声明两个整数,然后使用 lambda 表达式/闭包/匿名方法(都是分配给第一类函数泛型的定义的有效名称)返回将用于执行此计算的第一类函数,使用封闭的变量,在其他地方。

你可以说closeIt包含整数a和b;这些变量不属于闭包,但它们被它使用。

相关文章: