我正在尽最大努力理解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();

当前回答

解释JavaScript闭包的实际用法

当我们在另一个函数中创建一个函数时,我们是在创建一个闭包。闭包功能强大,因为它们能够读取和操作其外部函数的数据。无论何时调用函数,都会为该调用创建一个新的作用域。在函数内部声明的局部变量属于该作用域,并且只能从该函数访问它们。当函数完成执行时,作用域通常被销毁。

这类函数的一个简单例子是:

function buildName(name) {
    const greeting = "Hello, " + name;
    return greeting;
}

在上面的例子中,函数buildName()声明了一个局部变量greeting并返回它。每次函数调用都会创建一个新的作用域和一个新的局部变量。在函数执行完成后,我们无法再次引用该作用域,因此它被垃圾收集。

但如果我们有一个指向范围的链接呢?

让我们看看下一个函数:

函数buildName(name) { const greeting = "Hello, " + name + " Welcome "; const sayName = function() { console.log(问候); }; 返回sayName; } const sayMyName = buildName("Mandeep"); sayMyName ();//你好,曼迪普

本例中的sayName()函数是一个闭包。sayName()函数有自己的局部作用域(变量welcome),也可以访问外部(封闭)函数的作用域。在本例中,是来自buildName()的greeting变量。

在执行buildName之后,在本例中不会销毁作用域。sayMyName()函数仍然可以访问它,因此它不会被垃圾收集。但是,除了闭包之外,没有其他从外部作用域访问数据的方法。闭包充当全局上下文和外部作用域之间的网关。

其他回答

我们在前端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;

小提琴

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

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

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体验功能。

闭包的另一个常见用途是将方法中的this绑定到特定对象,允许在其他地方调用它(例如作为事件处理程序)。

function bind(obj, method) {
    if (typeof method == 'string') {
        method = obj[method];
    }
    return function () {
        method.apply(obj, arguments);
    }
}
...
document.body.addEventListener('mousemove', bind(watcher, 'follow'), true);

每当鼠标移动事件触发时,都会调用watch .follow(evt)。

闭包也是高阶函数的重要组成部分,通过参数化不同部分,可以将多个相似函数重写为一个高阶函数,这是非常常见的模式。举个抽象的例子,

foo_a = function (...) {A a B}
foo_b = function (...) {A b B}
foo_c = function (...) {A c B}

就变成了

fooer = function (x) {
    return function (...) {A x B}
}

其中A和B不是语法单位,而是源代码字符串(不是字符串字面量)。

具体示例请参见“用函数简化我的javascript”。

我正在尝试学习闭包,我认为我创建的示例是一个实际的用例。您可以运行一个代码片段并在控制台中查看结果。

我们有两个不同的用户,他们拥有不同的数据。它们中的每一个都可以看到实际的状态并进行更新。

function createUserWarningData(user) { const data = { name: user, numberOfWarnings: 0, }; function addWarning() { data.numberOfWarnings = data.numberOfWarnings + 1; } function getUserData() { console.log(data); return data; } return { getUserData: getUserData, addWarning: addWarning, }; } const user1 = createUserWarningData("Thomas"); const user2 = createUserWarningData("Alex"); //USER 1 user1.getUserData(); // Returning data user object user1.addWarning(); // Add one warning to specific user user1.getUserData(); // Returning data user object //USER2 user2.getUserData(); // Returning data user object user2.addWarning(); // Add one warning to specific user user2.addWarning(); // Add one warning to specific user user2.getUserData(); // Returning data user object