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

当前回答

假设,你想统计用户在网页上点击按钮的次数。

为此,您将在按钮的onclick事件上触发一个函数来更新变量的计数

<button onclick="updateClickCount()">click me</button>

现在有很多方法,比如:

你可以使用一个全局变量和一个函数来增加计数器: Var计数器= 0; 函数updatecickcount () { + +计数器; //用counter做一些事情 } 但是,问题在于页面上的任何脚本都可以更改计数器,而不需要调用updatecickcount()。


现在,你可能在考虑在函数内部声明变量: 函数updatecickcount () { Var计数器= 0; + +计数器; //用counter做一些事情 } 但是,嘿!每次调用updateClickCount()函数时,计数器再次被设置为1。


Thinking about nested functions? Nested functions have access to the scope "above" them. In this example, the inner function updateClickCount() has access to the counter variable in the parent function countWrapper(): function countWrapper() { var counter = 0; function updateClickCount() { ++counter; // Do something with counter } updateClickCount(); return counter; } This could have solved the counter dilemma, if you could reach the updateClickCount() function from the outside and you also need to find a way to execute counter = 0 only once not everytime.


Closure to the rescue! (self-invoking function): var updateClickCount = (function(){ var counter = 0; return function(){ ++counter; // Do something with counter } })(); The self-invoking function only runs once. It sets the counter to zero (0), and returns a function expression. This way updateClickCount becomes a function. The "wonderful" part is that it can access the counter in the parent scope. This is called a JavaScript closure. It makes it possible for a function to have "private" variables. The counter is protected by the scope of the anonymous function, and can only be changed using the updateClickCount() function!

一个关于闭包的更生动的例子

< >脚本 var updatecickcount =(函数(){ Var计数器= 0; 返回函数(){ + +计数器; . getelementbyid(“spnCount”)。innerHTML =计数器; } })(); > < /脚本 < html > <按钮onclick = " updateClickCount ()“>点击我> < /按钮 <div>你点击了 <span id="spnCount"> 0 </span> times! < / div > < / html >


参考:JavaScript闭包

其他回答

闭包的使用:

闭包是JavaScript最强大的特性之一。JavaScript允许函数嵌套,并授予内部函数对外部函数中定义的所有变量和函数的完全访问权(以及外部函数可以访问的所有其他变量和函数)。但是,外部函数不能访问内部函数内部定义的变量和函数。

这为内部函数的变量提供了一种安全性。此外,由于内部函数可以访问外部函数的作用域,如果内部函数能够在外部函数的生命周期之后继续存在,那么外部函数中定义的变量和函数将比外部函数本身的生命周期更长。当内部函数以某种方式对外部函数之外的任何作用域可用时,就会创建闭包。

例子:

<script>
var createPet = function(name) {
  var sex;
  
  return {
    setName: function(newName) {
      name = newName;
    },
    
    getName: function() {
      return name;
    },
    
    getSex: function() {
      return sex;
    },
    
    setSex: function(newSex) {
      if(typeof newSex == "string" && (newSex.toLowerCase() == "male" || newSex.toLowerCase() == "female")) {
        sex = newSex;
      }
    }
  }
}

var pet = createPet("Vivie");
console.log(pet.getName());                  // Vivie

console.log(pet.setName("Oliver"));   
console.log(pet.setSex("male"));
console.log(pet.getSex());                   // male
console.log(pet.getName());                  // Oliver
</script>

在上面的代码中,外部函数的name变量可以被内部函数访问,除了通过内部函数,没有其他方法访问内部变量。内部函数的内部变量充当内部函数的安全存储。它们保存“持久的”但安全的数据,供内部函数使用。这些函数甚至不需要赋值给变量,也不需要有名称。 详情请阅读此处。

参考:闭包的实际使用

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

一个例子是数组的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

假设,你想统计用户在网页上点击按钮的次数。

为此,您将在按钮的onclick事件上触发一个函数来更新变量的计数

<button onclick="updateClickCount()">click me</button>

现在有很多方法,比如:

你可以使用一个全局变量和一个函数来增加计数器: Var计数器= 0; 函数updatecickcount () { + +计数器; //用counter做一些事情 } 但是,问题在于页面上的任何脚本都可以更改计数器,而不需要调用updatecickcount()。


现在,你可能在考虑在函数内部声明变量: 函数updatecickcount () { Var计数器= 0; + +计数器; //用counter做一些事情 } 但是,嘿!每次调用updateClickCount()函数时,计数器再次被设置为1。


Thinking about nested functions? Nested functions have access to the scope "above" them. In this example, the inner function updateClickCount() has access to the counter variable in the parent function countWrapper(): function countWrapper() { var counter = 0; function updateClickCount() { ++counter; // Do something with counter } updateClickCount(); return counter; } This could have solved the counter dilemma, if you could reach the updateClickCount() function from the outside and you also need to find a way to execute counter = 0 only once not everytime.


Closure to the rescue! (self-invoking function): var updateClickCount = (function(){ var counter = 0; return function(){ ++counter; // Do something with counter } })(); The self-invoking function only runs once. It sets the counter to zero (0), and returns a function expression. This way updateClickCount becomes a function. The "wonderful" part is that it can access the counter in the parent scope. This is called a JavaScript closure. It makes it possible for a function to have "private" variables. The counter is protected by the scope of the anonymous function, and can only be changed using the updateClickCount() function!

一个关于闭包的更生动的例子

< >脚本 var updatecickcount =(函数(){ Var计数器= 0; 返回函数(){ + +计数器; . getelementbyid(“spnCount”)。innerHTML =计数器; } })(); > < /脚本 < html > <按钮onclick = " updateClickCount ()“>点击我> < /按钮 <div>你点击了 <span id="spnCount"> 0 </span> times! < / div > < / html >


参考:JavaScript闭包

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

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

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

没有闭包(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();