# 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); |