执行上下文(execution context),是JS中的一个很重要的概念。它对于我们理解函数定义,执行时都做了什么有着很大的意义。理解它我们才能明白我们常说的函数声明提升,作用域链,闭包等原理。

  在解释之前,我们先来看看经常会看到这样一段代码。

console.log(a); //undefined
var a =1;

  这段代码我们都知道原因,也就是变量声明提升。

  再看下面一段代码

var a=10;

function b(){
console.log(a);//undefiend
var a=20;
} b();

可能会有人不明白,好像按照作用域链查找应该会是10而为什么还是undefine呢?要去解释这个问题,要去理解为什么变量会提升,我们还是要回到执行上下文中。

  行上下文存在于两种情景中,一段script脚本或者一个函数中。一段script脚本中,有全局上下文环境,在这个时候进行了变量的定义与函数的声明。在一个函数上下文环境中发生了什么,在下文中有分析。

  每一个执行上下文环境,都有一个与之对应的变量对象(variable object),我们也简称为VO。这个VO保存了一个执行上下文环境定义的所有的变量和函数。

VO:{

  变量,

  函数,

  arguments对象,

  参数

}.

一.上下文的创建过程发生了什么?

  上下文的创建过程可以分为两个阶段。

  1.上下文的建立阶段,即在一个函数被调用但是在执行该函数内部代码之前的这段时间。在这段时间中,上下文做了如下几件事。

  ①.建立函数,变量,arguments对象,参数。在这个时候除了arguments,函数声明,以及参数已被赋值,其他的变量属性都默认是undefined。如果没有传入参数,它也是undefined。

  ②建立作用域链,注意是作用域链而不是作用域。这是因为函数的作用域在定义它的时候就已经确定了。

  ③.确定this的值。

  2.代码的执行阶段。

  ①.变量赋值

  ②.函数引用

  ③.执行其它的代码。

  其实,这个时候把执行上下文理解成一个对象更直观。

  EC_Object={

  VO(变量对象):函数中的arguments对象,参数,内部变量以及函数,

  chain(作用域链):VO以及所有执行上下文中的VO,

  this:{}

}。

二.函数调用时发生了什么?

  每一个函数在被调用时,都有执行代码前,执行代码时,还有执行后这三个阶段。

  ①.执行代码前

  1.创建执行上下文,每一个函数在被调用时都会产生一个新的执行上下文环境。

  2.进入创建阶段。

  (1).建立VO对象

  ①.建立arguments对象,检查当前上下文中的参数。如果传入参数则给参数赋值,否则参数值为undefined。

  ②.检查当前上下文中的函数声明。每找到一个函数声明,就在VO下建立一个该函数名为属性名的属性值,该属性值就是指向该函数在内存中的地址的一个引用。如果函数名已经存在于VO中,则对应的属性值会被新的引用所覆盖。

  ③.检查当前上下文中的变量声明。每找到一个变量声明,就在VO下建立一个该变量名为属性名的属性值,属性值默认为undefied(注意:此时还没有赋值)。如果该变量名存在于VO中,则会直接跳过而不会覆盖。

function f(){
var a=10;
function a(){};
}
f();
VO:{
a:function(){},//函数名覆盖了变量名
arguments,
} function f(){
function a(){};
var a=10;
}
f();
VO:{
a:function(){},//变量名跳过了
arguments,
}

  (2)初始化作用域链。作用域中变量的值是在执行过程中产生而确定的,作用域却是在函数创建时就确定的。若要查找一个作用域下的某个变量的值,就要找到这个作用域对象的执行上下文,找到它的VO,再到其中去寻找变量的值。如果在该上下文环境没有找到,他会随着作用域链向上查找另一个上下文环境,找到该环境下的VO,直到全局环境,全局上下文环境中的VO始终是作用域链中的最后一个对象。

  (3)确定上下文中this的指向

  ②.执行代码时

  执行函数内部代码时,一步步运行,给VO中的变量属性赋值。

  ③.执行代码后

   当一个执行上下文环境中的代码执行完毕后,该环境会被销毁,保存在其中的所有变量和函数都会随之销毁。但是,有一个特殊情况,则是另一个我要去说明的问题——闭包。

了解了这么多。我们再回到之前提到的两段代码。

console.log(a);//undefiend
var a=1; //这个时候是全局执行环境,在执行代码前,该环境已经为a定义了,全局中的VO已经有了a这个变量属性,值默认为undefined。
因为代码是一行行进行的,所有第一行代码执行后,a其实已经定义了,值为undefined。这就是所谓的变量声明提升了。

第二段代码

var a=10;

function b(){
console.log(a);//undefiend
var a=20;
} b(); //在调用b函数,执行代码之前。创建了一个b函数的执行上下文环境。在该环境下,VO中也已经有了a这个变量属性,值是undefined,
此时在执行代码第一句时,已经在这个函数执行上下文中的VO中找到了a,而不用再到全局中的VO中去找。所有仍然是undefined。
这就是所谓的变量查找就近原则,是不是很好理解。

关于上下文的说明就这么多,如果发现问题,还希望大家能帮我及时纠正,多多交流。

