js 中,传统声明变量是var、function;es6中是let、const、import。
变量提升(var、function)
- var function 声明的变量都存在变量提升机制,而且function 声明的变量会提前声明+定义。
- 基于 var function 声明的全局变量会给全局对象GO(window)增加一个对应的私有属性,它们之间有一个映射机制(一个修改,另一个也会跟着修改)
- 使用var 声明变量,使用var声明的变量会发生提升,变量提升就是把我们所写的变量声明代码提升到它所在作用域的顶端去执行,在代码所在的位置来赋值
运行代码:
<script>
function test() {
if (false) {
var web=123;
}
console.log(web);
}
test();
//输出undefined
</script>
提升后实际运行:
<script>
function test() {
var web;
if (false) {
web=123;
}
console.log(web);
}
test();
//输出undefined
</script>
//声明式
function test() {}
//字面量式
var test1 = function () {}
字面量式的函数提升效果跟变量提升的效果是一样的,因为字面量式的函数只是一个具体的值。
声明式的函数提升是整个代码块提升到它所在的作用域的最开始执行的地方,拥有最高的优先级。
let 、const
let 的检测是否重复声明发生在词法解析阶段(js代码自上而下执行,浏览器会提前处理很多事情,例如词法解析—>变量提升—>代码执行 等)。一旦在词法解析这一阶段报错,js代码一行都不会执行的。
- let const 都是声明一个变量,但是const声明的变量不允许指针重新指向,且const声明的时候必须赋值,否则会报错。
变量赋值本质上就是一个指针指向的过程。const变量的值如果是引用数据类型的话,那么是可以改变里面的值的(这并不会改变指针的指向)。
- let const 不存在变量提升,所以必须先声明后使用
- let const 声明的变量并不会给全局对象GO(window)增加属性。所以带声明的变量和不带声明的变量是不一样的机制,平时写的时候不要省略。
如果变量不带任何声明,则默认是给全局对象GO(window)增加属性,该变量就不会提前声明。
- 同一上下文中,let不允许重复声明
- 在ES6中基于let/const等方式创建的变量或者函数都不存在变量提升机制
旧版本变量提升
旧版本浏览器没有块级作用域这种说法,只有全局作用域与函数作用域
变量提升定义:js在代码执行之前,会将变量声明提升到所属作用域的最顶端
当变量同名时函数提升的优先级高于变量提升
提升变量时,提升的是变量的声明,而提升函数时,会将函数的声明和定义一起提升
新版本变量提升
新版本中函数变量提升更改为了只提升函数的声明,而不提升函数的定义
暂时性死区
如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。在代码块内使用let命令声明变量之前,该变量都是不可用的,称为“暂时性死区”(temporal dead zone,简称TDZ)。