基本概念
let
- let声明的变量只在let所在的代码块内有效
// for循环,设置循环变量是一个父作用域,循环体内又是一个作用域
for(let i = 0; i < 10; i++) {
let i = 'abc';
console.log(i); // abc
}
console.log(i); // 报错
- let声明不存在变量提升
- 暂时性死区(let变量声明前,该变量都是不可使用)
- let不允许相同作用域内,重复声明同一变量
const
- 声明只读常量,一旦声明,值就不能改变
- 只在声明的块级作用域内有效
- const声明不存在变量提升
- 暂时性死区
- 相同作用域内不可重复声明
- 不要使用const定义对象,因为此时虽然定义的对象,一样可以修改
const foo = {};
foo.info = 'info';
const的本质
const 只能保证变量指向的那个内存地址,所保存的值不可变动
简单类型的数据(数值、字符串、布尔值),变量指向的内存地址直接保存相关数据
复合数据类型(主要是对象和数据),变量指向的内存地址,保存的是实际数据的指针,这个指针只是固定的指向另外一个地址,至于这个指向的地址对应的数据结构是不是可变的,就无法控制。
所以使用 const 定义的简单数据类型可以理解为常量,如果修改会报错,但是如果使用const定义复合数据类型,修改这个对象的值,一样是可以的。
声明变量的方法
- var
- function
- let
- const
- import
- class
var 是 functuon scope,声明的变量,只有处在于某个函数中才会变成局部变量,否则就是全局变量,let、const 是 block scope ,声明的变量,只要存在于某个大括号内就是局部变量,大括号外无法访问
顶层对象、全局变量
顶层对象,在浏览器环境指的是 window 对象,在 Node 指的是 global 对象,ES5之中,顶层对象和全局对象是等价
ES6后,var、function声明的全局变量,依然会加挂到顶层对象上,但let、const、class声明的全局变量,不再属于顶层对象(也就是不能直接通过window对象的形式访问)
块级作用域
块级作用域内避免使用函数声明,可以使用函数表达式
// 下面情况下直接使用会报错
function f() { console.log('I am outside!'); }
(function () {
if (false) {
// 重复声明一次函数f
function f() { console.log('I am inside!'); }
}
f();
}());
// Uncaught TypeError: f is not a function
...
// 但是如果使用函数表达式就不会
function f() { console.log('I am outside!'); }
(function () {
if (false) {
// 重复声明一次函数f
let f = function () { console.log('I am inside!'); }
}
f();
}());
// I am outside! 这是一个符合预期的结果