问题:以下代码会输出什么?
showName()
console.log(myname)
var myname = 'jack'
function showName() {
console.log('函数showName被执行');
}
console.log(myname)
如果要了解为什么会存在变量提升就需要先了解下变量存在哪里,提升是什么意思?
答案是:代码在编译阶段,变量和函数会被存放到变量环境中,变量的默认值会被设置为 undefined;在代码执行阶段,JavaScript 引擎会从变量环境中去查找自定义的变量和函数。(就是存在变量环境中的意思,继续变量环境是啥)
首先javascript代码的执行过程是什么样的呢?一段 JavaScript 代码在执行之前需要被 JavaScript 引擎编译,编译完成之后,才会进入执行阶段。意思就是分两个阶段:编译,编译之后生个什么东西,执行。
编译阶段
从上图可以看,经过编译后,会生成两部分内容:执行上下文(Execution context)和可执行代码。
执行上下文是 :JavaScript 执行一段代码时的运行环境。比如调用一个函数,就会进入这个函数的执行上下文,在这个阶段中,执行上下文会分别创建变量对象,建立作用域链,以及确定this指向。
以上就说明:先编译生成执行上下文,执行上下文中有变量对象,变量就存在这个变量对象中
一、我们可以一行一行来分析代码,看看编译过程。
showName()
console.log(myname)
var myname = 'jack'
function showName() {
console.log('函数showName被执行');
}
console.log(myname)
第 1 行和第 2 行,由于这两行代码不是声明操作,所以 JavaScript 引擎不会做任何处理;
第 3 行,由于这行是经过 var 声明的,因此 JavaScript 引擎将在环境对象中创建一个名为 myname 的属性,并使用 undefined 对其初始化;
第 4 行,JavaScript 引擎发现了一个通过 function 定义的函数,所以它将函数定义存储到堆 (HEAP)中,并在环境对象中创建一个 showName 的属性,然后将该属性值指向堆中函数的位置。如果变量与函数同名,则在这个阶段,以函数值为准。
经过编译阶段变量对象中是这样的:
// VO 为 Variable Object的缩写,即变量对象
VO = {
myname : undefined,
showName : <showName reference> // 表示showName 的地址引用
}
执行阶段:
JavaScript 引擎开始执行“可执行代码”,按照顺序一行一行地执行。
showName()
console.log(myname)
var myname = 'jack'
function showName() {
console.log('函数showName被执行');
}
console.log(myname)
我们可以一行一行来分析上述代码:(执行阶段):
第 1 行,调用函数showName能够在变量对象中找到 ,输出 '函数showName被执行';
第 2 行,查找到myname,根据编译阶段的结果,输出 undefined;
第 3行, 将myname 赋值为jack;
第 4-6行,这就是函数声明
第7行,查找到myname,经过第三行的操作,输出 'jack';
// 执行阶段
VO -> AO // Active Object
AO = {
showName : <showName reference>,
myname : 'jack',
this: Window
}
练习:
console.log(foo());
function foo() {
return 2;
}
var a;
console.log(a);
a = 1;