深入理解javascript的作用域--函数声明为什么会前置
来源:互联网 发布:linux系统模拟下载 编辑:程序博客网 时间:2024/04/30 21:01
这篇博文解决了以下迷惑
- 函数声明为什么前置
- 函数声明前置和变量前置优先级问题
- 为什么js文件开头就可以使用Math,String等库,而不需要导入头文件
1.变量对象VO
变量对象(Variable Object, 缩写为VO)是一个抽象
概念中的“对象”,它用于存储执行上下文中的:
1. 变量
2. 函数声明
3. 函数参数
js解释器就是通过变量对象(VO)来找到我们定义的变量和函数的。
举个例子:
var a = 10;function test(x) {var b = 20;}test(30);
针对例子的浏览器js引擎的VO记录:
//全局作用域VO(globalContext) = {a : 10,//变量test : <ref to function>//函数声明};//test函数的函数作用域VO(test functionContext) = {x : 30,//函数参数b: 20//函数声明};
2.js开头不需要加入头文件谜解
在js代码执行前,js引擎为我们初始化了如下全局作用域的VO。
在全局上下文中
//在全局上下文中 ,vo===this===global
VO(globalContext) === [[global]];[[global]] = {Math : <...>,String : <...>,isNaN : function() {[Native Code]}......window : global // applied by browser(host)};
那么String(10)就相当于[[global]].String(10);了。这就是js代码执行前就可以调用Math等库的原因。
String(10); //[[global]].String(10);window.a = 10; // [[global]].window.a = 10this.b = 20; // [[global]].b = 20;GlobalContextVO (VO === this === global)
其中有趣的是,我们发现global的window指向global自身,所以我们可以在浏览器中尝试window.window.window…一直循环调用下去,可以证明window是一个无限循环调用。
3.函数中的VO–AO
在函数上下文中,我们在进入函数上下文的时候创建vo,这时候称呼他为ao(activation object)。
AO可以看作是VO的激活对象。
VO(functionContext) === AO;AO = {arguments : <Arg0>};arguments = {callee,length,properties-indexes};
函数的AO经历两个阶段
- 变量的初始化阶段
- 代码执行阶段
3.1变量初始化阶段
VO按照如下顺序填充:
函数参数(若未传⼊入,初始化该参数值为undefined)
函数声明(若发⽣生命名冲突,会覆盖)
变量声明(初始化变量值为undefined,若发⽣生命名冲突,会忽略。)
举个例子:
function test(a, b) {var c = 10;function d() {}var e = function _e() {};(function x() {});b = 20;}test(10);
VO扫描创建过程:
添加所有传入参数:a:undefined,b:undefined
添加所有函数声明,名字重复就覆盖:d:func
添加所有变量声明,名字重复就忽略:c:undefined,e:undefined
因此它的VO:
AO(test) = {a: 10,b: undefined,c: undefined,d: <ref to func "d">e: undefined};
再来个例子:
function foo(x,y,z){ function x(){}; alert(x);}foo(100);
结果alert:function x(){}
分析:扫描传入参数:x:undefined,y:undefined,z:undefined
扫描函数声明:x:func覆盖undefined
扫描变量声明:无
最终x是func。
function foo(x,y,z){ function func(){}; var func; consoel.log(func);}foo(100);
结果console.log:func(){}
分析:扫描传入参数:x:undefined,y:undefined,z:undefined
扫描函数声明:x:func覆盖undefined
扫描变量声明:x名字冲突不更改,直接忽略。
最终x还是func。
3.2代码执行阶段
还是这个例子
function test(a, b) {var c = 10;function d() {}var e = function _e() {};(function x() {});b = 20;}test(10);
之前分析之后的VO:
AO(test) = {a: 10,b: undefined,c: undefined,d: <ref to func "d">e: undefined};
十分好理解的为每个VO变量添加上数值
VO['c'] = 10;VO['e'] = function _e() {};VO['b'] = 20;
结果是:
AO(test) = {a: 10,b: 20,c: 10,d: <reference to FunctionDeclaration "d">e: function _e() {};};
3.3练习
题目:
alert(x); // functionvar x = 10;alert(x); // 10x = 20;function x() {}alert(x); // 20if (true) {var a = 1;} else {var b = true;}alert(a); // 1alert(b); // undefined
解析:
变量初始化阶段:
寻找函数声明:x:func
寻找变量声明:x不覆盖(还是func) a:undefined,b:undefined
所以第一行alert(x)返回function
代码执行阶段:
x:10
alert结果就是10
x:20
alert结果就是20
if语句没有产生新作用域,true永远为真,赋值a为1
最后两句打印a为1,b永远得不到执行,打印为undefined
- 深入理解javascript的作用域--函数声明为什么会前置
- JavaScript函数声明前置与变量声明
- 深入理解JavaScript的变量作用域
- 深入理解JavaScript的变量作用域
- 深入理解JavaScript的变量作用域
- 深入理解JavaScript的变量作用域
- 深入理解JavaScript的变量作用域
- 深入理解JavaScript的变量作用域
- 深入理解JavaScript的变量作用域
- 深入理解JavaScript的变量作用域
- javaScript的作用域链深入理解
- 深入理解JavaScript的变量作用域
- 深入理解JavaScript的变量作用域
- 深入理解JavaScript的变量作用域
- 深入理解JavaScript的变量作用域
- 深入理解JavaScript的变量作用域
- JavaScript的变量作用域深入理解
- 深入理解JavaScript的变量作用域
- 160613xib与代码混写界面注意事项
- 递推 2016.6.19
- **C++**C++刷题笔记
- As新建一个module形式的第三方library
- 快速选择
- 深入理解javascript的作用域--函数声明为什么会前置
- jdk的配置
- Ubuntu下让Linux开发板通过笔记本上网
- UVA - 725(水题)
- 数据结构之二叉树
- 动态SQL与模糊查询
- 使用Hive编写MapReduce程序
- Ubuntu 安装JDK1.8
- Eclipse下配置git方法