JS之执行上下文
执行上下文(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之执行上下文的更多相关文章
- js高级-执行上下文
全局上下文 方法1() 压入 (栈的数据结构 先进后出)push() pop() 1.当一个函数在调用另外一个函数的时候新调用的函数会行成一个新的执行上下文 压入执行环境栈的栈顶 2.浏览器js执 ...
- JS的执行上下文
定义 执行上下文时是代码执行时的环境,JS代码在运行前进行编译,那么会生成两部分,一部分是可执行的代码,而另一部分则是执行上下文. 发展 执行上下文所包含的内容是在不断的变化的.它主要分为了三个不同的 ...
- 一文弄懂js的执行上下文与执行上下文栈
目录 执行上下文与执行上下文栈 变量提升与函数提升 变量提升 函数提升 变量提升与函数提升的优先级 变量提升的一道题目引出var关键字与let关键字各自的特性 执行上下文 全局执行上下文 函数(局部) ...
- 进阶学习js中的执行上下文
在js中的执行上下文,菜鸟入门基础 这篇文章中我们简单的讲解了js中的上下文,今天我们就更进一步的讲解js中的执行上下文. 1.当遇到变量名和函数名相同的问题. var a = 10; functio ...
- 深入理解JavaScript执行上下文、函数堆栈、提升的概念
本文内容主要转载自以下两位作者的文章,如有侵权请联系我删除: https://feclub.cn/post/content/ec_ecs_hosting http://blog.csdn.net/hi ...
- 深入理解js——执行上下文
什么是"执行上下文"?暂且不下定义,先看一段代码: 第一句报错,a未定义,很正常.第二句.第三句输出都是undefined,说明浏览器在执行console.log(a)时,已经知道 ...
- js执行上下文(由浅入深)
每一个函数都有自己的执行上下文EC(执行环境 execution context),并且每个执行上下文中都有它自己的变量对象VO(Variable object),用于存储执行上下文中的变量 .函数声 ...
- 深入学习JS执行--创建执行上下文(变量对象,作用域链,this)
一.介绍 本篇继上一篇深入理解js执行--单线程的JS,这次我们来深入了解js执行过程中的执行上下文. 本篇涉及到的名词:预执行,执行上下文,变量对象,活动对象,作用域链,this等 二.预执行 在上 ...
- Js 作用域与作用域链与执行上下文不得不说的故事 ⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄
最近在研究Js,发现自己对作用域,作用域链,活动对象这几个概念,理解得不是很清楚,所以拜读了@田小计划大神的博客与其他文章,受益匪浅,写这篇随笔算是自己的读书笔记吧~. 作用域 首先明确一个概念,js ...
随机推荐
- spring-boot学习之属性配置
通过@value注解,将配置文件中的内容引入
- CSS中的样式层叠机制Cascade
CSS中的样式层叠机制Cascade 一.样式冲突 样式冲突是CSS渲染过程要解决的一个关键问题,样式冲突主要由两个原因造成: 元素包含了不同对象所赋予的样式:浏览器.用户.作者.其中,浏览器样式 ...
- laravel的nginx配置
最近阅读laravel官方文档 发现了关于nginx的推荐配置 Nginx 如果你使用 Nginx ,在你的网站配置中加入下述代码将会转发所有的请求到 index.php 前端控制器. locatio ...
- Oracle的oci.dll加载错误解决办法
开始 -> 程序 -> Oracle -> Configuration and Migration Tools -> Net Manager→本地→概要文件→Oracle高级安 ...
- Trouble Shooting的一些感想(实时补充)
最近一直做两个产品功能的Merge工作,代码Merge过来之后,发现了很多问题.经过Trouble Shooting,最终发现归根结底都是我们Merge的问题,例如有的Code没有Merge过来,Me ...
- Active Directory域服务备份
此篇介绍如何通过Windows Server Backup工具备份Active Directory域服务 AD 域系统状态 在域控制器上,系统状态通常包括以下内容,但所包含的数据实际上取决于服务器上安 ...
- EasyUI手风琴 Tab卡使用
--案例项目代码,初始化手风琴,定义打开Tab的方法. $(result).each(function () { //m_pi_jscode,pi_jscode if (m_pi_id != this ...
- *205. Isomorphic Strings (string & map idea)
Given two strings s and t, determine if they are isomorphic. Two strings are isomorphic if the chara ...
- iOS逆向命令集
越狱命令行 破壳: 10.10.215.119 ssh root@10.10.215.119 ssh root@10.10.213.176 CCBMobileBank Fuqianlade-iPhon ...
- 【洛谷4459】[BJOI2018] 双人猜数游戏(动态规划)
点此看题面 大致题意: 一直有两个数\(m,n\),已知\(s\le m\le n\),且\(Alice\)和\(Bob\)二个"最强大佬"各知道\(mn\)和\(m+n\).每轮 ...