JavaScript:理解执行环境、作用域链和活动对象
作用域的原理,对JS将如何解析标识符做出了解答。而作用域的形成与执行环境和活动对象紧密相关。
我们对于JS标识符解析的判断,存在一个常见误区
首先,看一个关于JS标识符解析的问题 ,源于风雪之隅提出的问题
var name = 'globalName';
function funcA() {
console.log(name);
var name = 'funAName';
console.log(name);
console.log(age);
}
funcA();
这段代码的运行结果是怎样的?
相信会有人跟我最初遇到这个问题时一样,以为结果会是这样:
globalName
funAName
[脚本错误: ReferenceError]
我们认为:在funA中, 第一次console.log的时候,会取到全局变量name的值'globalName', 而第二次值被局部变量name覆盖, 所以第二次console.log是'funAName'。 而age属性没有定义, 所以脚本会出错。
但是实际上,运行结果是这样的:
undefined
funAName
[脚本错误: ReferenceError]
为什么会这样呢?在JS中,标识符解析是沿作用域链一级一级地搜索标识符的过程,搜索过程始终从作用域链的前端开始,然后逐级地向后回溯,直到找到标识符为止(如果找不到标识符,通常会导致错误发生)。所以为了正确地判断标识符的解析结果,我们必须把作用域链原理弄清楚。
深入理解作用域原理能够为我们解密这个误区
作用域链(scope chain)的生成跟执行环境(execution context)、函数对象(function object)和活动对象(activation object)紧密相关。
执行环境
执行环境是JavaScript中最为重要的一个概念。执行函数定义了变量或函数有权访问的其它数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象(variable object)和一个作用域链(scope chain),环境中定义的所以变量和函数都保存在其变量对象中。执行环境分为两种,一种是全局执行环境,一种是函数执行环境。
全局执行环境
全局执行环境是最外围的一个执行环境,其变量对象就是全局活动对象(window activation object),全局执行环境直到应用程序退出——例如关闭网页或浏览器——时才会被销毁。
函数执行环境
每个函数都有自己的执行环境。当执行流进入一个函数时,函数环境就会被推入一个环境栈中。当函数执行完之后,栈将其环境弹出,把控制权返回给之前的执行环境。函数执行环境的变量对象是该函数的活动对象(activation object)。
作用域链
对于每一个执行环境,都会创建一个与之关联的作用域链。每个执行环境的作用域链的前端,始终都是该执行环境的变量对象,对于全局执行环境就相当于window对象,对于函数执行环境就相当于该函数的活动对象;对于全局执行环境,已经是根部,没有后续,对于函数执行环境,其作用域链的后续是该函数对象的[[scope]]属性里的作用域链。
函数对象
在一个函数定义的时候, 会创建一个这个函数对象的[[scope]]属性(内部属性,只有JS引擎可以访问, 但FireFox的几个引擎(SpiderMonkey和Rhino)提供了私有属性__parent__来访问它),并将这个[[scope]]属性指向定义它的作用域链上。 在这里的问题中,因为funcA定义在全局环境, 所以此时的[[scope]]只是指向全局活动对象window active object。
活动对象
在一个函数对象被调用的时候,会创建一个活动对象,首先将该函数的每个形参和实参,都添加为该活动对象的属性和值;将该函数体内显示声明的变量和函数,也添加为该活动的的属性(在刚进入该函数执行环境时,未赋值,所以值为undefined,这个是JS的提前声明机制)。
然后将这个活动对象做为该函数执行环境的作用域链的最前端,并将这个函数对象的[[scope]]属性里作用域链接入到该函数执行环境作用域链的后端。

