Javascript执行流总结
面对各种各样的JavaScript代码,我们有时候难免会犯错。可当自己仔细研究一下,哦原来是这么回事。有时候怎么会想为什么Javascript程序会是这样执行的呢?为什么没有得到自己预期的答案呢?自己到底是哪一步想错了呢?这时候就想如果我是JS执行流我会怎么执行?仔细想想这些问题,原来这其中还包含着很多自己不熟悉的知识点,今天就来总结下,同时也好加深印象。
首先我们来熟悉几个名称:
- 执行上下文栈(Execution Context Stack)
每一种代码的执行都需要依赖自身的上下文。函数的每一次调用,都会进入函数执行中的上下文,并且来计算函数中变量等的值。一个执行上下文可以激活另一个上下文,就好比一个函数调用了另一个函数(或者全局的上下文调用了一个全局函数),然后一层一层调用下去。逻辑上来说,这种实现方式是栈,我们可以称之为上下文堆栈。
激活其它上下文的某个上下文被称为 调用者(caller) 。被激活的上下文被称为被调用者(callee) 。当一个caller激活了一个callee,那么这个caller就会暂停它自身的执行,然后将控制权交给这个callee. 于是这个callee被放入堆栈,称为进行中的上下文[running/active execution context]. 当这个callee的上下文结束之后,会把控制权再次交给它的caller,然后caller会在刚才暂停的地方继续执行。在这个caller结束之后,会继续触发其他的上下文。一个callee可以用返回(return)或者抛出异常(exception)来结束自身的上下文。
当一段程序开始时,会先进入全局执行上下文环境[global execution context], 这个也是堆栈中最底部的元素。此全局程序会开始初始化,初始化生成必要的对象[objects]和函数[functions]. 在此全局上下文执行的过程中,它可能会激活一些方法(当然是已经初始化过的),然后进入他们的上下文环境,然后将新的元素压入堆栈。在这些初始化都结束之后,这个系统会等待一些事件(例如用户的鼠标点击等),会触发一些方法,然后进入一个新的上下文环境。ECMAScript运行时系统就是这样管理代码的执行。 - 执行上下文(Execution Context)
一个执行的上下文可以抽象的理解为object。每一个执行的上下文都有一系列的属性(变量对象(variable object),this指针(this value),作用域链(scope chain) ) - 变量对象(variable object)
变量对象是与执行上下文相关的 数据作用域(scope of data) 。它是与上下文关联的特殊对象,用于存储被定义在上下文中的变量(variables)和函数声明(function declarations) 。 - 活动对象(activation object)
在一个函数上下文中,变量对象被表示为活动对象。它包含变量(variables)和函数声明(function declarations) 普通参数(形参) 与特殊参数(arguments)对象(具有索引属性的参数映射表)。
知道了这几个名称后我们拿几个实例来分一下Javascript到底是如何执行的?
if (!("a" in window)) {
var a = 1;
}
alert(a);
这里如果不加思考,想当然的认为如果window不包含属性a,就声明一个变量a,然后赋值为1。所以答案为1。
可是正确答案是undefined,再仔细想想为什么?如果你就是JS程序你会如何运行?
详细分析:
当一段程序开始时,会先进入全局执行上下文环境并初始化生成必要的对象,在全局执行上下文环境中申明了变量a,根据变量声明提升,此时该上下文环境中的变量对象VO = {a:undefined}(全局上下文中VO还包括其他对象如Math,Date等对此题不构成影响,暂不考虑)。全局上下文环境初始化好后开始执行代码,首先判断变量a是否属于window对象,我们知道变量a已经在window对象中,所以,if条件语句不会被执行,直接执行alert,
该题可简化为:
var a;
if (!("a" in window)) {
a = 1;
}
alert(a); //undefined
第二题
function a(x) {
return x * 2;
}
var a;
alert(a);
我们知道变量对象中及包括函数声明也包括变量申明,在此题中有同名的函数和变量,此时函数声明会覆盖变量声明。但不会覆盖已经赋值的同名变量声明。所以此题中最后结果是函数
第三题
function b(x, y, a) {
arguments[2] = 10;
alert(a);
}
b(1, 2, 3);
在此题中,b函数被激活会开辟一个新的内存栈并添加到执行上下文栈中,执行流进入b函数上下文,此时变量对象表示为活动对象
AO = {
x : 1,
y : 2,
a : 3,
arguments:{0:1,1:2,2:3}
}
Arguments对象是活动对象的一个属性,它包括如下属性:
- callee — 指向当前函数的引用
- length — 真正传递的参数个数
- properties-indexes (字符串类型的整数) 属性的值就是函数的参数值(按参数列表从左到右排列)。 properties-indexes内部元素的个数等于arguments.length. properties-indexes的值和实际传递进来的参数之间是共享的。这个共享其实不是真正的共享一个内存地址,而是2个不同的内存地址,使用JavaScript引擎来保证2个值是随时一样的.
所以当代码执行到arguments[2] = 10;时a也会变为10。
参考文献:
Javascript执行流总结的更多相关文章
- 一份最贴近真实面试的Java基础面试题
这是一份Java基础知识的面试题.在网上的关于Java的面试题数不胜数,但认真看过感觉大多数都没有实用性,有很多是面试官根本就不会问到的,那些已经脱离了实际开发的技术问题.而这份资料来源自一份个人觉得 ...
- 一份贴近真实面试的Java面试题(基础部分)
这是一份关于Java基础的面试题.在网上的关于Java的面试题数不胜数,但本人认真看过后觉得大多数都没有实用性,有很多是面试官根本就不会问到的,企业根本不会用到的,一些已经脱离了实际开发的技术问题.而 ...
- Javascript 的执行环境(execution context)和作用域(scope)及垃圾回收
执行环境有全局执行环境和函数执行环境之分,每次进入一个新执行环境,都会创建一个搜索变量和函数的作用域链.函数的局部环境不仅有权访问函数作用于中的变量,而且可以访问其外部环境,直到全局环境.全局执行环境 ...
- JavaScript 中的数据类型
Javascript中的数据类型有以下几种情况: 基本类型:string,number,boolean 特殊类型:undefined,null 引用类型:Object,Function,Date,Ar ...
- 《高性能javascript》一书要点和延伸(上)
前些天收到了HTML5中国送来的<高性能javascript>一书,便打算将其做为假期消遣,顺便也写篇文章记录下书中一些要点. 个人觉得本书很值得中低级别的前端朋友阅读,会有很多意想不到的 ...
- javascript的垃圾收集机制
× 目录 [1]原理 [2]标记清除 [3]引用计数[4]性能问题[5]内存管理 前面的话 javascript具有自动垃圾收集机制,执行环境会负责管理代码执行过程中使用的内存.在编写javascri ...
- 深入理解javascript作用域系列第五篇——一张图理解执行环境和作用域
× 目录 [1]图示 [2]概念 [3]说明[4]总结 前面的话 对于执行环境(execution context)和作用域(scope)并不容易区分,甚至很多人认为它们就是一回事,只是高程和犀牛书关 ...
- JavaScript作用域链
之前写过一篇JavaScript 闭包究竟是什么的文章理解闭包,觉得写得很清晰,可以简单理解闭包产生原因,但看评论都在说了解了作用域链和活动对象才能真正理解闭包,起初不以为然,后来在跟公司同事交流的时 ...
- Professional JavaScript for Web Developers 3rd Edition ---读书笔记
1. DOMContentLoaded DOM树构建完成时触发该事件 load 页面加载完毕触发 原生js document.addEventListener('DOMContentLoaded', ...
随机推荐
- Git for Windows之推送本地版本库到远程仓库
Git for Windows之基础环境搭建与基础操作中介绍了Git基本环境的构建与基本的操作.生成了一个本地git版本库,本文将介绍如何将这个版本库推送到远程仓库(码云,github也可以). 1. ...
- css实现图片垂直居中
1.行高 == 高度:已知图片的高宽 <div style="text-align: center; width: 500px;height:200px; line-height:20 ...
- SpringSecurity学习之快速上手
互联网项目中,安全与权限控制是不可回避的问题,为了解决这一些列问题,许多安全框架应运而生了.这些框架旨在帮我们解决公用的安全问题,让我们的程序更加健壮,从而让程序员全身心投入到业务开发当中.那么Spr ...
- Mysql大数据表优化处理
原文链接: https://segmentfault.com/a/1190000006158186 当MySQL单表记录数过大时,增删改查性能都会急剧下降,可以参考以下步骤来优化: 单表优化 除非单表 ...
- JAVA多态计算面积main函数调用方法
public static void main(String[] args) { Shape shape; Scanner input = new Scanner(System.in); System ...
- JDK8简化if-else
简化if-else 1234567891011 User user = ...if (user != null) { String userName = user.getUserName(); if ...
- Java之建造者模式(Builder Pattern)(转)
1.概念 将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示. [构建与表示分离,同构建不同表示] 与抽象工厂的区别:在建造者模式里,有个指导者,由指导者来管理建造者,用户是与指导者 ...
- VS和Eclipse的调试功能哪个更强大?
以前一直用VS 2012来调试C/C++代码,F5.F10.F11用起来甚是顺手,前面也写过一篇关于VS最好用的快捷键:Visual Studio最好用的快捷键(你最喜欢哪个), 所以对于调试C/C+ ...
- layer插件学习——询问框
本文是自己整理的关于layer插件的询问框样式结果 一.准备工作 下载jQuery插件和layer插件,并引入插件(注意:jQuery插件必须在layer插件之前引用) 百度云资源链接: jQuery ...
- Java中数据类型转换大全(个人总结)
一.字符串转换为其他类型 1.将字符串转化为int型 (1)方法一 int i = Integer.parseInt(String str); (2)方法二 int i = Integer.value ...