JS作用域链详解

yizhihongxing

JS作用域链详解

JavaScript采用词法作用域,也就是变量的作用域在定义时就已经确定了。而在JavaScript中,作用域可以形成一个链式结构,这被称为作用域链。在这个链结构中,每一个函数都有自己的作用域,如果一个变量在当前作用域中未定义,则会沿着作用域链向上查找,直到查找到该变量为止,或者到达全局作用域。

作用域链的构成

JavaScript中的作用域链是由一个个执行上下文(Execution Context)构成的。而每一个执行上下文又分为三个部分:变量对象(Variable Object),作用域链(Scope Chain)和this对象。

变量对象是当前执行上下文中的变量、函数声明和形参的存储空间,作用域链是当前执行上下文的父环境。变量对象通过作用域链查找某个变量的值。this对象是函数调用时的当前对象。

作用域链形成的过程:在函数执行的时候,会首先创建一个新的执行上下文,然后将这个上下文的变量对象加入到作用域链的最顶端,接着将父级执行上下文的作用域链加入到自身作用域链的末尾,最后形成的作用域链便是可以被访问的所有变量、函数或对象的作用域。

作用域链的查找

当JavaScript引擎在执行代码时遇到一个变量,它会先在当前作用域中查找该变量是否被定义,如果没找到,那么就会沿着作用域链向上查找,直到找到为止。如果一直找到全局部还没找到,则会抛出ReferenceError的异常。如果找到了,就直接使用这个变量,而不需要再次创建这个变量。

具体来说,当需要查找某个变量时,JavaScript引擎会先在当前执行上下文中的变量对象中查找该变量,在该对象中找到该变量就不需要再进行后续的查找了;否则就把当前执行上下文的作用域链中的父级执行上下文的变量对象加入到自身作用域链的末尾,然后继续执行上述查找逻辑,直到查找到该变量,或者直到作用域链的末尾。

示例说明

下面通过两个例子进一步演示作用域链的应用:

例子1:全局环境和函数环境之间的作用域链

var a = 1;
function foo() {
  var b = 2;
  function bar() {
    var c = 3;
    console.log(a, b, c);
  }
  bar();
}
foo(); // 输出:1 2 3

在该例中,当执行foo函数时,会首先创建一个名为foo的执行上下文,并将该上下文的变量对象加入到作用域链的顶端。此时作用域链为:foo变量对象 => 全局变量对象

当执行到bar函数时,JavaScript会同样创建一个名为bar的执行上下文,并将该上下文的变量对象加入到作用域链的顶端。此时作用域链为:bar变量对象 => foo变量对象 => 全局变量对象

因此,当bar函数执行时,会先在该函数作用域中查找c变量,然后在上层的foo作用域中查找b变量,最后在全局作用域中查找a变量。

例子2:作用域链的动态性

var a = 10;
function foo() {
  console.log(a);
  var b = 20;
  function bar() {
    console.log(a, b, c);
  }
  bar();
}
foo();

在该例中,当执行foo()函数时,JavaScript引擎会首先查找当前作用域下的变量对象,由于当前作用域下不存在变量a,因此JavaScript引擎会沿着作用域链向上查找,找到它的父级作用域,也就是全局作用域,在全局作用域中找到了变量a的值,因此执行完console.log(a)语句后,即可输出变量a的值为10

接着JavaScript引擎执行到bar()函数时,会创建一个新的执行上下文,并将该上下文的变量对象加入到作用域链的顶端。此时作用域链为:bar变量对象 => foo变量对象 => 全局变量对象

由于变量c未定义,在当前执行上下文中查找不到变量c,因此JavaScript引擎继续在上一级执行上下文中查找变量c,但上一级执行上下文依然查找不到变量c,更上一级执行上下文也查找不到变量c,最终在全局变量对象中仍然找不到变量c,因此引擎抛出了ReferenceError错误,提示变量c未定义。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JS作用域链详解 - Python技术站

(0)
上一篇 2023年6月10日
下一篇 2023年6月10日

