在 JavaScript 中, 只有函数内部的子函数才能读取局部变量, 所以闭包可以理解成 "定义在一个函数内部的函数". 创建闭包的常见方式就是在一个函数内部创建另外一个函数.
什么是闭包?
闭包就是能够读取其他函数内部变量的函数; 是指有权访问另外一个函数作用域中的变量的函数.
由于在 JavaScript 语言中, 只有函数内部的子函数才能读取局部变量, 因此可以把闭包简单理解成 "定义在一个函数内部的函数".
所以, 在本质上, 闭包就是将函数内部和函数外部连接起来的一座桥梁.
闭包的用途
闭包可以用在许多地方. 它的最大用处有两个, 一个是前面提到的可以读取函数内部的变量, 另一个就是让这些变量的值始终保持在内存中.
JavaScript 闭包的使用场景
闭包经典使用场景一: 通过循环给页面上多个 dom 节点绑定事件
场景描述: 假如页面上有 5 个 button, 要给 button 绑定 onclick 事件, 点击的时候, 弹出对应 button 的索引编号.
闭包使用场景二: 封装变量
闭包可以将一些不希望暴露在全局的变量封装成 "私有变量".
假如有一个计算乘积的函数, mult 函数接收一些 number 类型的参数, 并返回乘积结果. 为了提高函数性能, 我们增加缓存机制, 将之前计算过的结果缓存起来, 下次遇到同样的参数, 就可以直接返回结果, 而不需要参与运算.
这里, 存放缓存结果的变量不需要暴露给外界, 并且需要在函数运行结束后, 仍然保存, 所以可以采用闭包.
示例:
- var mult = (function(){
- var cache = {};
- var calculate = function() {
- var a = 1;
- for(var i = 0, len = arguments.length; i < len; i++) {
- a = a * arguments[i];
- }
- return a;
- }
- return function() {
- var args = Array.prototype.join.call(arguments, ',');
- if(args in cache) {
- return cache[args];
- }
- return cache[args] = calculate.apply(null, arguments);
- }
- }())
闭包使用场景三: 延续局部变量的寿命
img 对象经常用于数据上报, 如下:
- var report = function(src) { var img = new Image();
- img.src = src;
- }
- report('http://xxx.com/getUserInfo');
这段代码在运行时, 发现在一些低版本浏览器上存在 bug, 会丢失部分数据上报, 原因是 img 是 report 函数中的局部变量, 当 report 函数调用结束后, img 对象随即被销毁, 而此时可能还没来得及发出 http 请求, 所以此次请求就会丢失.
因此, 我们使用闭包把 img 对象封闭起来, 就可以解决数据丢失的问题:
- var report = (function() {
- var imgs = [];
- return function(src) {
- var img = new Image();
- imgs.push(img);
- img.src = src;
- }
- }())
闭包 + 设计模式
在诸多设计模式中, 闭包都有广泛的应用. 对象 == 数据 + 方法. 而闭包是在过程中以环境的形式包含了数据. 因此, 通常面向对象能实现的功能, 使用闭包也可以实现.
来源: http://www.css88.com/qa/javascript/11756.html