【repost】 原生JS执行环境与作用域深入理解
首先,我们要知道执行环境和作用域是两个完全不同的概念。
函数的每次调用都有与之紧密相关的作用域和执行环境。从根本上来说,作用域是基于函数的,而执行环境是基于对象的(例如:全局执行环境即window对象)。
换句话说,作用域涉及到所被调用函数中的变量访问,并且不同的调用场景是不一样的。执行环境始终是this关键字的值,它是拥有当前所执行代码的对象的引用。每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。虽然我们编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它。
执行环境(也称执行上下文–execution context)
当JavaScript解释器初始化执行代码时,它首先默认进入全局执行环境,从此刻开始,函数的每次调用都会创建一个新的执行环境。
每个函数都有自己的执行环境。当执行流进入一个函数时,函数的环境就会被推入一个环境栈中(execution stack)。在函数执行完后,栈将其环境弹出,把控制权返回给之前的执行环境。ECMAScript程序中的执行流正是由这个便利的机制控制着。
执行环境可以分为创建和执行两个阶段。在创建阶段,解析器首先会创建一个变量对象(variable object,也称为活动对象 activation object),它由定义在执行环境中的变量、函数声明、和参数组成。在这个阶段,作用域链会被初始化,this的值也会被最终确定。在执行阶段,代码被解释执行。
Demo:
<script type="text/javascript">
function Fn1(){
function Fn2(){
alert(document.body.tagName);//BODY
//other code...
}
Fn2();
}
Fn1();
//code here
</script>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
特别说明:图片来自于笨蛋的座右铭博客
小结
当javascript代码被浏览器载入后,默认最先进入的是一个全局执行环境。当在全局执行环境中调用执行一个函数时,程序流就进入该被调用函数内,此时JS引擎就会为该函数创建一个新的执行环境,并且将其压入到执行环境堆栈的顶部。浏览器总是执行当前在堆栈顶部的执行环境,一旦执行完毕,该执行环境就会从堆栈顶部被弹出,然后,进入其下的执行环境执行代码。这样,堆栈中的执行环境就会被依次执行并且弹出堆栈,直到回到全局执行环境。
此外还要注意一下几点:
- 单线程
- 同步执行
- 唯一的全局执行环境
- 局部执行环境的个数没有限制
- 每次某个函数被调用,就会有个新的局部执行环境为其创建,即使是多次调用的自身函数(即一个函数被调用多次,也会创建多个不同的局部执行环境)。
作用域
当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain)。作用域链的用途是保证对执行环境有权访问的所有变量和函数的有序访问。
作用域链包含了执行环境栈中的每个执行环境对应的变量对象。通过作用域链,可以决定变量的访问和标识符的解析。
注意:全局执行环境的变量对象始终都是作用域链的最后一个对象。
在访问变量时,就必须存在一个可见性的问题(内层环境可以访问外层中的变量和函数,而外层环境不能访问内层的变量和函数)。更深入的说,当访问一个变量或调用一个函数时,JavaScript引擎将不同执行环境中的变量对象按照规则构建一个链表,在访问一个变量时,先在链表的第一个变量对象上查找,如果没有找到则继续在第二个变量对象上查找,直到搜索到全局执行环境的变量对象即window对象。这也就形成了Scope Chain的概念。
特别说明:图片来自于笨蛋的座右铭博客
作用域链图,清楚的表达了执行环境与作用域的关系(一一对应的关系),作用域与作用域之间的关系(链表结构,由上至下的关系)。
Demo:
var color = "blue";
function changeColor(){
var anotherColor = "red";
function swapColors(){
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
// 这里可以访问color, anotherColor, 和 tempColor
}
// 这里可以访问color 和 anotherColor,但是不能访问 tempColor
swapColors();
}
changeColor();
// 这里只能访问color
console.log("Color is now " + color);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
上述代码一共包括三个执行环境:全局执行环境、changeColor()的局部执行环境、swapColors()的局部执行环境。
- 全局环境有一个变量color和一个函数changecolor();
- changecolor()函数的局部环境中具有一个anothercolor属性和一个swapcolors函数,当然,changecolor函数中可以访问自身以及它外围(即全局环境)中的变量;
- swapcolor()函数的局部环境中具有一个变量tempcolor。在该函数内部可以访问上面的两个环境(changecolor和window)中的所有变量,因为那两个环境都是它的父执行环境。
上述代码的作用域链如下图所示:
从上图发现。内部环境可以通过作用域链访问所有的外部环境,但是外部环境不能访问内部环境中的任何变量和函数。
标识符解析(变量名或函数名搜索)是沿着作用域链一级一级地搜索标识符的过程。搜索过程始终从作用域链的前端开始,然后逐级地向后(全局执行环境)回溯,直到找到标识符为止。
执行环境与作用域的区别与联系
执行环境为全局执行环境和局部执行环境,局部执行环境是函数执行过程中创建的。
作用域链是基于执行环境的变量对象的,由所有执行环境的变量对象(对于函数而言是活动对象,因为在函数执行环境中,变量对象是不能直接访问的,此时由活动对象(activation object,缩写为AO)扮演VO(变量对象)的角色。)共同组成。
当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途:是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执行的代码所在环境的变量对象。
小练习
<script type="text/javascript">
(function(){
a= 5;
console.log(window.a);//undefined
var a = 1;//这里会发生变量声明提升
console.log(a);//1
})();
</script>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
window.a之所以是undefined,是因为var a = 1;发生了变量声明提升。相当于如下代码:
<script type="text/javascript">
(function(){
var a;//a是局部变量
a = 5;//这里局部环境中有a,就不会找全局中的
console.log(window.a);//undefined
a = 1;//这里会发生变量声明提升
console.log(a);//1
})();
</script>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
参考博文:
图解Javascript上下文与作用域
理解JavaScript中的作用域和上下文
JavaScript的执行上下文
深入理解javascript之执行上下文
执行环境,作用域
from:http://blog.csdn.net/liujie19901217/article/details/52225025
【repost】 原生JS执行环境与作用域深入理解的更多相关文章
- js执行环境、作用域
js执行环境.作用域 执行环境:是javascript中的一个重要的概念,<javascript高级程序设计第三版>的定义是:执行环境定义了变量或函数有权访问的其他数据,决定了他们各自的行 ...
- JS执行环境,作用域链及非块状作用域
JS中的执行环境,顾名思义就是变量或函数所执行时的环境.在我的理解中,执行环境和作用域相差不大. 每个函数都有自己的执行环境,当执行流进入一个函数时,函数的环境就会被推入一个环境栈中.而在函数执行之后 ...
- 浅谈JS执行环境及作用域
今天刚刚开通博客,也是第一次写博文,略感紧张.作为一个表达能力弱弱的人来说,自己花三分钟理解一个知识点,当别人问起时,也许需要30分钟才只是让别人知道自己在说什么,一点也不夸张,希望在博客上可以练习 ...
- JS 执行环境与作用域链
1.执行环境 JavaScript 代码都是在执行环境中被执行的.执行环境是一个概念,一种机制,用来完成JavaScript运行时在作用域.生命周期等方面的处理,它定义了变量或函数是否有权访问其他数据 ...
- 【原】javascript执行环境及作用域
最近在重读<javascript高级程序设计3>,觉得应该写一些博客记录一下学习的一些知识,不然都忘光啦.今天要总结的是js执行环境和作用域. 首先来说一下执行环境 一.执行环境 书上概念 ...
- js中的执行环境及作用域
最近在面试时被问到了对作用域链的理解,感觉当时回答的不是很好,今天就来说说js中的作用域链吧. 首先来说说js中的执行环境,所谓执行环境(有时也称环境)它是JavaScript中最为重要的一个概念.执 ...
- js的执行环境及作用域
主要的是执行环境和作用域链. 执行环境 执行环境定义了变量或函数有权访问的其他数据,每个函数都有一个执行环境,每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个变量对象中, ...
- js中的执行环境和作用域链
首先介绍一些即将用到的概念: 执行环境: 它定义了变量和函数有权访问其他数据的范围,每一个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个变量对象中. 所有javasc ...
- JavaScript之一: 闭包、执行环境、作用域链
这是大虾的第一篇博文,大虾试图用最直白的语言去描述出所理解的东西,大虾是菜鸟,水平有限,有误的地方希望路过的朋友们务必指正,谢谢大家了. 从读书时代一路走来,大虾在学习的时候逐渐喜欢上了去追寻根源,这 ...
随机推荐
- IDEA安装小配置
1. view-->toolbar+toolbuttons 2. 根据大小写IDEA能准确提示 配置自动导入包 定义代码模板 提示忽略大小写 配置虚拟机内存,修改idea64.exe.vmopt ...
- 当时钟事件声明为过程变量 让system.threading.timer时钟失效
这个项目的小模块就是画label 控件到tablepayoutpanel表单 之中, 中间用到了时钟,事件(带返回值的),哈希表 .由于时钟定义在 form1的启动构造函数中导致了form1,启动完毕 ...
- export export defalut
require/exports 和 import/export 形式不一样 require/exports 的用法只有以下三种简单的写法: const fs = require('fs') expor ...
- Codeforces 767B. The Queue 模拟题
B. The Queue time limit per test:1 second memory limit per test:256 megabytes input:standard input o ...
- cron Linux下的定时执行工具
说明:测试平台 Ubuntu 16.04.4 LTS cron是一个Linux下的定时执行工具,可以在无需人工干预的情况下运行作业.所以,在Linux中,周期性执行的任务一般由cron这个守护进程来 ...
- java 内存, 类加载g
1. java 内存区域 方法区 虚拟机栈 本地方法栈 堆 程序计数器 其中 : 方法区 和 堆 是所有线程共享的 , 其他是线程隔离的 1. 程序计数器 : 可以看做是当前线程所执行的字节码的 ...
- callable与runable区别?switch char ?sql只查是否存在,sql复制表 ?反射 ? spring mvc 和spring 上下文区别?
中化技术部 2018.4.16 1. callable 和 thread 区别 实现Callable接口的线程能返回执行结果,而Runable 不可以 . Callable 的call方法允许抛出异 ...
- mybatis 一次执行多条语句
现在的一些互联网应用 为了提高性能,现在一般比较少的使用外键.不是不用,只是在创建数据库不标明外键关系,用程序去维护. 为了维护数据一致性,我们需要手动完成相关数据的删除 比如用户和用户的关注 当用户 ...
- pkg_resources.DistributionNotFound: The 'catkin-pkg==0.4.9' distribution was not found
个人感觉是python2与python3在ros中的差异导致的, 问题一:Traceback (most recent call last): File "/usr/bin/rosdep& ...
- Elastix 安装G729 G723语音编码
下載適合自己機器及軟體版本的模組檔,基本上略分為 pentium/pentium2/pentium3/x86_64,Asterisk 1.2/1.4/1.6.前往 http://asterisk.ho ...