1.let命令
基本用法:
let命令用来声明变量,只在let命令所在的代码块中有效
for(let i = 0; i < 10; i++) {}
console.log(i);//not defined
以上代码i只在for循环中有效。
与var声明变量作比较:
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
i通过var声明,在全局范围内有效,数组a的function通过闭包读到i,最后输出的是最后一轮i的值。
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
当前i只在本轮循环有效,每次循环的i是一个新的变量,设置循环的部分是一个父作用域,循环体内是一个单独的子作用域。
不存在变量提升:
var声明变量可以在声明之前使用变量,值为undefined;
let命令声明变量一定要在声明后使用,否则会报错,变量不可用,这称为 “暂时性死区”(temporal dead zone,简称 TDZ),在let声明bar变量之前,都属于bar的死区。
// var 的情况
console.log(foo); // 输出undefined
var foo = 2;
// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;
不允许重复声明:
let不允许在相同作用域内,重复声明同一个变量。
function func(arg) {
let arg; // 报错
}
function func(arg) {
{
let arg; // 不报错
}
}
2.块级作用域
let为javascript新增了块级作用域,“同层”的代码作用域相同。
function f1() {
let n = 5;
if (true) {
let n = 10;
}
console.log(n); // 5
}
块级作用域和函数声明
ES5中不允许在块级作用域声明函数,函数只能在顶层作用域和函数作用域中声明。
//非法情况
// 情况一
if (true) {
function f() {}
}
// 情况二
try {
function f() {}
} catch(e) {
// ...
}
ES6允许在块级作用域之中声明函数,函数声明语句的行为类似于let,在块级作用域之外不可引用。
作用域对比:
function f() { console.log('I am outside!'); }
(function () {
if (false) {
// 重复声明一次函数f
function f() { console.log('I am inside!'); }
}
f();
}());
在ES5中,if内声明的f函数会提升到函数的头部,即:
// ES5 环境
function f() { console.log('I am outside!'); }
(function () {
function f() { console.log('I am inside!'); }
if (false) {
}
f();
}());
在ES6中,函数声明类似于var,提升到全局作用域或函数作用域的头部,即:
// 浏览器的 ES6 环境
function f() { console.log('I am outside!'); }
(function () {
- //相当于在这里声明了var f = undefined;
if (false) {
// 重复声明一次函数f
function f() { console.log('I am inside!'); }
}
- f();
}());
// Uncaught TypeError: f is not a function
解决办法:避免在块级作用域内声明函数,应该写成函数表达式。
// 函数声明语句
{
let a = 'secret';
function f() {
return a;
}
}
// 函数表达式
{
let a = 'secret';
let f = function () {
return a;
};
}
do表达式
do表达式,用于返回块级作用域的值:
let x = do {
let t = f();
t * t + 1;
};
变量x会得到整个块级作用域的返回值。
3.const命令
const声明一个只读的常量,一旦声明,值不能改变,必须立刻初始化,只声明不赋值会报错,只在声明所在的块级作用域内有效,与let相同,常量也不提升,存在暂时性死区,只能在声明的位置后面使用,不可重复声明。
const事实上保证指向的内存地址不得改动,对于简单数据类型(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,等同于常量。复合类型(对象和数组),变量指向的内存地址, 保存的只是一个指针,const只能保证指针是固定的。
4.顶层对象的属性
ES5中,顶层对象(window)的属性的赋值等同于全局变量的赋值,不利于模块化编程。
ES6改变了这一段,保留了var命令和function命令声明的全局变量,依旧是顶层对象的属性,但是let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。
var a = 1;
// 如果在Node的REPL环境,可以写成global.a
// 或者采用通用方法,写成this.a
window.a // 1
let b = 1;
window.b // undefined
5.global对象
在system.global中,global作为全局变量,在所有的环境(浏览器环境、node环境、web worker环境)中都能从它拿到顶层对象。
// CommonJS的写法
require('system.global/shim')();
var global = require('system.global')();
// ES6模块的写法
import shim from 'system.global/shim'; shim();
import getGlobal from 'system.global'; const global = getGlobal();