首先我们看一段代码的执行
1这段代码的输出是 undefined, 为什么它会是 undefined ,而不是 a is not defined,这就跟 JS 的运行机制有关。
JS 中的 声明 和 赋值
对于简单的 var a = 1 声明语句,我们可以理解为两个步骤:
1 声明部分: var a;
2 赋值部分: a = 1;
那么 函数的 声明 和 赋值 又是如何的
2对于 foo 函数 是一个完整的函数声明,没有涉及到 赋值操作; 而第二个函数 先声明了 变量 bar ,再将 函数 赋值给 bar。
再谈变量提升
理解了 声明 和 赋值,那么 什么是 变量提升
变量提升,是指在 JavaScript 代码执⾏过程中,JavaScript 引擎把变量的声明部分和函数的声明部 分提升到代码开头的“行为”。变量被提升后,会给变量设置默认值,这个默认值就是我们熟悉的 undefined。
也就是说 对于 var a = 1,可以理解为两步:
1 var a = undefined;
2 a = 1;
注意 : 只有 声明本身 会被提升,而 赋值或其他运行逻辑 会留在原地。
3注意: 在每个作用域中,都会进行提升操作,比如 在函数 作用域内 用 var 声明的,会提升至 本作用域 的开头。
再谈 var a = 1
JS 在执行 var a = 1 这段代码时,变量 和 函数声明 在代码里的位置是不会改变的,而是在编译 阶段被JavaScript引擎放入内存中 。一段 JS 代码在执行前 需要被 JS 引擎 编译,编译完成之后 才会进入 执行阶段。
一段 JS 代码 ---------> 编译阶段 ---------> 执行阶段
这意味着无论作用域中的声明出现在什么地方,都将在代码本身被执行前首先进行处理。 可以将这个过程形象地想象成所有的声明(变量和函数)都会被“移动”到各自作用域的 最顶端,这个过程被称为提升。
声明本身会被提升,而包括函数表达式的赋值在内的赋值操作并不会提升。
编译阶段
还是上面的 例子
4一段 JS 代码 经过 编译阶段后 会生成 两部分:执行上下文 和 可执行代码。
5执行上下文 是 JS 执行一段代码时的 运行环境, 它存在 一个变量环境对象,这个对象保存了 变量提升部分的内容,比如上面例子中的 变量 a 和 函数 foo。
分析 图4 中的代码:
1 第一行和第二行 不是声明操作, JS 引擎不处理。
2 第三行 是 一个 var 的声明变量, JS 引擎会在环境对象中 创建一个 名为 a 的 属性,并初始化值 undefined
3 第四行 是函数声明语句, JS 引擎 会在环境对象中 创建一个 名为 foo的 属性, 并将函数定义存储到 堆中,属性值 指向 函数所在堆的地址。
这样 就生成了 变量环境对象。
执行阶段
在执行阶段, JS 引擎就会处理 执行阶段的代码,JS 引擎 就会在 变量环境对象 中 找到 所需要的值,并输出结果。
总结
JS 代码在执行过程中,会经过两个阶段 : 编译阶段 和 执行阶段。
在编译阶段,变量和函数会被存放到 变量环境 中,变量的默认值会被设置为 undefined;在执行阶段,JavaScript 引擎会从变量环境中去查找⾃定义的变量和函数。
网友评论