首先,我们要知道执行环境和作用域是两个完全不同的概念。 
函数的每次调用都有与之紧密相关的作用域和执行环境。从根本上来说,作用域是基于函数的,而执行环境是基于对象的(例如:全局执行环境即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执行环境与作用域深入理解的更多相关文章

  1. js执行环境、作用域

    js执行环境.作用域 执行环境:是javascript中的一个重要的概念,<javascript高级程序设计第三版>的定义是:执行环境定义了变量或函数有权访问的其他数据,决定了他们各自的行 ...

  2. JS执行环境,作用域链及非块状作用域

    JS中的执行环境,顾名思义就是变量或函数所执行时的环境.在我的理解中,执行环境和作用域相差不大. 每个函数都有自己的执行环境,当执行流进入一个函数时,函数的环境就会被推入一个环境栈中.而在函数执行之后 ...

  3. 浅谈JS执行环境及作用域

     今天刚刚开通博客,也是第一次写博文,略感紧张.作为一个表达能力弱弱的人来说,自己花三分钟理解一个知识点,当别人问起时,也许需要30分钟才只是让别人知道自己在说什么,一点也不夸张,希望在博客上可以练习 ...

  4. JS 执行环境与作用域链

    1.执行环境 JavaScript 代码都是在执行环境中被执行的.执行环境是一个概念,一种机制,用来完成JavaScript运行时在作用域.生命周期等方面的处理,它定义了变量或函数是否有权访问其他数据 ...

  5. 【原】javascript执行环境及作用域

    最近在重读<javascript高级程序设计3>,觉得应该写一些博客记录一下学习的一些知识,不然都忘光啦.今天要总结的是js执行环境和作用域. 首先来说一下执行环境 一.执行环境 书上概念 ...

  6. js中的执行环境及作用域

    最近在面试时被问到了对作用域链的理解,感觉当时回答的不是很好,今天就来说说js中的作用域链吧. 首先来说说js中的执行环境,所谓执行环境(有时也称环境)它是JavaScript中最为重要的一个概念.执 ...

  7. js的执行环境及作用域

    主要的是执行环境和作用域链. 执行环境 执行环境定义了变量或函数有权访问的其他数据,每个函数都有一个执行环境,每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个变量对象中, ...

  8. js中的执行环境和作用域链

    首先介绍一些即将用到的概念: 执行环境:  它定义了变量和函数有权访问其他数据的范围,每一个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个变量对象中.   所有javasc ...

  9. JavaScript之一: 闭包、执行环境、作用域链

    这是大虾的第一篇博文,大虾试图用最直白的语言去描述出所理解的东西,大虾是菜鸟,水平有限,有误的地方希望路过的朋友们务必指正,谢谢大家了. 从读书时代一路走来,大虾在学习的时候逐渐喜欢上了去追寻根源,这 ...

随机推荐

  1. localstorage和vue结合使用

    父组件 <template> <div class="hello"> <p>Original message:"{{message}} ...

  2. windbg 加载dump监测蓝屏原因时出现重复的星星框提示解决办法

    加载dump文件出现了重复上边的信息 总结: 要reload一下环境,说明符号库未加载出现的错误,!sym noisy 显示详细信息 ,reload重载符号库,未找到的,从服务器进行下载, 注意,第一 ...

  3. Oracle_SQL(7) 复杂查询

    1.rownum 伪列<,<=select * from emp where rownum<5; 取工资前3名的人员 select * from (select * from emp ...

  4. 织梦替换百度编辑器后栏目内容、单页无法保存bug修复

    找了一些教程是错的,这个测试过是正确的. 修改后台文件dede>templets>catalog_add.htm和catalog_edit.htm 一.在catalog_add.htm大概 ...

  5. oracle 直接复制表内容到新表

    不知道为什么,刚建的oracle数据库删除数据很慢,表里面有120多万数据,非常地慢 于是采用的复制的方法,命令如下: create table students_backup as select * ...

  6. 公共的service接口

    package com.taotao.manager.service; import java.util.List; /** * @author Administrator * * @param &l ...

  7. redis 数据类型为string命令整理以及示例

    #设置值 SET key value [EX seconds] [PX milliseconds] [NX|XX] SET命令加上选项已经可以完全取代SETNX, SETEX, PSETEX的功能,所 ...

  8. 开源项目CircleImageView

    1.在自己MainActivity所在包下创建CircleImageView.class文件 package 自己包名; import android.content.Context; import ...

  9. less 官网讲解 ( http://www.bootcss.com/p/lesscss/ )

    变量 变量允许我们单独定义一系列通用的样式,然后在需要的时候去调用.所以在做全局样式调整的时候我们可能只需要修改几行代码就可以了. // LESS @color: #4D926F; #header { ...

  10. POJ2230 Watchcow

    原题链接 类欧拉回路,要求每条边被正反各经过一次,且从\(1\)出发并回到\(1\). 只需每次搜索该点的边时,将该点的边对应的邻接表头及时修改为下一条即可,因为邻接表恰好储存了正反方向的边,所以及时 ...