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

当前回答

闭包是一种创建生成器的有用方法,它是一个按需递增的序列:

var foobar = function(i){var count = count || i; return function(){return ++count;}} 巴兹 = 福巴(1); console.log(“First Call: ” + baz());2 console.log(“第二次调用: ” + baz());3

区别总结如下:

Anonymous functions                                    Defined functions

Cannot be used as a method                             Can be used as a method of an object

Exists only in the scope in which it is defined        Exists within the object it is defined in

Can only be called in the scope in which it is defined Can be called at any point in the code

Can be reassigned a new value or deleted               Cannot be deleted or changed

参考文献

AS3基础知识:功能

其他回答

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

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

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

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

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

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

为此,您将在按钮的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(或任何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对象的属性,但是脚本用户可以看到它,他们甚至可以根据需要更改它,甚至不需要您的源代码。但是,由于它被返回日期查找函数的匿名函数所包围,因此只能由查找函数访问,因此现在它是防篡改的。

参考:闭包的实际使用

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

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

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

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