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

当前回答

这个帖子极大地帮助我更好地理解闭包是如何工作的。

从那以后,我自己做了一些实验,并提出了这个相当简单的代码,它可能会帮助其他人了解如何以实际的方式使用闭包,以及如何在不同的级别上使用闭包来维护类似于静态和/或全局变量的变量,而不会有它们被覆盖或与全局变量混淆的风险。

这将跟踪按钮点击,无论是在本地级别上的每个按钮,还是在全局级别上的每个按钮,计算每个按钮的点击,为单个数字做出贡献。请注意,我没有使用任何全局变量来完成此操作,这是练习的要点—拥有一个可以应用于任何按钮的处理程序,该按钮也对全局具有贡献。

专家们,如果我在这里犯了什么错误,请告诉我!我自己也在学习这些东西。

<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <title>Closures on button presses</title>

    <script type="text/javascript">

        window.addEventListener("load" , function () {
            /*
                Grab the function from the first closure,
                and assign to a temporary variable
                this will set the totalButtonCount variable
                that is used to count the total of all button clicks
            */
            var buttonHandler = buttonsCount();

            /*
                Using the result from the first closure (a function is returned)
                assign and run the sub closure that carries the
                individual variable for button count and assign to the click handlers
            */
            document.getElementById("button1").addEventListener("click" , buttonHandler() );
            document.getElementById("button2").addEventListener("click" , buttonHandler() );
            document.getElementById("button3").addEventListener("click" , buttonHandler() );

            // Now that buttonHandler has served its purpose it can be deleted if needs be
            buttonHandler = null;
        });


        function buttonsCount() {
            /*
                First closure level
                - totalButtonCount acts as a sort of global counter to count any button presses
            */
            var totalButtonCount = 0;

            return  function () {
                // Second closure level
                var myButtonCount = 0;

                return function (event) {
                    // Actual function that is called on the button click
                    event.preventDefault();
                    /*
                       Increment the button counts.
                       myButtonCount only exists in the scope that is
                       applied to each event handler and therefore acts
                       to count each button individually, whereas because
                       of the first closure totalButtonCount exists at
                       the scope just outside, it maintains a sort
                       of static or global variable state
                    */

                    totalButtonCount++;
                    myButtonCount++;

                    /*
                        Do something with the values ... fairly pointless
                        but it shows that each button contributes to both
                        its own variable and the outer variable in the
                        first closure
                    */
                    console.log("Total button clicks: "+totalButtonCount);
                    console.log("This button count: "+myButtonCount);
                }
            }
        }
    </script>
</head>

<body>
    <a href="#" id="button1">Button 1</a>
    <a href="#" id="button2">Button 2</a>
    <a href="#" id="button3">Button 3</a>
</body>

</html>

其他回答

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

为此,您将在按钮的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闭包

闭包有各种各样的用例。在这里,我将解释闭包概念的最重要的用法。

闭包可以用来创建私有方法和变量,就像面向对象的语言,如java、c++等。一旦你实现了私有方法和变量,你在函数中定义的变量将不能被窗口对象访问。这有助于数据隐藏和数据安全。

const privateClass = () => {
  let name = "sundar";
  function setName(changeName) {
    name = changeName;
  }
  function getName() {
    return name;
  }
  return {
    setName: setName,
    getName: getName,
  };
};

let javaLikeObject = privateClass(); \\ similar to new Class() in OOPS.

console.log(javaLikeObject.getName()); \\this will give sundar
javaLikeObject.setName("suresh");
console.log(javaLikeObject.getName()); \\this will give suresh

另一个关于闭包的现实例子:

创建index . html:

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Program with Javascript</title>
  </head>
  <body>
    <p id="first"></p>
    <p id="second"></p>
    <button onclick="applyingConcepts()">Click</button>
    <script src="./index.js"></script>
  </body>
</html>

2)在index.js:

  let count = 0;
  return () => {
    document.getElementById("first").innerHTML = count++;
  };
})();

在本例中,当您单击一个按钮时,计数将在p#id上更新。 注意:您可能想知道这段代码有什么特别之处。检查时,您将注意到不能使用window对象更改count的值。这意味着你已经声明了私有变量count,这样可以防止你的状态被客户端破坏。

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

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