zoukankan      html  css  js  c++  java
  • 浅析 JS 中的作用域链

    作用域链的形成

    在 JS 中每个函数都有自己的执行环境,而每个执行环境都有一个与之对应的变量对象。例如:

    var a = 2
    function fn () {
      var a = 1
      console.log(a) 
    }
    fn() // 输出 1
    

    你就可以将 fn 当做函数 fn 执行环境对应的一个变量对象,这个变量对象我们通过代码是无法访问到的,但是 JS

    引擎在解析代码时会用到它。

    思考为什么上面函数中的 fn 运行后输出 1,可能大家都知道,但是为什么会输出 1 呢,用上面的变量对象来理解就可以得出答案。实际上:

    console.log(a)
    // 等价于
    console.log(fn.a)
    

    这个 fn 就是函数 fn 对应的变量对象,我们通过代码没有办法得到它,但是 JS 引擎可以,并且利用它找了变量 a。

    现在再来思考下面这一种情况:

    var a = 3
    function fn1() {
      var a = 2
      function fn2() {
        console.log(a)
      }
      fn2()
    }
    fn1() // 输出 2
    

    为什么输出 2 而不是 3 呢?

    这就引出了作用域链,函数 fn2 对应的变量对象时是 fn2,函数 fn1 对应的变量对象是 fn1,全局执行环境对应的变量对象是 window 对象。当代码中的变量 a 在 fn2 中找不到时就不会去它的父环境 fn1 对应的变量对象 fn1 中去查找,发现有 a 变量就使用它。

    实际上这个查找的过程就是沿着作用域链查找的过程。

    当一个函数被执行时,就会创建一条由变量对象(函数执行时也叫活动对象)组成的作用域链,作用域链的前端就是当前代码执行所在环境对应的变量对象(即 fn2),下一个变量对象来自父环境对应的变量对象(即 fn1),一直到全局执行环境的变量对象 window。

    因此,上面代码中的作用域链就是 fn1 -> fn2 -> window,查找标识符的顺序就是顺着作用域链从最前端开始依次向后查找,在某个变量对象中找到后就停止往后查找。

    延长作用域链

    既然我们知道作用域链的前端就是当前运行环境所在的变量对象,那么能不能人为地改变作用域链前端的变量对象呢?

    答案是肯定的。

    1)利用 try-catch 语句块中的 catch

    catch 语句块中会创建一个新的变量对象,并且处于作用域链的最前端,其中包含的是被抛出的错误对象的声明。

    2)with 语句

    对于 with 语句来说会将指定的对象添加到作用域链的最前端。

  • 相关阅读:
    3、看源码MVC中的Controllr的Json方法
    2、MVC+IOC容器+ORM结合
    1、看源码MVC如何实例化控制器?
    6、UnityConfig实现AOP
    5、动态代理AOP实现-DynamicProxy模式
    1、面向切面编程
    通过js看类似C#中的回掉
    C#新开一个线程取到数据,如何更新到主线程UI上面
    2.C#自定义Attribute
    1.C#中几个简单的内置Attribute
  • 原文地址:https://www.cnblogs.com/zhangguicheng/p/12815201.html
Copyright © 2011-2022 走看看