我正在尽最大努力理解JavaScript闭包。

通过返回一个内部函数,它可以访问直接父函数中定义的任何变量。

这对我有什么用?也许我还没完全搞清楚。我在网上看到的大多数示例都没有提供任何真实的代码,只是一些模糊的示例。

有人能告诉我一个闭包的真实用法吗?

比如这个吗?

var warnUser = function (msg) {
    var calledCount = 0;
    return function() {
       calledCount++;
       alert(msg + '\nYou have been warned ' + calledCount + ' times.');
    };
};

var warnForTamper = warnUser('You can not tamper with our HTML.');
warnForTamper();
warnForTamper();

当前回答

参考:闭包的实际使用

在实践中,闭包可以创建优雅的设计,允许自定义各种计算、延迟调用、回调、创建封装的作用域等。

一个例子是数组的sort方法,它接受sort条件函数作为参数:

[1, 2, 3].sort(function (a, b) {
    ... // Sort conditions
});

将函数函数映射为数组的map方法,它根据函数参数的条件映射一个新数组:

[1, 2, 3].map(function (element) {
    return element * 2;
}); // [2, 4, 6]

通常,通过使用函数参数定义几乎无限的搜索条件来实现搜索函数是很方便的:

someCollection.find(function (element) {
    return element.someProperty == 'searchCondition';
});

此外,我们可能会注意到应用函数,例如,forEach方法将函数应用于元素数组:

[1, 2, 3].forEach(function (element) {
    if (element % 2 != 0) {
        alert(element);
    }
}); // 1, 3

函数应用于实参(在apply中应用于实参列表,在call中应用于定位实参):

(function () {
    alert([].join.call(arguments, ';')); // 1;2;3
}).apply(this, [1, 2, 3]);

延迟调用:

var a = 10;
setTimeout(function () {
    alert(a); // 10, after one second
}, 1000);

回调函数:

var x = 10;
// Only for example
xmlHttpRequestObject.onreadystatechange = function () {
    // Callback, which will be called deferral ,
    // when data will be ready;
    // variable "x" here is available,
    // regardless that context in which,
    // it was created already finished
    alert(x); // 10
};

创建一个用于隐藏辅助对象的封装作用域:

var foo = {};
(function (object) {
    var x = 10;
    object.getX = function _getX() {
        return x;
    };
})(foo);

alert(foo.getX()); // Get closured "x" – 10

其他回答

如果你熟悉面向对象意义上的实例化类的概念(即创建该类的对象),那么你就接近理解闭包了。

这样想:当你实例化两个Person对象时,你知道类成员变量“Name”在实例之间是不共享的;每个对象都有自己的“副本”。类似地,当你创建一个闭包时,自由变量(上面例子中的'calledCount')被绑定到函数的'实例'。

我认为你的概念上的突破有点受到这样一个事实的阻碍,即由warnUser函数(另外:这是一个高阶函数)返回的每个函数/闭包都绑定'calledCount'与相同的初始值(0),而通常在创建闭包时,将不同的初始化式传递到高阶函数中更有用,就像将不同的值传递给类的构造函数一样。

所以,假设当'calledCount'达到某个值时,你想结束用户的会话;您可能需要不同的值,这取决于请求是来自本地网络还是来自大的坏Internet(是的,这是一个人为的例子)。要实现这一点,您可以将不同的calledCount初始值传递给warnUser(即-3或0?)

文献的部分问题是用来描述它们的命名法(“词汇范围”,“自由变量”)。不要让它欺骗你,闭包比看起来要简单得多…初步证据;-)

JavaScript闭包可用于在应用程序中实现节流和反弹功能。

节流

节流限制了一个函数在一段时间内可以被调用的最大次数。就像“最多每100毫秒执行一次这个函数。”

代码:

const throttle = (func, limit) => {
  let isThrottling
  return function() {
    const args = arguments
    const context = this
    if (!isThrottling) {
      func.apply(context, args)
      isThrottling = true
      setTimeout(() => isThrottling = false, limit)
    }
  }
}

消除抖动

deboundation限制了函数在经过一段时间后才会被再次调用。就像“仅在100毫秒后未被调用时才执行该函数。”

代码:

const debounce = (func, delay) => {
  let debouncing
  return function() {
    const context = this
    const args = arguments
    clearTimeout(debouncing)
    debouncing = setTimeout(() => func.apply(context, args), delay)
  }
}

正如你所看到的,闭包帮助实现了两个漂亮的特性,每个web应用程序都应该提供流畅的UI体验功能。

我曾经写过一篇关于如何使用闭包来简化事件处理代码的文章。它比较ASP。NET事件处理到客户端jQuery。

http://www.hackification.com/2009/02/20/closures-simplify-event-handling-code/

我们在前端JavaScript中编写的大部分代码都是基于事件的——我们定义了一些行为,然后将其附加到由用户触发的事件(例如单击或按键)。我们的代码通常是作为一个回调附加的:在响应事件时执行的单个函数。 Size12、size14和size16现在是将正文文本分别调整为12、14和16像素的函数。我们可以将它们附加到按钮(在本例中是链接),如下所示:

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;

小提琴

闭包是一种创建生成器的有用方法,它是一个按需递增的序列:

var foobar = function(i){var count = count || i; return function(){return ++count;}} 巴兹 = 福巴(1); console.log(“First Call: ” + baz());2 console.log(“第二次调用: ” + baz());3

区别总结如下:

Anonymous functions                                    Defined functions

Cannot be used as a method                             Can be used as a method of an object

Exists only in the scope in which it is defined        Exists within the object it is defined in

Can only be called in the scope in which it is defined Can be called at any point in the code

Can be reassigned a new value or deleted               Cannot be deleted or changed

参考文献

AS3基础知识:功能