# let 关键字

# 作用域绑定在最近的 {...} 块中

let 在使用时会绑定离它最近的 {...} 作为作用域。原本在 ES6 以前是没有块级作用域的概念,在 ES6 引入了 let、const 关键字之后就有了块级作用域。实际上这个块级作用域并不是我们平常理解的块级作用域,仅当变量是由 let、const 关键字声明时,这些关键字声明的变量其作用域会绑定在这个块上,若是使用 var 关键字声明,其变量依然会成为全局变量。

使用这个特性我们可以很好的解决 for 循环全局变量污染的问题

if(true){
	{
		let a = 10;
		var b = 20;
		console.log(a); // 10
	}
	console.log(a); // ReferenceError
}
console.log(b); // 20

# 无变量提升

let 关键字在使用的时候,不像 var 那样存在变量提升的情况。它必须先声明再使用。

function fn(){
	console.log(a); // undefined
	console.log(b); //ReferenceError
	var a = 10;
	let b = 20;
}
fn();
// 上述代码等价于
function fn(){
	var a;  //var 变量提升至所在作用域顶部
	console.log(a); // undefined
	console.log(b); //ReferenceError
	a = 10;
	let b = 20;
}
fn();

# 暂时性死区

所谓暂时性死区就是,你在块级作用域使用 let 声明了一个变量 i ,同时你在外部作用域也声明的一个同名变量 i 。若你在 let 声明这个变量前使用它,它并不会像以前的那样去上级作用域寻找这个变量,仅会在该作用域内寻找变量,又因为变量使用 let 声明,并且声明在其使用之后,就会抛出 ReferenceError。因为使用 let 在作用域内声明了同名变量,它会屏蔽外界变量,这个块级区域就被称为暂时性死区

var a = 20;
//if {} 内形成暂时性死区
if(true){
	console.log(a); // ReferenceError
	let a = 10;
}
-------------
var b = 20;
// 不是同名变量,没有暂时性死区
if(true){
	console.log(b); // 20
	let a = 10;
}

# const

# 声明时必须赋值

const 关键字的特性和 let 相同, let 有的特性 const 都具有。不同点是它在声明的同时必须赋予一个值,否则抛出 SyntaxError。

const a;  // SyntaxError

# 赋值后不可改变

这里 const 关键字声明的变量能否更改还需要看具体的情况。

const 声明的是一个基本数据类型,则不能更改其值

const a = 10;
a = 20; // TypeError

但是如果 const 声明的是一个复杂数据类型,则可以更改复杂数据类型变量内部的值,不可更改该复杂数据类型变量本身

const b = [1,2,3];
b[1] = 100; 
console.log(b); // [1,100,3]
b = [3,4,5]; //TypeError

# 箭头函数

最初使用箭头函数的目的就是为了简化函数声明的操作,但它的作用不仅如此。我们都知道 this 指针的指向在不同地方其指向不同,例如在构造函数中其指向就是它的实例化对象,在 class 中的 constructor 中也是同样的指向自身的实例化对象,而在普通函数中其指向的是函数的调用者。

# 箭头函数中的 this 是根据上下文环境确定的

箭头函数 this 指向的是被声明的作用域里面

let btn = document.querSelector('.btn');
btn.onclick = function(){
	setTimeout(function(){
		console.log(this); // window
	},1000);
}
------------
// 在定时器的回调函数中使用箭头函数则其 this 会根据上下文指向 btn 对象,而不是指向 window
btn.onclick = function(){
	setTimeout(()=>{
		console.log(this); // btn
	},1000);
}

# 多种简写形式

当形参只有一个且函数体内仅有一句返回值时

let sum = n => n*3;
// 等价一
let sum = (n) => {
    return n*3;
}
// 等价二
let sum = function(n){
    return n*3;
}

函数体中只有一句代码,且代码的执行结果就是返回值,可以省略大括号

let sum = (a,b) => a+b;
// 等价一
let sum = (a,b) => {
	return a + b;
}
// 等价二
let sum = function(a,b){
    return a + b;
}

# 解构

# 数组的解构

在 es6 中我们可以使用新的方式来命名多个变量,这种新的声明赋值方式就叫解构

// 传统命名多个变量并赋值的方式
let a = 10,b = 20,c = 30;
// 采用数组解构的方式
let arr = [10,20,30];
let [a,b,c] = arr;  //a = 10,b = 20,c = 30
// 当变量数量大于数组长度
let arr = [1,2,3];
let [a,b,c,d] = arr; //a = 1,b = 2, c = 3,d = undefined // 多余的变量为未定义
// 当变量数量少于数组长度
let arr = [1,2,3];
let [a,b] = arr; //a = 1,b = 2  // 多余的直接被截断
--------------
// 对象解构
let obj = {
    name:'Asuhe',
    age: 18,
    sex: '男'
}
let {name:myname,age:myage,sex:mysex} = obj; //myname = 'Asuhe',myage = 18,mysex = ' 男 ' // 按匹配相同名称,即使乱序也会匹配上
// 等价于
let myname = 'Asuhe';
let myage = 18;
let sex = '男';
----------------
let {name,age,sex} = obj;
等价于
let name = 'Asuhe';
let age = 18;
let sex = '男';

# 剩余参数

在 es6 中新扩展了一种方法可以使函数的形参接收不定数量的实参,那就是使用剩余参数。我们知道在以前 js 同样支持函数形参和实参数量不匹配,即使定义函数时形参列表为空我们依然可以使用 arguments 对象获取到实参。但在 es6 新增的箭头函数中并不支持 arguments ,所以 es6 扩展了 ...args 剩余参数来解决这个问题。

// 传统获取所有形参
function foo(){
	console.log(arguments[0]); //1
    console.log(arguments[1]); //2
    console.log(arguments[2]); //3
}
foo(1,2,3);
// 使用剩余参数
function foo(a,...args){ // 剩余参数必须放在最后一个形参的位置
    console.log(a); //1
    console.log(args); //[2,3,4,5] // 以数组的形式存储值
}
foo(1,2,3,4,5);