十分钟快速搞懂执行上下文与作用域的关系

1,058 阅读3分钟

海阔凭鱼跃,天高任鸟飞。Hey 你好!我是猫力Molly

温故而知新,可以为师矣。重读红宝书(第四版)系列文章意在对JS知识点复盘整理、查漏补缺,构建自己的前端知识体系。该系列会以自己的理解将红宝书的各个章节知识点整理为文章并发布出来。喜欢的小伙伴欢迎加入我们,让我们一起重读红宝书,温故知新。

变量

JavaScript中的变量是松散类型的,变量可以理解为:指定特定时间点的一个特定值的名称

变量包含两种不同类型的数据:原始值引用值

原始值包含UndefinedNullBooleanNumberStringBigintSymbol,引用值包含Object

原始值

  • 按值访问
  • 赋值时相当于被复制到新变量的位置,两个变量可以独立使用,互不干扰
  • 对于函数的参数传递是复制一份到函数内部属于一个局部变量

引用值

  • 按引用访问
  • 有动态属性的概念,也就是说我们可以随时添加,修改,删除其属性和方法
  • 赋值时相当于将对象引用(指针)复制到新变量的位置,两个变量指向同一个内存地址,当对其中一个对象进行属性操作时,会影响到另一个对象
  • 对于函数参数传递,是复制一份引用到函数内部,修改函数内部参数变量会反应到函数外部

执行上下文(简称:上下文)

变量或函数的上下文决定了它们可以访问哪些数据,以及他们的行为。每个上下文都有一个与之关联的变量对象,这个上下文中定义的所有变量和函数都会存放于这个对象上。虽然无法通过代码直接访问到这个变量对象,不过我们可以通过打断点的方式在控制台查看。

  function foo() {
    let num = 0;
    return function () {
      return num++;
    };
  }
  let add = foo();
  add();

image.png

如图所示其中的[[Scopes]]就是存储上下文的变量对象

上下文可分为全局上下文局部上下文,全局上下文会在程序退出前(例如关闭网页或退出浏览器)被销毁,局部上下文会在其代码执行完毕后被销毁。

每个函数调用都有自己的上下文,当函数执行时,函数的上下文会被推入到一个上下文执行栈上,在函数执行完毕后,上下文执行栈会弹出该函数的上下文,将控制权返还给之前的执行上下文。

当脚本程序执行时,会往所有的上下文执行栈底部推入一个全局上下文,也就是上示截图中的Global属性

上下文中的代码在执行的时候,会创建变量对象的一个作用域链。这个作用域链决定了各级上下文中的代码在访问变量和函数时的顺序。作用域是包含关系,全局包含局部。

小总结

上下文关联了变量对象决定了函数可以访问哪些数据,而作用域则是决定了数据访问的规则。

简单来说,作用域的访问规则可以总结为:由内向外查找访问,内部可以访问外部而外部无法访问内部,这样的访问方式可以称之为作用域链

函数参数被认为是当前上下文中的变量,因此也跟上下文中的其他变量遵循相同的访问规则。

感谢

欢迎关注我的个人公众号前端有猫腻每天给你推送新鲜的优质好文。回复 “福利” 即可获得我精心准备的前端知识大礼包。愿你一路前行,眼里有光!

该系列持续更新中,喜欢的小伙伴欢迎加入我们,让我们一起重读红宝书,温故知新。微信:猫力molly