相关文章

  • js中json处理总结之JSON.parse

    JSON.parse() 是 JavaScript 中一个用于将 JSON 字符串转换成 JavaScript 对象的方法,它的语法如下: JSON.parse(text [, reviver]) 其中,text 是要转换的 JSON 字符串;reviver 是一个可选的转换函数,用于对最终生成的对象进行处理。 当我们从后台或其他来源获取到 JSON 数据时…

    JavaScript 2023年5月27日
    00
  • 细品javascript 寻址,闭包,对象模型和相关问题

    以下是关于“细品 JavaScript 寻址、闭包、对象模型和相关问题”的详细攻略。 一、JavaScript 寻址 JavaScript 寻址是指在访问对象的属性或方法时,JavaScript 引擎会自动查找对象及其原型链,然后返回相应属性或方法的值或引用。具体实现方式有点类似于链表,会一层层向上查找直到找到目标属性或方法。 例如,我们可以创建一个对象 p…

    JavaScript 2023年6月10日
    00
  • 一文彻底搞懂Vue的MVVM响应式原理

    一文彻底搞懂Vue的MVVM响应式原理 了解Vue.js Vue.js 是一个渐进式JavaScript框架,它采用 MVVM(Model-View-ViewModel)模式进行构建。其中 ViewModel 是 Vue.js 主要的核心,Vue.js 的响应式也是建立在 ViewModel 上的。 Vue.js 的响应式原理 Vue.js 的响应式原理是基…

    JavaScript 2023年6月10日
    00
  • javascript实现自动输出文本(打字特效)

    下面是JavaScript实现自动输出文本(打字特效)的完整攻略。 1. 前置知识 JavaScript基础知识 HTML/CSS基础知识 DOM基础知识 2. 确定需求 在实现自动输出文本的过程中,我们需要考虑以下问题: 输出文本的内容是什么? 文本输出的速度是多少? 每个字符输出的间隔时间是多少? 3. 实现步骤 3.1 HTML结构 首先,我们需要准备…

    JavaScript 2023年5月28日
    00
  • JS代码放在head和body中的区别分析

    JS代码放在head和body中的区别分析 以网页为例,其中包含了HTML、CSS、JS三种内容。其中HTML体现了网页的内容结构,CSS刻画了网页的外观样式,而JS则掌管了网页的交互行为。而JS代码在页面中该如何放置呢?通常有两种位置可供选择:head标签内和body标签内。下面分别对这两种方式进行分析。 head标签内放置JS代码 head标签一般放置的…

    JavaScript 2023年6月11日
    00
  • javascript作用域和闭包使用详解

    JavaScript作用域和闭包使用详解 什么是作用域 作用域是指变量的可访问范围。在JavaScript中,变量的作用域主要有两种,全局作用域和局部作用域。 全局作用域中定义的变量可以被任何代码访问,而局部作用域中定义的变量只能在其所在的代码块(比如函数,循环等)中访问。 在JavaScript中,作用域链是沿着嵌套的代码块向上查询变量定义的一条链。如果当…

    JavaScript 2023年6月10日
    00
  • fireworks菜单生成器mm_menu.js在 IE 7.0 显示问题的解决方法

    为了解决Fireworks菜单生成器mm_menu.js在IE 7.0中的显示问题,我们需要进行以下步骤: 步骤一:升级mm_menu.js 首先,我们需要下载最新版本的mm_menu.js文件,并将其替换掉原始的文件。最新版本的mm_menu.js可以从Dreamweaver的官网或其他网络资源库中获取。 步骤二:修改CSS样式 接下来,我们需要修改CSS…

    JavaScript 2023年5月28日
    00
  • js实现表单校验功能

    当我们进行前端开发时,表单校验是必不可少的功能。下面是一些基本的步骤和示例,可以帮助你实现基本的表单校验功能。 步骤 选择需要校验的表单如果你的表单不止一个,可以给每个表单添加id属性,便于区分。 给表单绑定submit事件我们需要在表单提交的时候进行校验,避免用户输入不合法的信息。 $(‘#form’).submit(function(e) { // 表单…

    JavaScript 2023年6月10日
    00
合作推广
合作推广
分享本页
返回顶部