我正在尽最大努力理解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模块模式使用闭包。它的良好模式允许你拥有类似“公共”和“私有”变量的东西。

var myNamespace = (function () {

  var myPrivateVar, myPrivateMethod;

  // A private counter variable
  myPrivateVar = 0;

  // A private function which logs any arguments
  myPrivateMethod = function(foo) {
      console.log(foo);
  };

  return {

    // A public variable
    myPublicVar: "foo",

    // A public function utilizing privates
    myPublicFunction: function(bar) {

      // Increment our private counter
      myPrivateVar++;

      // Call our private method using bar
      myPrivateMethod(bar);
    }
  };

})();

其他回答

在这里,我有一句想说好几遍的问候语。如果我创建一个闭包,我可以简单地调用该函数来记录问候语。如果我不创建闭包,我必须每次都传递我的名字。

没有闭包(https://jsfiddle.net/lukeschlangen/pw61qrow/3/):

function greeting(firstName, lastName) {
  var message = "Hello " + firstName + " " + lastName + "!";
  console.log(message);
}

greeting("Billy", "Bob");
greeting("Billy", "Bob");
greeting("Billy", "Bob");
greeting("Luke", "Schlangen");
greeting("Luke", "Schlangen");
greeting("Luke", "Schlangen");

使用闭包(https://jsfiddle.net/lukeschlangen/Lb5cfve9/3/):

function greeting(firstName, lastName) {
  var message = "Hello " + firstName + " " + lastName + "!";

  return function() {
    console.log(message);
  }
}

var greetingBilly = greeting("Billy", "Bob");
var greetingLuke = greeting("Luke", "Schlangen");

greetingBilly();
greetingBilly();
greetingBilly();
greetingLuke();
greetingLuke();
greetingLuke();

特别是在JavaScript(或任何ECMAScript)语言中,闭包在隐藏功能实现的同时仍然显示接口方面非常有用。

例如,假设您正在编写一个日期实用工具方法类,您希望允许用户通过索引查找工作日名称,但不希望他们能够修改您在底层使用的名称数组。

var dateUtil = {
  weekdayShort: (function() {
    var days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
    return function(x) {
      if ((x != parseInt(x)) || (x < 1) || (x > 7)) {
        throw new Error("invalid weekday number");
      }
      return days[x - 1];
    };
  }())
};

注意,days数组可以简单地存储为dateUtil对象的属性,但是脚本用户可以看到它,他们甚至可以根据需要更改它,甚至不需要您的源代码。但是,由于它被返回日期查找函数的匿名函数所包围,因此只能由查找函数访问,因此现在它是防篡改的。

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

在Mozilla开发者网络上有一个关于实用闭包的章节。

在给定的示例中,所包含的变量'counter'的值是受保护的,只能使用给定的函数(自增,自减)来更改。因为它在闭包中,

var MyCounter =函数(){ Var计数器= 0; 返回{ 增量:函数(){返回计数器+= 1;}, 递减:函数(){返回计数器= 1;}, 获取:函数(){返回计数器;} }; }; var x = MyCounter(); / /或 var y = MyCounter(); 警报(x.get ());/ / 0 警报(x.increment ());/ / 1 警报(x.increment ());/ / 2 警报(y.increment ());/ / 1 警报(x.get ());// x仍然是2