看题说话,分析一下以下代码的作用域
var x = 10; function a() { console.log(x); } function b () { var x = 5; a(); } b();
简单分析一下这个程序吧,虽然不敢保证理解完全正确.先简单介绍点概念.
执行上下文
每当控制器到达ECMAScript可执行代码的时候,控制器就进入了一个执行上下文.
执行上下文是个抽象概念,标准中没有从技术实现上定义执行上下文的具体结构和类型.
就是一系列活动的执行上下文从逻辑上形成一个栈(比较抽象).
栈底总是全局上下文,栈顶是当前(活动的)执行上下文.
当在不同的执行上下文间切换(退出而进入新的执行上下文)的时候,栈会被修改(通过压栈或者出栈的形式).
变量对象
执行上下文的数据是以变量对象的属性形式进行存储的.
一个变量对象(简写为VO)是一个和执行上下文相关的特别对象,存储以下内容:
变量(声明的变量,var)
函数声明(简写为FD)
在上下文中,函数声明的形式参数
作用域链
作用域链是一条变量对象的链,它和执行上下文有关,用于在处理标识符的时候进行变量查询.
函数上下文的作用域链在函数调用的时候创建出来,它包含了活跃对象和该函数的内部[[Scope]]属性.
执行上下文变量大致如下:
activeExecutionContext = { VO:{...},//或者AO this:thisValue, Scope:[ //作用域链,所有变量对象的列表,用来查询标识符 ] }
上面Scope可以定义如下:
Scope = AO+[[Scope]]
可以用数组进行表示:
var Scope = [VO1,VO2,...,VOn];//作用域链
函数的创建
在进入上下文阶段,函数声明会存储在变量/活跃对象中(VO/AO)
[[Scope]]是一个包含了所有上层变量对象的分层链,它属于当前函数的上下文,并在函数创建的时候,保存在函数中.
[[Scope]]是在函数创建的时候i保存起来的----静态的(不变的),只有一次并且一直都存在--直到函数销毁. [[Scope]]与Scope(作用域链)是不同的,前者是函数的属性,后者是上下文的属性.拿上面的来说a函数的 [[Scope]]:
a.[[Scope]] = [
globalContext.VO //===Global
]
函数调用后,就会进入函数上下文,此时创建活跃对象并且确定this的值和Scope(作用域链).
函数激活
在进入上下文,AO/VO创建之后,上下文的Scope属性(作用域链)会定义如下所示:
Scope = AO+[[Scope]]
AO会添加在作用域链的最前面
Scope = [AO].concat([[Scope]]);
处理标识符其实就是一个确定变量(或者函数声明)属于作用域中哪个变量对象的过程.
此算法返回的总是一个引用类型的值,其base属性就是对应的变量对象(或者如果变量不存在的时候返回null),其property name属性的名字就是要查询的标识符.
标识符处理过程包括了对应的变量名的属性查询,如:在作用域链中会进行一系列的变量对象的检测,从作用域链的最底层上下文一直到最上层上下文
所以,在查询过程中上下文中的局部变量相比较上层上下文的变量会优先被查询到
分析如下:
全局上下文的变量对象如下:
globalContext.VO===Global={
x:10,
a:,
b:
}
在"a"函数创建的时候,其[[Scope]]属性如下所示:
a.[[Scope]]=[
globalContext.VO
]
在"b"函数创建的时候,其[[Scope]]属性如下所示:
b.[[Scope]]=[
globalContext.VO
]
在"b"函数激活的时候(进入上下文时),"b"函数上下文的活跃对象如下:
bContext.AO={
x:5
}
同时,"b"函数上下文的作用域如下所示:
bContext.Scope=[bContext.AO,globalContext.VO]
在"a"函数激活的时候(进入上下文时),"a"函数上下文的活跃对象如下:
aContext.AO={
}
同时,"a"函数上下文的作用域如下所示:
aContext.Scope=[aContext.AO,globalContext.VO]
"x"标识符的查找过程:
"x"
----aContext.AO//没有找到
----globalContext.VO //找到 10
相关推荐
JavaScript中的执行环境(作用域)和作用域链是理解JavaScript变量和函数访问规则的关键概念。首先,执行环境指的是代码在何处执行,它决定了变量的生命周期和可访问性。全局执行环境是在整个脚本开始运行时创建的,...
在JavaScript编程中,作用域是一个重要的概念,它决定了变量和函数可以被访问和使用的区域。与一些其他编程语言相比,JavaScript的作用域机制有所不同,因此开发者需要特别注意。 首先,JavaScript中的作用域分为两...
Js中的变量作用域问题: 1、没有块级作用域。Js中的变量作用域不是以{}为界的,不像C/C++/Java。 如: 代码如下: if(true){ var name = “qqyumidi”; } alert(name); // 结果:qqyumidi Js会...
JavaScript中的函数和作用域是编程的核心概念,理解它们对于编写高效、可维护的代码至关重要。本文将深入探讨这两个主题。 (一)JavaScript函数 函数在JavaScript中扮演着至关重要的角色,它们是可重用的代码块,...
闭包是一个重要的概念,它对于理解JavaScript和Node.js中的作用域非常重要。 通过上述内容的介绍,相信你已经对Node.js中的作用域问题有了较为全面的认识。了解这些作用域机制对于编写可维护、可扩展的Node.js应用...
作用域和闭包在JavaScript里非常重要。但是在我最初学习JavaScript的时候,却很难理解。这篇文章会用一些例子帮你理解它们。 我们先从作用域开始。 作用域 JavaScript的作用域限定了你可以访问哪些变量。有两种作用...
在执行过程中,JavaScript通过作用域链来解析标识符(变量和函数名)。它从作用域链的前端开始,沿着链路逐级查找,直到找到标识符为止。如果在局部作用域找不到,会继续在上一层(外部)作用域查找,直到全局作用域...
在JavaScript编程中,作用域和闭包是两个十分重要的概念。作用域决定了变量的生命周期和可见性,而闭包则是让函数能够记住并访问所在词法作用域的特性,即使函数在当前词法作用域外执行。 首先,关于JavaScript中的...
由于childCtrl的作用域继承自parentCtrl,因此它能够通过原型链访问到parentCtrl作用域中的args属性。所以在子控制器中输入的值能够实时同步到父控制器的视图中。然而,因为childCtrl中的input标签绑定了childCtrl...
在js中有两种主要的作用域: 1. **全局作用域**:在所有函数外部定义的变量拥有全局作用域,也就是说,可以在整个脚本的任何位置访问这些变量。 2. **函数作用域**:在函数内部定义的变量只在该函数内部有效。每当...
在本篇中,我们将深入探讨Vue.js组件的几个关键概念,包括插槽、作用域以及具名插槽。 首先,插槽(Slot)是Vue.js中实现组件内容分发的方式。它允许父组件向子组件传递动态内容。在子组件中定义一个名为`child`的...
2. 让这些变量始终保持在内存中:由于`B`函数的存在,`A`函数的作用域并未被垃圾回收,`S`变量得以保留在内存中。在下面的例子中: ```javascript function A() { var S = 1; D = function() { S += 1; }; ...