现在让我们回到最初的问题
var name = 'globalName';
function funcA() {
//当funcA()被调用时,刚进入funcA的执行环境,其作用域链最前端的funA activation object里有name属性,值为undefined。
console.log(name);
var name = 'funAName';
console.log(name);
console.log(age);
}
funcA();
虽然感觉这个例子的误区跟JS提前声明机制的关系也很大,但是理解funA.[[scope]]属性的作用域链是funA定义时的作用域链,而不是被调用时的作用域链,对于看懂多层函数嵌套的情况下作用域链的坑,也是非常关键的。
JavaScript:理解执行环境、作用域链和活动对象的更多相关文章
- 深入理解javascript中执行环境(作用域)与作用域链
深入理解javascript中执行环境(作用域)与作用域链 相信很多初学者对与javascript中的执行环境与作用域链不能很好的理解,这里,我会按照自己的理解同大家一起分享. 一般情况下,我们把执行 ...
- javascript中函数的执行环境、作用域链、变量对象与活动对象
javascript高级程序设计中:对执行环境.作用域链.变量对象.活动对象的解释: 1.执行环境: 执行环境:有时也叫环境:是JavaScript中最为重要的一个概念:执行环境定义了变量或函数有权访 ...
- JavaScript之执行环境及作用域
执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为.每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中.我们编写的代码是无法访问这个对象的,但解 ...
- Javascript 的执行环境(execution context)和作用域(scope)及垃圾回收
执行环境有全局执行环境和函数执行环境之分,每次进入一个新执行环境,都会创建一个搜索变量和函数的作用域链.函数的局部环境不仅有权访问函数作用于中的变量,而且可以访问其外部环境,直到全局环境.全局执行环境 ...
- javascript中执行环境和作用域(js高程)
执行环境(execution context,为简单起见,有时也成为“环境”)是javascript中最为重要的一个概念.执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为.每个执行环境 ...
- Javascript手记-执行环境和作用域
执行环境是javascript一个重要的概念,执行环境定义了变量有权访问其他数据决定了他们各自的行为,每个执行环境 都有一个与之关联的变量,环境中定义的所有变量和函数都保存在这个对象中,虽然我们编写的 ...
- 从头开始学JavaScript (九)——执行环境和作用域
原文:从头开始学JavaScript (九)--执行环境和作用域 一.执行环境:定义了变量或者函数有权访问的其他数据,决定了它们各自的行为.每个执行环境都有与之关联的变量对象. 变量对象:保存着环境中 ...
- 【进阶2-2期】JavaScript深入之从作用域链理解闭包(转)
这是我在公众号(高级前端进阶)看到的文章,现在做笔记 https://github.com/yygmind/blog/issues/18 红宝书(p178)上对于闭包的定义:闭包是指有权访问另外一 ...
- JavaScript中执行环境和栈
在这篇文章中,我会深入理解JavaScript最根本的组成之一 : "执行环境(执行上下文)".文章结束后,你应该对解释器试图做什么,为什么一些函数/变量在未声明时就可以调用并且他 ...
随机推荐
- Django:Admin,Cookie,Session
一. Admin的配置 1.Admin基础设置 admin是django强大功能之一,它能够从数据库中读取数据,呈现在页面中,进行管理.默认情况下,它的功能已经非常强大,如果你不需要复杂的功能,它已经 ...
- OPENGL学习【一】VS2008开发OPENGL程序开发环境搭建
1.VS2008工具自行在网上下载安装,现只提供VS2008开发工具中配置OPENGL环境的详细步骤.开发包及编译工具会在下方一并放出链接. 2.打开CMake的工具,主要的配置信息如下,按照数字顺序 ...
- Bind for 0.0.0.0:80 failed: port is already allocated.解决方案
一句话总结就是容器占用的port还没有完全释放 查看进程,发现相关的容器并没有在运行,而 docker-proxy 却依然绑定着端口: $ docker ps 检查docker镜像 $ ps -aux ...
- HDU1846 - Brave Game【巴什博弈】
十年前读大学的时候,中国每年都要从国外引进一些电影大片,其中有一部电影就叫<勇敢者的游戏>(英文名称:Zathura),一直到现在,我依然对于电影中的部分电脑特技印象深刻. 今天,大家选 ...
- LINUX 中 VSFTPD安裝
VSFTPD 简写:vsftpd是very secure FTP daemon 的缩写,是一个完全免费的,开源代码的ftp服务器软件 特点:vsftpd是一款在LINUX发行版中最受推崇的FTP服务器 ...
- Mark一下:成为CSDN博客专家
距第一篇博客(发表于2015.08.13)已有差不多7个月,还记得当时受一个基友的启发,觉得要总结写作些什么,于是磕磕碰碰写出第一篇博客,坚持写作至今,穿梭于CSDN.简书.知乎和作业部落等门户网站, ...
- 加速 MySQL 导入导出的方法
http://www.21andy.com/new/20100917/1952.html MySQL导出的SQL语句在导入时有可能会非常非常慢,在处理百万级数据的时候,可能导入要花几小时.在导出时合理 ...
- R语言的帮助使用和图形功能简单介绍
R语言的帮助使用和图形功能简单介绍 R语言帮助,在Windows桌面下,有很多种.最长使用的是在命令行下help() > help.start() 会在浏览器中,打开帮助的主页 watermar ...
- Linux 网卡驱动学习(六)(应用层、tcp 层、ip 层、设备层和驱动层作用解析)
本文将介绍网络连接建立的过程.收发包流程,以及当中应用层.tcp层.ip层.设备层和驱动层各层发挥的作用. 1.应用层 对于使用socket进行网络连接的server端程序.我们会先调用socket函 ...
- Ambari-单步创建cluster
Ambari-单步创建 总体介绍 单步创建集群即对于集群内每个服务的安装.开启.组成服务的每个组件host信息的设置等操作都进行一次ambari-server的restAPI的调用. 这样做提高了对集 ...