【动画演示】:JS 作用域链不在话下

作者:Lydia Hallie
译者:前端小智
来源:dev

点赞再看,养成习惯

本文 GitHub https://github.com/qq44924588... 上已经收录,更多往期高赞文章的分类,也整理了很多我的文档,和教程资料。欢迎Star和完善,大家面试可以参照考点复习,希望我们一起有点东西。



本篇我们来看看啥是作用域以及作用域链,首先,来看看下面的代码:

const name = "Lydia"
const age = 21
const city = "San Francisco"

function getPersonInfo() {
  const name = "Sarah"
  const age = 22

  return `${name} is ${age} and lives in ${city}`
}

console.log(getPersonInfo())
// Sarah is 22 and lives in San Francisco

我们调用getPersonInfo函数,它返回一个包含姓名、年龄和城市变量值的字符串:Sarah is 22 and lives in San Francisco。但是,getPersonInfo函数中不包含变量 city,它是怎么取到 city 的值?

首先,JS 引擎为不同的上下文设置内存空间。我们有默认的全局上下文(浏览器中的window、Node 中的global ),以及已经调用的getPersonInfo函数的本地上下文,每个上下文还有一个作用域链

对于getPersonInfo函数,作用域链看起来是这样的:

作用域链基本上是对对象的“引用链”,其中包含对在执行上下文中可引用的值(和其他作用域)的引用。作用域是在创建执行上下文时创建的,这说明它是在运行时创建的。

在本文中,不会讨论激活对象或执行上下文,我们只关注作用域。 在以下示例中,执行上下文中的键/值对表示使作用域链对变量的引用。

全局执行上下文(GLOBAL EXECUTION CONTEXT)的作用域链引用了3个变量:值为Lydianame、值为21age和值为San Franciscocity。在本地执行上下文(LOCAL EXECUTION CONTEXT)中,我们引用了两个变量:name值为Sarah, age值为22

当我们试图访问getPersonInfo函数中的变量时,JS引擎首先检查局部作用域链。

本地作用域链有一个nameage的引用!name的值是Sarah, age的值是22。但是现在,当它试图访问city变量时会发生什么?

为了找到变量city的值,JS 引擎沿着作用域链向上查找,直到在外部作用域内为找到了一个city的值,本地作用域有一个引用,在本例中是全局对象

在全局上下文中,我们用San Francisco的值声明了变量city,因此有一个对变量city的引用。现在我们有了变量的值,函数getPersonInfo可以返回字符串Sarah is 22 and lives in San Francisco

我们可以沿着作用域链向下走,但是我们不能沿着作用链向上走,这可能会让人困惑,因为我们大都会说“向上”而不是“向下”,所以换一种说法:你可以进入外部作用域,但不能进入内部作用域,可以把它想象成瀑布模型:

更深的嵌套:

以这段代码为例:

这个跟上个例子代码几乎是一样的,但是有一个很大的区别:我们现在只在getPersonInfo函数中声明city,而不在全局作用域中。这里也没有调用getPersonInfo函数,所以也没有创建本地上下文。然而,我们试图在全局上下文中访问nameagecity的值。

这里分抛出一个ReferenceError异常,因为 JS 在全局范围内找不到一个名为city的变量的引用,因为已处于顶部作用域,也没法向上的作用域查找了。

通过这种方式,我们可以将作用域用作“保护”变量并重新使用变量名的方法。

除了全局作用域和局部作用域之外,还有一个块作用域。使用letconst关键字声明的变量的作用域就是块作用域。

const age = 21

function checkAge() {
  if (age < 21) {
    const message = "You cannot drink!"
    return message
  } else {
    const message = "You can drink!"
    return message
  }
}

可以将上面的作用域可视化为:

这里有一个全局作用域、一个函数作用域和两个块作用域。我们可以两次声明变量message ,因为message 变量处在不同的作用域中。

快速回顾:

  • 可以将“作用域链”看作是在当前上下文中访问的值的引用链。
  • 作用域还可以重用在该该作用域链上定义的变量名,因为它会沿着作用域链向上查找。


原文:https://dev.to/lydiahallie/ja...

代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。



交流

干货系列文章汇总如下,觉得不错点个Star,欢迎 加群 互相学习。

https://github.com/qq44924588...

我是小智,公众号「大迁世界」作者,对前端技术保持学习爱好者。我会经常分享自己所学所看的干货,在进阶的路上,共勉!

关注公众号,后台回复福利,即可看到福利,你懂的。

原文地址:https://www.cnblogs.com/dearroy/p/12200810.html

时间: 2024-10-09 09:35:40

