执行上下文(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. Spring-cloud微服务 Eureka学习教程-单服务器配置之快速搭建EurekaServer、EurekaClient(基础)

    以下实例代码下载地址:https://github.com/wades2/EurekaDemo Eureka是Spring Cloud Netflix的一个子模块,也是核心模块之一.用于云端服务发现, ...

  2. spring mvc 与Struts的认识

    首先,纠正一个概念上的错误.ssh一般意义上是指 struts,spring framework以及hibernate.这三个框架作用是不一样的.hibernate主要是用于持久层,struts主要是 ...

  3. (十)JavaScript之【DOM定义】

    DOM定义Document Object Model 文档对象模型 是干什么的?改变 HTML 元素的内容 (innerHTML)改变 HTML 元素的样式 (CSS)改变 HTML 元素的属性对 H ...

  4. Java学习笔记——集合

    类集简介 从JDK1.2开始Java引入了类集开发框架,所谓的类集指的就是一套动态对象数组的实现方案,在实际开发之中没有有何一项开发可以离开数组,但是传统的数组实现起来非常的繁琐.而且长度是其致命伤, ...

  5. 聪明的Azure CDN,帮你找到云端捷径

    你知道吗?身处上海和纽约的两个用户同时通过网络收看“春晚”直播,纽约播放得可能比上海还要更流畅,这当然不是因为纽约距离北京的直播机房更近或者网速更快,而是因为大年夜在大洋彼岸围观“春晚”的观众相对较少 ...

  6. eclipse:maven工程下显示不出文件,但系统存在,可能是这个原因

  7. 科大讯飞语音转文字以及中文分词的Java测试代码

    我录了一段音存储在这个test.m4a文件里,语音内容为"测试一下Netweaver对于并发请求的响应性能". 使用如下Java代码进行测试: package com.iflyte ...

  8. Javascript作业—数字转化为大写

    开始学javascript,写作业. <script type="text/javascript"> function toChinese(money){ var ch ...

  9. UESTC 1246 拆x3

    用归纳法分析可以知道死循环只有4. 分析一下复杂度,如果n很大并且不是素数,根据基本不等式可以知道 sum factor(n) ≥ 2+n/2 ≍ n/2. 复杂度是O(T*logN*sqrt(N)) ...

  10. 进程—内存描述符(mm_struct)

    http://blog.csdn.net/qq_26768741/article/details/54375524 前言 上一篇我们谈论了task_struct这个结构体,它被叫做进程描述符,内部成员 ...