我正在尽最大努力理解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闭包

其他回答

我已经使用闭包做了如下的事情:

a = (function () {
    var privatefunction = function () {
        alert('hello');
    }

    return {
        publicfunction : function () {
            privatefunction();
        }
    }
})();

正如你在那里看到的,a现在是一个对象,它有一个方法publicfunction(a.publicfunction()),它调用privatefunction,它只存在于闭包中。你不能直接调用privatefunction(即a.b ratefunction()),只能调用publicfunction()。

这是一个最小的例子,但也许你可以看到它的用途?我们使用它来强制公共/私有方法。

是的,这是一个有用闭包的好例子。对warnUser的调用在其作用域中创建calledCount变量,并返回一个匿名函数,该函数存储在warnForTamper变量中。因为仍然有一个使用calledCount变量的闭包,所以在函数退出时不会删除它,所以每次调用warnForTamper()都会增加作用域变量并提醒该值。

我在Stack Overflow上看到的最常见的问题是,有人想要“延迟”使用在每次循环中增加的变量,但因为变量是有作用域的,所以对变量的每次引用都是在循环结束后,导致变量的结束状态:

for (var i = 0; i < someVar.length; i++)
    window.setTimeout(function () {
        alert("Value of i was "+i+" when this timer was set" )
    }, 10000);

这将导致每个警报都显示相同的i值,即循环结束时它增加到的值。解决方案是创建一个新的闭包,一个变量的独立作用域。这可以使用一个立即执行的匿名函数来完成,该函数接收变量并将其状态存储为参数:

for (var i = 0; i < someVar.length; i++)
    (function (i) {
        window.setTimeout(function () {
            alert("Value of i was " + i + " when this timer was set")
        }, 10000);
    })(i);

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

我喜欢Mozilla的函数工厂示例。

function makeAdder(x) {

    return function(y) {
        return x + y;
    };
}

var addFive = makeAdder(5);

console.assert(addFive(2) === 7);
console.assert(addFive(-5) === 0);

闭包的另一个常见用途是将方法中的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”。