美文网首页
关于作用域链

关于作用域链

作者: gzy_a5a4 | 来源:发表于2018-06-27 16:44 被阅读0次

    JavaScript 有两种作用域:全局作用域和函数作用域。

    var n = 1;
    
    function f1() {
      console.log(n);
    }
    f1() // 1
    

    函数内部可以直接读取全局变量,但是函数外部不能读取函数内部声明的变量。

    function f1() {
      var n = 1;
    }
    
    console.log(n)
    // Uncaught ReferenceError: n is not defined
    

    如果出于种种原因,需要得到函数内的局部变量。正常情况下,这是办不到的,只有通过变通方法才能实现。那就是在函数的内部,再定义一个函数。

    function f1() {
      var n = 1;
      function f2() {
      console.log(n); // 1
      }
    }
    

    JavaScript 语言特有的”链式作用域”结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。父对象的所有变量,对子对象都是可见的,反之则不成立。因此对于上述例子中,f2可以使用f1作用域中的变量。

    function f1() {
      var n = 1;
      function f2() {
        console.log(n);
      }
      return f2;
    }
    
    var result = f1();
    result(); // 1
    

    闭包就是函数f2,即能够读取其他函数内部变量的函数。

    由于在 JavaScript 语言中,只有函数内部的子函数才能读取内部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。

    闭包最大的特点,就是它可以“记住”诞生的环境,比如f2记住了它诞生的环境f1,所以从f2可以得到f1的内部变量。

    在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

    关于作用域链,只要记住先从自己的作用域下找,找不到从上层作用域找就可以了。

    题1
    
    var a = 1
    function fn1(){
      function fn2(){
        console.log(a)
      }
      function fn3(){
        var a = 4
        fn2()
      }
      var a = 2
      return fn3
    }
    var fn = fn1()
    fn() // 找出输出函数是 fn2,但是其作用域下无 a 的声明,再找上一级 fn1,a=2
    
    题2
    
    var a = 1
    function fn1(){
      function fn3(){
        var a = 4
        fn2()
      }
      var a = 2
      return fn3
    }
    function fn2(){
      console.log(a)
    }
    var fn = fn1()
    fn() // fn2 里没有,全局 a=1
    
    题3
    
    var a = 1
    function fn1(){
    
      function fn3(){
        function fn2(){
          console.log(a)
        }
        var a
    
        fn2()
        a = 4
      }
      var a = 2
      return fn3
    }
    var fn = fn1()
    fn() // fn2 没有,fn3 有,但是根据声明顺序,最终结果是 undefined
    

    参考:http://javascript.ruanyifeng.com/ 、饥人谷

    相关文章

      网友评论

          本文标题:关于作用域链

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