JavaScript引擎在开始编译代码的时候,会对JavaScript代码进行一次预编译,生成一个执行环境,比如如下代码:
window.οnlοad=function(){ function sub(a,b){ return a-b; } var result=sub(5,10);}
就会生成如下图所示的一个类似嵌套的执行环境的逻辑结构视图,
说明:这些执行环境(也叫作用域)都会有一个变量对象,这些变量对象保存着该执行环境(作用域)中的所有变量与函数的名和值,虽然JavaScript代码还没有执行,但是你所书写的代码中的所有变量名和函数名已经提前保存在了这些变量对象中。当代码执行的时候,这些变量对象会和作用域链进行密切的配合,帮助JavaScript引擎寻找函数执行时所需要的变量和函数。如果内部的函数没有该变量,就向外边去找。
而这些环境变量的存储结构视图却不是嵌套的,而是用堆栈的形式:如图:
同样为了满足逻辑结构中提到的变量/函数的遍历寻找,JavaScript提出了作用域链的概念,这在下节会讲到。
介绍完JavaScript在预编译时的逻辑结构和存储结构,下面就说说JavaScript引擎在处理上述内容时实现的两个规则:
1.声明变量时用var和不用var
用var,JavaScript在预编译的时候会把这个变量放到该执行环境的变量对象中,不用var声明,就放到全局执行环境的变量对象中。
2.如果变量和函数的声明重名怎么办
这得分情况:
如果变量已经赋值,不管变量声明在前还是在后,函数的声明无效。
如果变量没赋值,不管函数声明在前还是在后,变量的声明无效。
这两条没有什么原理,是js原创者当时做的时候就是这么规定的。希望大家牢记。
通过上述的讲解,我想大家能够轻松的理解以下所谓的《你真的了解JavaScript吗?》系列问题的解题原理了。
1.
if (!("a" in window)) { var a = 1;}alert(a);
2.
var a = 1, b = function a(x) { x && a(--x); };alert(a);
3.
function a(x) { return x * 2;}var a; alert(a);