JS拓展:Let和变量提升(函数预编译)
Let(定义变量)
在es5中我们声明变量一般是使用var,然而var具有变量提升的功能,有可能会给我们带来出乎意料的异常
变量提升是什么
- 用var声明一个变量,他会被提升到函数或全局作用域的顶部。这样在变量声明之前就可以获取到此变量
- 如果变量声明时给了初始值,那么值不会被提升,提升到最顶部的变量是一个未初始化值的变量
变量提升带来的问题
var ar=[];
for (var i = 0; i < 10; i++) {
ar.push(function(){console.info(i);})
}
//注意for循环中是没有块级作用域的
打印出来的i全部都是10,因为在打印时才去获取的i值,而这里的i由于被提升到全局作用域了,所以每次迭代的都是同一个值
解决变量提升导致的问题(let的由来)
let关键字具有块级作用域。相当于var的升级版
- let不会进行变量提升,它只有被声明了只会才能使用。称之为TDZ(暂时性死区)
- Let具有块级作用域,只在它当前所在或括号范围内有效
- 不允许在重复定义let已经定义过的变量
函数提升及其解决方法
- 不仅变量可以提升,函数也可以提升,并且提升时函数的函数体也会提升
- 如果声明了多个同名函数,那么只会提升最后一个函数函数
注意:通过字面量形式声明的函数,会被当做变量处理,提升时不会提升值。
函数内部的变量提升的过程和优先级
基本规则:函数优先提升,同时提升函数体
对于同名的变量和函数,只会提升函数而不会提升变量
如果函数含有参数的话,会有点区别
- 函数最优先级最高
- 形参第二优先
- 最后才是普通变量
函数内部的变量提升执行过程
这个提升过程也称之为函数预编译过程,共分为五步:
生成环境>>查找形参>>赋值实参>>查找变量>>查找函数
- 数在运行的瞬间,生成一个执行期环境上下文 (Active Object),简称AO;
- 查找是否具有形参,找到后添加到AO的属性,值为undefine,例如AO.age=undefined;
- 接收实参,添加到AO的属性,覆盖之前的undefined;
- 查找函数内是否具有变量声明,如var age;或varage=23;,如果找到了且AO上还没有这个属性,就把他添加AO上,值为undefined。如果找到了但AO上已经有了这个属性,则不作任何修改;
- 查找函数内是否具有其他函数的声明,如:function age(){};如果找到了就把函数赋给AO.age,而不管AO上是否已经存在此属性。如果找到了多个同名函数声明,那么只会以最后一个函数声明为准