第五章 作用域闭包

5.作用域闭包

5.1 启示

  1. function foo(){
  2.    var a = 2;
  3.    function bar(){
  4.        console.log(a);
  5. }
  6.    return bar;
  7. }
  8. var baz = foo();
  9. baz(); // 2 闭包的效果
  10. // 函数bar在定义时的词法作用域外被调用。闭包使得它可以继续访问定义时的词法作用域。
 
闭包实际上只是一个标准--关于如何在函数作为值按需传递的此法环境中书写代码
 
当函数可以记住并访问所在的词法作用域,即使函数是在当前词法作用域之外执行,这时就产生了闭包。
 

5.2 实质问题

无论使用何种方式对函数类型的值进行传递,当函数在别处调用时都可以观察到闭包。
  1. function foo(){
  2.    var a = 2;
  3.    function baz(){
  4.      console.log(a); //2
  5. }
  6.    bar(baz);
  7. }
  8. function bar(fn){
  9.    fn(); //闭包
  10. }
间接调用
  1. var fn;
  2.  
  3. function foo(){
  4.    var a = 2;
  5.    function baz(){
  6.       console.log(a);
  7. }
  8.    fn = baz; //将baz分配给全局变量
  9. }
  10. function bar(){
  11.    fn();
  12. }
  13. foo();
  14. bar();//2
 

5.3 I got it

在定时器、事假监听器、Ajax请求、跨窗口通信、Web Woekers或者任何其他的异步(或同步)任务中,使用了回调函数就是在使用闭包。
 
IIFE
  1. var a = 2;
  2. (function IIFE(){
  3.    console.log(a);
  4. })();
严格来说,并不是闭包。IIFE不是在它本身的词法作用域以外执行的。a是通过普通的词法作用域查找而非闭包发现的。
但它的确创建了闭包,并且也是最常用来创建可以封闭起来的闭包的工具。
 

5.4 循环和闭包

  1. for(var i =1; i<=5; i++){
  2.    setTimeout(function timer(){
  3.        console.log(i);
  4. },i*1000);
  5. }
输出6.  延迟函数的回调会在循环结束时才执行,即使第二个参数是0,所有的回调函数依然是在循环结束之后才会被执行。
 
缺陷是:再循环过程中每个迭代都需要一个闭包作用域。要想得到想要的结果--每个一秒输出一个数字(递增1)--1~5
 
  1. for(var i =1;i<=5;i++){
  2.    (function(){
  3.     var j = i;
  4.        setTimeout(function timer(){
  5.            console.log(j);
  6.    },j*1000);
  7. })();
  8. }
在迭代内使用IIFE会为每个迭代都生成一个新的作用域,使延迟函数的回调可以将新的作用域封闭在每个迭代内部,每个迭代中都会含有一个具有正确值的变量供我们访问。
 
块作用域

let:用来劫持块作用域,并且在这个块作用域中声明一个变量。

  1. for(let i = 1; i<=5; i++){
  2.    setTimeout(function(){
  3.        console.log(i);
  4. },i*1000);
  5. }
!!!可以得到想要的效果 1,2,3,4,5   块作用域和闭包
 

5.5 模块

模块模式需要具备两个必备条件:
  1. 必须有外部的封闭函数,该函数必须至少被调用一次(每次调用都会创建一个新的模块实例)。
  2. 封闭函数必须返回至少一个内部函数,这样内部函数才能在私有作用于中形成闭包,并且可以访问或者修改 私有的状态。
一个从函数调用所返回的,只有数据属性而没有闭包函数的对象并不是真正的模块。
 
 
模块有两个主要特征
  • 为创建内部作用域而调用了一个包装函数
  • 包装函数的返回值必须至少包括一个对内部函数的引用,这样就会创建涵盖整个包装函数内部作用域的闭包。
 

5.5.1 现代的模块

大多数模块依赖加载器/管理器本质上都是将这种模块定义封装进一个有好的API里。

5.5.2  未来的模块

import可以将一个模块中的一个或多个API导入到当前作用域中,并分别绑定在一个变量上。
moddle会将整个模块的API导入并绑定在一个变量上。
export会将当前模块的一个标识符(变量、函数)导出为公共API
 
模块文件中的内容会被当做好型包含在作用域闭包中一样来处理,和函数闭包模块一样
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 





posted @ 2017-03-02 09:12  夏目233  阅读(168)  评论(0编辑  收藏  举报