美文网首页
JavaScript 作用域

JavaScript 作用域

作者: 樱木夜访流川枫 | 来源:发表于2018-08-05 20:58 被阅读0次

    概览

    背景知识:JavaScript内存管理、JavaScript作用域。

    内容

    1 闭包定义

    闭包:当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行

    function foo() {
      var a = 2;
    
      function bar() {
         console.log(a);
      }
    
      return bar;
    }
    
    var fn = foo();  // parent函数不会被垃圾回收
    fn()  // 2
    

    细节:1 bar函数定义在foo函数内部,bar函数本身被当作一个值类型进行传递,并且它在定义的词法作用域之外执行。
    2 foo()执行完后不会被垃圾回收,bar()将一直持有对该作用域的引用,而这个引用就是闭包

    以下依然是闭包:

    function foo() {
       var a = 2;
       function baz() {
          console.log(a);
       }
    
       bar(baz);
    }
    
    function bar(fn) {
      fn();  // 闭包
    }
    

    总结:无论通过何种手段将内部函数传递到所在的词法作用域外,它都会持有对原始定义词法作用域的引用,无论在何处执行这个函数都会使用到闭包

    闭包 定时器:

    function wait(message) {
       setTimeout(function timer() {
        console.log(message);
       }, 1000);
    }
    
    wait();
    

    分析:wait()执行1000ms后,它不会被垃圾回收,timer()依然wait()作用域的闭包。

    闭包 事件监听器:

    function addEvent(selector) {
      $('selector').click(function cb() {
        // todo
      })
    }
    
    addEvent(btn);
    

    谨记:在定时器、事件监听器、Ajax请求、跨窗口通信、WebWorkers或者任何其他的异步(或同步)任务中,只要使用了回调函数,实际上就是使用闭包。

    循环与闭包

    块级作用域与闭包的结合功能强大。

    内容

    思考:

    for (var i = 0; i < 5; i++) {
      setTimeout(function Timer() {
        console.log(i);
      });
    }
    

    分析:尽管循环中的函数是在各个迭代中分别定义,但是它们都被封闭在共享的全局作用域中,实际上只有一个i

    1 利用IIFE

    for(var i = 0; i < 5; i++) {
      (function print() {
        var j = i;
        setTimeout(function() {
          console.log(j)
        }, j*1000);
      })();
    }
    

    2 利用let、const:

    for(let i = 0; i < 5; i++) {
      setTimeout(function() {
        console.log(i);
      }, i * 1000);
    }
    

    3 模块

    模块也是一种利用闭包的代码模式。

    模块模式的两个必要条件

    1 必须有外部的封闭函数,该函数必须至少被调用一次(每次调用都会创建一个新的模块实例)。
    2 封闭函数必须返回至少一个内部函数,这样内部函数才能在私有作用域中形成闭包,并且可以访问和修改私有的状态。

    一个具有函数属性的对象本身并不是真正的模块。
    一个从函数调用返回的,只有数据属性而没有闭包函数的对象并不是真正的模块。

    相关文章

      网友评论

          本文标题:JavaScript 作用域

          本文链接:https://www.haomeiwen.com/subject/sdkivftx.html