关于作用域与闭包的问题,可以看下我的另一篇文章。

JS之执行上下文的更多相关文章

  1. js高级-执行上下文

    全局上下文  方法1() 压入 (栈的数据结构 先进后出)push()  pop() 1.当一个函数在调用另外一个函数的时候新调用的函数会行成一个新的执行上下文 压入执行环境栈的栈顶 2.浏览器js执 ...

  2. JS的执行上下文

    定义 执行上下文时是代码执行时的环境,JS代码在运行前进行编译,那么会生成两部分,一部分是可执行的代码,而另一部分则是执行上下文. 发展 执行上下文所包含的内容是在不断的变化的.它主要分为了三个不同的 ...

  3. 一文弄懂js的执行上下文与执行上下文栈

    目录 执行上下文与执行上下文栈 变量提升与函数提升 变量提升 函数提升 变量提升与函数提升的优先级 变量提升的一道题目引出var关键字与let关键字各自的特性 执行上下文 全局执行上下文 函数(局部) ...

  4. 进阶学习js中的执行上下文

    在js中的执行上下文,菜鸟入门基础 这篇文章中我们简单的讲解了js中的上下文,今天我们就更进一步的讲解js中的执行上下文. 1.当遇到变量名和函数名相同的问题. var a = 10; functio ...

  5. 深入理解JavaScript执行上下文、函数堆栈、提升的概念

    本文内容主要转载自以下两位作者的文章,如有侵权请联系我删除: https://feclub.cn/post/content/ec_ecs_hosting http://blog.csdn.net/hi ...

  6. 深入理解js——执行上下文

    什么是"执行上下文"?暂且不下定义,先看一段代码: 第一句报错,a未定义,很正常.第二句.第三句输出都是undefined,说明浏览器在执行console.log(a)时,已经知道 ...

  7. js执行上下文(由浅入深)

    每一个函数都有自己的执行上下文EC(执行环境 execution context),并且每个执行上下文中都有它自己的变量对象VO(Variable object),用于存储执行上下文中的变量 .函数声 ...

  8. 深入学习JS执行--创建执行上下文(变量对象,作用域链,this)

    一.介绍 本篇继上一篇深入理解js执行--单线程的JS,这次我们来深入了解js执行过程中的执行上下文. 本篇涉及到的名词:预执行,执行上下文,变量对象,活动对象,作用域链,this等 二.预执行 在上 ...

  9. Js 作用域与作用域链与执行上下文不得不说的故事 ⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄

    最近在研究Js,发现自己对作用域,作用域链,活动对象这几个概念,理解得不是很清楚,所以拜读了@田小计划大神的博客与其他文章,受益匪浅,写这篇随笔算是自己的读书笔记吧~. 作用域 首先明确一个概念,js ...

随机推荐

  1. IIS下发布关于Excel导入导出时遇到的问题集锦(转)

    问题描述 1.Excel每个工作薄(sheet)生成记录行数 2.asp.net关于导出Excel的一些问题的集锦 3.下载失败,临时文件或其所在磁盘不可写 4.未能加载文件或程序集“Microsof ...

  2. [Java][Servlet] Cannot call sendRedirect() after the response has been committed

    做一个Login Demo的时候,写了如下代码: protected void doPost(HttpServletRequest request, HttpServletResponse respo ...

  3. ios 你必须了解的系统定义宏使用

    1. UNAVAILABLE_ATTRIBUTE __attribute__((unavailable)) - (instancetype)init UNAVAILABLE_ATTRIBUTE; 告诉 ...

  4. 在CentOS上配置Tomcat服务脚本

    #!/bin/bash # chkconfig: - 85 15 # description: Tomcat Server basic start/shutdown script # processn ...

  5. python随笔--根据号码查询归属地

    给定一组(串)数据,根据输入得号码,查询归属地 def num_info(num): info0 = """5583|1860100|010|北京市|北京联通GSM卡 5 ...

  6. Lync二次开发关于Lync启动退出问题

    以前使用C++开发的version.dll文件,由于各个用户环境的不同,造成某些用户加载不了我们开发的插件,并且写version.dll的同事还没找到好的解决办法,所以得换一种思路去解决这个问题,就是 ...

  7. ndk制作so库,ndk-build不是内部或外部命令。。。的错误

    想了想大概就需要下面这几步: 1.下载ndk 2.配置ndk的环境变量 3.在android studio添加一些ndk的配置 4.编写c文件 5.生成so库 6.调用so库 上面提到的大部分问题你都 ...

  8. 最小正子序列(序列之和最小,同时满足和值要最小)(数据结构与算法分析——C语言描述第二章习题2.12第二问)

    #include "stdio.h" #include "stdlib.h" #define random(x) (rand()%x) void creat_a ...

  9. Oracle 数据库自动备份方案

    1.新建 backup.bat脚本 @echo off echo ================================================ echo Windows环境下Ora ...

  10. php的yii框架开发总结5

    MVC架构之model类: 我的日报系统用到的数据表:tbl_dailyreport表 其中anthor_id是外键,对应tbl_user数据表的主键id,下面是tbl_user表 class Dai ...