【动画演示】:JS 作用域链不在话下的相关文章

js作用域链中变量提前的问题

js訪问变量是从内到外,这条作用域链上面的每一个活动变量也是从内到外的.比方一个函数,首先由arguments和函数内部声明的变量,然后是外层的能訪问的变量.直至最后window全局对象.当出了这个函数,函数内部声明的活动对象就会销毁,所以外部滴根本无法訪问函数内部声明的对象的.之所以说js会把全部的变量提前也是针对不同的作用域的,在最外面.则是把全部的全局变量和全局的函数声明提前,在函数内部,则是先把函数内部声明的变量和函数提前

js 作用域链&amp;内存回收&amp;变量&amp;闭包

闭包主要涉及到js的几个其他的特性:作用域链,垃圾(内存)回收机制,函数嵌套,等等 一.作用域链:函数在定义的时候创建的,用于寻找使用到的变量的值的一个索引,而他内部的规则是,把函数自身的本地变量放在最前面,把自身的父级函数中的变量放在其次,把再高一级函数中的变量放在更后面,以此类推直至全局对象为止.当函数中需要查询一个变量的值的时候,js解释器会去作用域链去查找,从最前面的本地变量中先找,如果没有找到对应的变量,则到下一级的链上找,一旦找到了变量,则不再继续.如果找到最后也没找到需要的变量,则

Js作用域链及变量作用域

要理解变量的作用域范围就得先理解作用域链 用var关键字声明一个变量时,就是为该变量所在的对象添加了一个属性. 作用域链:由于js的变量都是对象的属性,而该对象可能又是其它对象的属性,而所有的对象都是window对象的属性,所以这些对象的关系可以看作是一条链 链头就是变量所处的对象,链尾就是window对象 看下面的代码: function t() { var a; function t2() { var b; } } js中函数也是对象,所以变量a所在的对象是t,t又在window对象中,所以

JS作用域链

Js作用域与执行环境: 1. 作用域链: <1>用途:保证对执行环境有权访问的所有变量和函数的有序访问. <2>构成: a.作用域链的前端,始终都是当前执行代码所在环境的变量对象(如果这个环境是函数,则将其活动对象作为变量对象,活动对象在最开始时只包含一个变量,即arguments对象): b.下一个变量对象来自包含(外部)环境: c.最后一个对象,为全局执行环境的变量对象. <3>标识符解析:是沿着作用域链一级一级地搜索标识符的过程,始终从作用域链的前端开始,然后逐级

[js]作用域链查找规则获取值和设置值

作用域链查找规则获取值和设置值 <script> /** 1.作用域链查找规则 私有作用域出现的一个变量不是私有的,则往上一级作用域查找,上级作用域没有则继续向上级查找,一直找到window为止,如果window也没有了? 1)如果是获取值,则报错 2)如果是设置值,则相当于给window设置了一个属性 2.js代码一旦报错,则不往下执行了. */ function fn() { console.log(total); //获取值 total = 100; //设置值 } fn(); cons

js作用域链以及全局变量和局部变量

> [带var] > 在当前作用于中声明了一个变量,如果当前是全局作用域,也相当于给全局作用域设置了一个属性叫做a ```javascript //=>变量提升:var a; <=>window.a=undefined; console.log(a);//undefined var a = 12; console.log(a);//12 console.log(window.a);//window['a']在'全局作用域'中,我们声明了一个变量,相当于全局对象window增加

Js 作用域链(是指AO链)

1:参数 2:局部变量声明 3:函数声明 * 函数声明与函数表达式的区别 表达式必有返回值,把返回值(即匿名函数)赋给了一个变量. 此时 就是普通的赋值过程. ①.js并不是一句一句顺序执行的,先进行词法分析 This, 与 arguments 当一个函数运行的时候,函数内部能引用的变量有这么几种 AO.arguments.this 对于 arguments和this, 每个函数都有自己独有的arguments和this, 且不进行链式查找 arguments是什么? 答:1:arguments

关于js作用域链,以及闭包中的坑

eg:链式作用域,想在外部读取blogName的值得方法 <script>var authorName="山边小溪";function doSomething(){    var blogName="梦想天空"; function innerSay(){        console.log(blogName+"1");    }       innerSay();  }doSomething() </script> 在上

js作用域链 js没有块级作用域

arguments和函数内定义的变量或函数->父级->下一个父级->.....->全局环境中的变量或函数 if(true){ var a=1; } console.log(a);js没有块级作用域, 变量a直接添加到当前的执行环境中.  java有块级作用域,if语句结束后会销毁if中定义的变量