let 命令
let
命令,用来声明变量。类似 var
,但是只在 let
命令所在的代码块内有效。
{
let a = 10;
var b = 1;
}
a // ReferenceError: a is not defined.
b // 1
for
循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
上面代码输出3次 abc
。表明代码块内容变量 i
与循环变量 i
不在同一个作用域,有各自单独的作用域。
不存在变量提升
var
命令会发生“变量提升”现象,即变量可以在声明之前使用,值为 undefined
。
let
改变了语法行为,一定先声明后使用。
暂时性死区
只要块级作用域内存在 let
命令,它所声明的变量就“绑定”这个区域,不再受到外部影响。
var tmp = 123;
if (true) {
tmp = 'abc'; //ReferenceError
let tmp;
}
** ES6 明确规定,如果区块内存在 let
和 const
命令,这个区块对这些命令声明的变量形成封闭作用域。 **
typeof
不在是一个安全的操作
typeof x; //ReferenceError
let x;
如果一个变量没有被声明,不会报错。
不允许重复声明
块级作用域
ES6 的 let
为 JavaScript 新增了块级作用域。
允许块级作用域的任意嵌套。
外层作用域无法读取内层作用域的变量。
内层可以定义外层同名的变量。
do 表达式
块级作用域是一个语句,讲多个操作封装在一起,没有返回值。
现在有一个提案,使它变为 do
表达式。
let x = do {
let t = f();
t * t + 1;
}
上面代码,变量x会得到整个块级作用域的返回值。
const命令
const
声明一个只读的常量。一旦声明,值不能改变。
本质
const
保证的是变量指向的内存地址不得改动。
当地址指向一个对象时,对象本身是可变,可以添加新属性。
如果真的想将对象冻结,可以使用 Object.freeze
方法。
const foo = Object.freeze({});
// 常规模式时,下面一行不起作用;
// 严格模式时,改行会报错
foo.prop = 123;
除了将对象本身冻结,对象的属性也应该冻结。下面是一个将对象彻底冻结的函数。
var constantize = (obj) => {
Object.freeze(obj);
Object.keys(obj).forEach( (key, i) => {
if ( typeof obj[key] === 'object' ) {
constantize( obj[key] );
}
})
}
ES6声明变量的六种方法
var
、function
、let
、const
、import
、class
顶层对象的属性
ES5时,浏览器中的顶层对象指的是 window
,Node指的是 global
对象。
ES6为了改变这一点,var
和 function
命令声明和ES5保持一致,let
命令、const
命令、class
命令声明的全局变量,不属于顶层对象的属性。