1. let命令

let 命令不存在变量提升
let 命令 只在let命令所在的代码块内有效。

{
let a = 10;
var b = 1;
} a // ReferenceError: a is not defined.
b //

特别适合 for 语句

var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); //

其实对于上面的代码, babel 转码以后变成

"use strict";

var a = [];

var _loop = function _loop(i) {
a[i] = function () {
console.log(i);
};
}; for (var i = 0; i < 10; i++) {
_loop(i);
}
a[6](); //

for循环还有一个特别之处,就是循环语句部分是一个父作用域,而循环体内部是一个单独的子作用域。

for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc

暂时性死区, temporal dead zone,简称 TDZ

下面的例子, 由于在代码里 定义了let tmp, 所以会报错

var tmp = 123;

if (true) {
tmp = 'abc'; // tmp is not defined
typeof tmp; // tmp is not defined
let tmp;
}

但是如果直接 typeof 一个不存在的变量 aaa, 则不会报错
typeof aaa // "undefined"

不允许重复声明
let不允许在相同作用域内,重复声明同一个变量。

function f() {
let a = 10;
var a = 1;
}
f(); // 执行的时候报错 function func(arg) {
let arg;
}
func(2); // 执行的时候报错 function func(arg) {
{
let arg; // 不报错
}
}
func(2); // 不报错

2. 块级作用域

内层作用域可以定义外层作用域的同名变量。

{
let insane = 'Hello World';
{let insane = 'Hello World'}
};

块级作用域的出现,实际上使得获得广泛应用的立即执行函数表达式(IIFE)不再必要了。

// IIFE 写法
(function () {
var tmp = 2;
console.log(tmp);
}()); // 块级作用域写法
{
let tmp = 2;
console.log(tmp);
}

块级作用域与函数声明
ES5 规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。
但是,浏览器 为了兼容以前的旧代码,还是支持在块级作用域之中声明函数。
ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。

// 情况一
if (true) {
function f() {}
} // 情况二
try {
function f() {}
} catch(e) {
// ...
}

ES6规定
允许在块级作用域内声明函数。
函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
同时,函数声明还会提升到所在的块级作用域的头部。

所以下面的代码会报错

// 浏览器的 ES6 环境
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
}()); // 相当于: // 浏览器的 ES6 环境
function f() { console.log('I am outside!'); }
(function () {
var f = undefined;
if (false) {
function f() { console.log('I am inside!'); }
} f();
}());
// Uncaught TypeError: f is not a function

但是在 ES5 环境里, 是可以正常运行, 打印 I am inside!
所以在块级作用域里用, 建议用函数表达式来声明 let f = function(){}

3. const 命令

const声明一个只读的常量。一旦声明,常量的值就不能改变。
const a = 1;
a = 2; // Uncaught TypeError: Assignment to constant variable.

const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,
const a; // Missing initializer in const declaration

const的作用域:
只在声明所在的块级作用域内有效。
声明的常量也是不提升。
不可重复声明。

本质

const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。
对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const只能保证这个指针是固定的

const foo = {};
foo.prop = 123; // 成功
foo = {}; // Uncaught TypeError: Assignment to constant variable.

ES6 声明变量的六种方法
var, function, let, const, import, class

4.顶层对象的属性

在浏览器环境指的是window对象
node 环境里没有 window 对象, 有global对象;
ES6 规定var和function命令声明的全局变量,依旧是顶层对象的属性;
let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性

// node 环境里
var a = 1;
console.log( global.a ); // 输出1

// ES6 环境里
var a = 1;
window.a // 1

let b = 1;
window.b // undefined

5. global 对象

浏览器 顶层对象 window 和 self; (window === self // true)
Web Workerself指向顶层对象
node global

全局环境中,this会返回顶层对象。但是,Node模块和ES6模块中,this返回的是当前模块。

05-26 11:50