javascript闭包-讲解应用示例

javascript闭包

闭包解释:

1. 官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
2. javascript解释:Closures (闭包)是使用被作用域封闭的变量,函数,闭包等执行的一个函数的作用域。  
通常我们用和其相应的函数来指代这些作用域。(可以访问独立数据的函数)
3. 闭包是这样一种手段:通过它,内部函数在其父函数结束后依然能过够引用其外围函数(outer enclosing function)中的变量。
4. 闭包是有权访问另一个函数作用域的变量的函数。

闭包产生:

1. 当函数可以记住并访问所在的上下文时,就产生了闭包,即使函数是在当前上下文外执行。

作用:

1.  阻止GC回收函数作用域相关变量;
2.  读取修改父函数上下文内部的变量;
3.  父函数内部和子函数外部连接起来的一座桥梁;
4.  结合自执行匿名函数遮蔽全局变量。  

实现方式:

1. 定义父函数内部自由变量;
2. 创建并且返回函数,此函数会"捕获"父函数上下文变量绑定(除了this和arguments)。  

闭包的三个事实:

1. javascript允许你引用当前函数以外定义的变量;
2. 即使外部函数已经返回,当前函数任然可以引用在外部函数所定义的变量;
3. 闭包可以更新外部变量的值。

闭包的应用:

1、在定时器,事件监听器、ajax请求、跨窗口通信,web workers或者其他的异步(或同步)任务中,只要使用了回调函数,实际上就是在使用闭包。
2、模块暴露公共API定义
3、循环和闭包:延时输出循环变量,绑定对象引用
4、函数柯里化

示例:两个利用闭包来增加代码清晰度的例子

// 找到ID为main的元素
var objEle = document.getElementById('main');

// 更改边框样式
objEle.style.border = '1px solid red';

// 初始化回调函数,该函数会在1秒之后被调用
setTimeout(function() {
  // 隐藏对象
  objEle.display = 'none';
}, 1000);

// 一个通用函数,显示一条延迟的警告信息
function delayeAlert(msg, time) {
  // 初始化内部的回调函数
  setTimeout(function() {
    // 使用从外部函数传入的msg
    console.log(msg);
  }, time);
}

// 调用函数delayeAlert并传入两个参数
delayeAlert('Welconme', 2000);

示例:使用闭包技术的函数柯里化

// 定义一个函数,该函数生成一个新的加法函数
function addGenerator(num) {
  // 返回一个将两个数字相加的简单函数,其中第一个参数重该函数生成器中获取
  return function(toAdd) {
    return num + toAdd;
  };
}

// addFive中包含了一个函数,该函数接受一个参数,然后将该参数与5相加并且返回计算结果
var addFive = addGenerator(5);

// 在这里可以看到,给函数addFive传入一个值为4的参数时,得到的结果是9
console.log(addFive(4) === 9);

示例:使用匿名函数隐藏全局变量

// 创建一个匿名函数作为包装器来使用
(function() {
  // 这些变量通常都是作为全局变量
  var msg = 'Thanks for visiting!';

  // 将一个新函数绑定到全局对象
  window.onload = function() {
    // 使用隐藏变量
    console.log(msg);
  };

  // 结束匿名函数定义并执行
})();

示例:使用匿名函数来生成创建多个闭包函数所需要的作用域

// ID为main元素
var objElement = document.getElementById('main');

// 要绑定的数组
var onItems = ['click', 'keypress'];

// 迭代数组中的每一项
for (var i = 0; i < onItems.length; i++) {
  // 利用自执行的匿名函数生成作用域
  (function(j) {
    // 记住这一作用域中的值
    // 在该作用域的每个item和j的值都是唯一的,不依赖父上下文中所创建的变量
    var item = items[j];
    // 为元素绑定事件函数
    objElement['on' + item] = function() {
      // item指向的是处于for循环上下文中的父变量
      console.log('Thanks for your ' + item);
    }
  })(i);
}

示例:模块暴露公共API定义

javascript模块模式需要两个必要条件:
1. 必须有外部的封闭函数,该函数必须至少被调用一次(每次调用都会创建一个新的模块实例)
2. 封闭函数必须返回至少一个内部函数,这样内部函数才能在私有上下文中形成闭包,并且可以访问或者修改私有的状态。

// 创建模块CoolModule
function CoolModule() {
  // 定义私有变量
  var something = "cool";
  var another = [1, 2, 3];
  // 定义需要暴露的API方法
  function doSomething() {
    console.log(something);
  }

  function doAnother() {
    console.log(another.join("!"));
  }

  // 暴露API
  return {
    DoSomething: doSomething,
    DoAnother: doAnother
  }
}

var foo = CoolModule();

foo.DoSomething(); // cool
foo.DoAnother(); // 1!2!3
本文参考书籍
  1. 你不知道的JavaScript(上卷)
  2. Effective JavaScript 编写高质量JavaScript代码的68个有效方法
  3. 精通javascript(2)
  4. JavaScript函数式编程
  5. [MDN Web 文档] (https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures)
    [^footnote].[^footnote]: 第一次写内容 如有不足的地方,请大家提出来,共同进步.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值