ECMAScript 6.0
简称(es6) 是继ECMAScript 5
之后的javascript
语言的下一代标准,它的目标是使得javascript
语言可以用来编写复杂的大型应用程序。es6新特性:let
、const
、解构赋值
、Set
、Map
、Iterrator接口
等
Let
- 使用let声明的变量,所声明的变量只在命令所在的代码块有效. for if 等形成块级作用域
- 为什么需要块级作用域 内层变量会覆盖外层变量 用来计数的循环变量泄漏为全局变量
- 使用let命令声明的变量在预解析的时候不会被提升 let声明的变量不允许未定义就使用
- 暂时性死区 只要块级作用域内存在let命令,它所声明的变量就绑定在这个区域内,不再受外部的影响. 当前作用域在执行之前,浏览器会做语法(重复性)检测,如果语法(重复性)检测不通过会直接报错,整个代码不执行
console.log(typeof a) //暂时性死区 - let不允许在同一个作用域下声明已经存在的变量 不能在函数内部重新声明参数
var 声明的变量由函数来划分作用域
let 声明的变量由代码块来划分作用域 一对{ } 包括的区域被称为代码块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40/*
<div>
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
</div>
*/
// 给多个button添加点击事件,并弹出对应的索引值
var btns = document.querySelectorAll('button')
/* 问题代码
for(var i=0;i<btns.length;i++){
btns[i].onclick = function() {
console.log(i) // 6 6 6 6
}
}
*/
// 方法1 使用let
for(let i=0;i<btns.length;i++){
btns[i].onclick = function() {
console.log(i) // 1 2 3 4
}
}
// 方法二 自定义属性存索引
for(var i=0;i<btns.length;i++){
btns[i].index = i
btns[i].onclick = function() {
console.log(this.index) // 1 2 3 4
}
}
// 方法三 闭包
for(let i=0;i<btns.length;i++){
// 遍历过程 仅将事件处理函数赋值给按钮的onclick属性 不调用函数
(function(i)){ // 形参相当于局部变量 var i
btns[i].onclick = function() {
// 每调用一次 就创建一个函数 并将本次传入的i值放在局部变量 被永久保存起来
console.log(i) // 1 2 3 4
}
})(i)
}
Const
Const命令同样有上面let的1,2,3条特点,第一:所声明的常量只在其所在的代码块内有效,第二声明的常量不会被提升,第三不能声明已经被声明过得常量,除了这些,在使用const声明常量的时候需要注意的两点.
声明的时候必须赋值 否咋报错
1
2const C
// Uncaught SyntaxError: Missing initializer in const declaration声明的常量储存简单的数据类型不可改变其值,如果存储的是对象,那么引用不可以被改变,对象的属性是可以被修改
1
2
3
4
5
6
7
8const C = 1; C = 2
// Uncaught SyntaxError: Assignment to constant variable.
const obj = { a: 10}
obj.a = 20
console.log(obj) // {a: 20}
obj = {a: 30}
// Uncaught TypeError: Assignment to constant variable声明不可更改的常量对象
1
2
3
4
5const arr1 = Object.freeze([1, 2, 3])
console.log(Object.isFrozen(arr1)) // true
arr1[0] = 4
console.log(arr1) // [1, 2, 3]
arr1.push(4) // Uncaught TypeError: Cannot add property 3, object is not extensible
顶层对象window的属性
Es6为了保持兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性.另一方面规定,let命令,const命令,class命令声明的全局变量,不属于顶层对象的属性.1
2
3
4
5
6
7
8
9
10var a = 1
console.log(window.a) // 1
function fn(){}
console.log(window.fn) // fn(){}
let b = 2
console.log(window.b) // undefined
const c = 3
console.log(window.c) // undefined
class Person {}
console.log(window.Person) // undefined
解构赋值
解构赋值: 按照一定的模式从数组和对象中提取值,并对变量进行赋值,解构不成功,变量的值都会是undefined. 只要等号两边的模式相同.左边的变量就可以被赋予对象的值
基本类型的解构赋值
null和undefined 不能进行解构
1
2
3
4
5
6
7
8
9// 字符串的解构
let [a,b,c] = '123'
console.log(a,b,c) // 1 2 3
// length属性的解构
let {length: len} = 'tew'
console.log(len) // 3
// null和undefined 不能进行解构
let [n] = undefined // Uncaught TypeError: undefined is not iterable
let [m] = null // Uncaught TypeError: null is not iterable数组的解构赋值
1
2
3
4let [a,b,c] = [1,'test', false]
console.log(a,b,c) // 1 "test" false
let [x, [[y],z]] = [1,[[['a', 'b']], false]]
console.log(x, y, z) // 1 ["a", "b"] false对象的解构赋值
允许你为对象的不同属性绑定变量名,左侧类似一个对象字面量,对象中是一个名值对的列表,冒号左侧是属性名称,右侧是变量名称,每个属性都会去右侧对象中查找相应的值,每一个值都会赋值给它对应的变量.先找到同名的属性,然后赋值给变量,真正赋值的是变量,而不是属性1
2
3let {a:b} = {a:1}
console.log(b) // 1
console.log(a) // Uncaught ReferenceError: a is not defined属性名和变量名相同可简写
1
2let {a, b} = {b: 'bbb', a: 'aaa'}
console.log(a,b) // aaa bbb对象解构赋值的默认值
默认值生效的条件是属性值严格等于undefined
1
2
3
4
5
6
7
8
9
10
11let {x,y=5} = {x:1}
console.log(x, y) // 1 5
let {msg='tew'} = {msg: 'default'}
console.log(msg) // default
// 只有属性值是 === undefined 才会采用默认值
let {a = 3} = {a: undefined}
let {b = 3} = {b: 'undefined'}
let {c = 3} = {c: null}
let {d = 3} = {d: false}
console.log(a,b, c,d) // 3 'undefined' null false选择性解构赋值,用逗号可省略隔开
1
2let [,,c] = [1,2,3]
console.log(c) // 3将右侧多余的值以数组形式赋值给左边的变量–rest模式
1
2let [head, ...tail] = [1,2,3]
console.log(head, tail) // 1 [2, 3]起别名 原名称:别名 只能用别名来访问
1
2
3let {name, a:num} = {'name':'tew', a: 9}
console.log(name, num) // tew 9
console.log(a) // a is not defined
函数参数的解构赋值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25function fn2(a=1,b=2){
console.log(a,b)
}
fn2() // 1 2
fn2({b:9}) // {b:9} 2
// 函数参数解构赋值 默认值
// 函数在未传值时才会使用默认值
function fn({a=1,b=2} = {}){
// 通过 对参数(对象) 进行解构得到 变量a和b的值
// 解构赋值 {a=1, b=2} = 传过来的实参 (默认{})
console.log(a,b)
}
fn() // 1 2 => {a=1,b=2} = {}
fn({b:5}) // 1 5 => {a=1, b=2} = {b:5}
// 函数在未传值时才会使用默认值
function fn1({a, b} = {a:3, b:4}){
// 解构赋值 {a, b} = 传过来的实参(默认{a:3, b:4})
// 如果有参数如fn1({a:5}) 则{a:3, b:4} 会被替代成 {a: 5} 相当于 {a, b} = {a:5}
console.log(a,b)
console.log(arguments[0]) // 打印实参 可以看到 {a:3, b:4} 被替换掉
}
fn1() // 3 4 => fn1({a, b} = {a:3, b:4})
fn1({a:5}) // 5 undefined => fn1({a, b} = {a:5})
fn1({a:10, b:20}) // 10 20 => fn1({a, b} = {a:10, b:20})
fn1({}) // undefined undefined => fn1({a, b} = {})解构赋值的用途
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31/* 1. 交换变量 */
let x = 100, y = 200
console.log('交换前', x, y); // 交换前 100 200
[x, y] = [y, x] //表达式前语句必须有;分号
console.log('交换后', x, y) // 交换后 200 100
/* 2. 从函数返回多个值(数组或对象) */
function fun1(){
return {
id:10001,
name: 'tew'
}
}
let {id, name} = fun1()
console.log(id, name)
/* 3. 当函数参数顺序不确定时 */
function fn({id, name}){
console.log(id, name)
}
fn({name: 'tew', id: '002'}) // 002 tew
/* 4. 提取json数据 例如axios返回的数据 */
// let {status, data} = this.$axios.post('xx')
let data = {
id: '003',
nick: 'bob',
score: { math: 95, chinese: 90 }
}
let { id:num, nick, score: { math } } = data
console.log(num, nick, math) // 003 bob 95
/* 5. 加载模块的指定的方法 */
import { formateDate, formateMoney } from 'util.js'
数据结构 Set
Set是由一组无序且唯一(既不能重复)的项组成 ,key和value相同,没有重复的value
创建set 可以接受数组或类数组作为参数,用来初始化
1
2
3
4
5// 创建 Set
var a = new Set([1,2,3])
console.log(a) // Set(3) {1, 2, 3}
// Set的属性 a.size
console.log(a.size) // 3set.add(value)
添加数据 返回值为set结构本身1
2a.add('a').add('b')
console.log(a) // Set(5) {1, 2, 3, "a", "b"}set.delete(value)
删除指定的数据,返回布尔值,表示删除是否成功1
2
3console.log(a.delete('a')) // true
console.log(a) // Set(4) {1, 2, 3, "b"}
console.log(a.delete('a')) // falseset.has(value)
判断该值是否为set成员,返回一个布尔值1
2console.log(a.has('b')) // true
console.log(a.has('a')) // falseset.keys()
返回所有键名set.values()
返回所有键名set.entries()
返回所有键值对1
2
3console.log(a.keys()) // SetIterator {1, 2, 3, "b"}
console.log(a.values()) // SetIterator {1, 2, 3, "b"}
console.log(a.entries()) // SetIterator {1 => 1, 2 => 2, 3 => 3, "b" => "b"}set.forEach(function(value,key,set){})
遍历1
2
3
4a.forEach(function(value, key, set){
console.log(key+'--'+value) // 1--1 2--2 3--3 b--b
console.log(set) // SetIterator {1, 2, 3, "b"}
})set.clear()
清除所有数据,无返回值1
2a.clear()
console.log(a) // Set(0) {}set
应用场景(去重、交集、并集、差集)1
2
3
4
5
6
7
8
9
10
11
12
13// 数组去重
const arr = [1, 'a', true, 'a', true]
console.log([...new Set(arr)]) // [1, "a", true]
let arr1 = [4, 6, 8, 2, 1]
let arr2 = [3, 6, 8, 7, 1]
// 合并并去重
Array.from(new Set([...arr1, ...arr2]))) //[4, 6, 8, 2, 1, 3, 7]
// 交集
Array.from(new Set([...arr1])).filter(item => arr2.includes(item)) // [6, 8, 1]
[...new Set([...arr1])].filter(item => new Set(arr2).has(item)) // [6, 8, 1]
// 差集
Array.from(new Set([...arr1])).filter(item => !arr2.includes(item)) // [4, 2]
[...new Set([...arr1])].filter(item => !new Set(arr2).has(item)) // [4, 2]
数据结构 Map
Map类似于对象,也是键值对的集合,但是’键’不限于字符串.各种数据的值(包括对象)都可以当成键,也就是说,Object结构提供了’字符串–值’的对应,Map提供了’值–值’的对应.
创建map数据结构
1
2
3
4
5
6
7var map = new Map([
['a', 1],
['b', 2]
])
console.log(map) // Map(2) {"a" => 1, "b" => 2}
// Map的属性size
console.log(map.size) // 2map.set(key,value)
设置值,返回整个map结构,如果可以已经有值,则键值会被更新,否则新生成该键.1
2map.set('name', 'tew').set('id', 001)
console.log(map) // {"a" => 1, "b" => 2, "name" => "tew", "id" => 1}map.get(key)
get方法读取key对应的键值,如果找不到key,返回undefined1
2console.log(map.get('name')) // tew
console.log(map.get('age')) // undefined.map.delate(key)
删除某个键,返回布尔值true成功,false失败1
2
3console.log(map.delete('id')) // true
console.log(map.delete('age')) // false
console.log(map) // Map(3) {"a" => 1, "b" => 2, "name" => "tew"}map.has(key)
判断某个键是否在当前map对象之中1
2console.log(map.has('name')) // true
console.log(map.has('age')) // falsemap.keys()
返回所有的键名map.values()
返回所有的键值map.entries()
返回所有键值对1
2
3console.log(map.keys()) // MapIterator {"a", "b", "name"}
console.log(map.values()) // MapIterator {1, 2, "tew"}
console.log(map.entries()) // MapIterator {"a" => 1, "b" => 2, "name" => "tew"}map.forEach(value, key, map)
遍历map每个成员1
2
3
4map.forEach(function(value, key, map){
console.log(key+'--'+value) // a--1 b--2 name--tew
console.log(map) // Map(3) {"a" => 1, "b" => 2, "name" => "tew"}
})map.clear()
清除所有数据,没有返回值1
2map.clear()
console.log(map) // Map(0) {}map的键是基本数据类型时,只要两个值严格相等,map将其视为一个键,但NaN不严格相等与自身,但map将其视为同一个键
1
map.set(NaN, 10).set(NaN, 20) // Map(1) {NaN => 20}
map的键是对象的时候,比较的是引用(内存地址),只有引用地址一样才可以
1
2
3map.set({}, '对象').set({}, '对象')
console.log(map) // Map(3) {{…} => "对象", {…} => "对象"}
console.log(map.get({})) // undefined
Iterrator和for-of循环
Iterator(迭代器)是一种接口,为不同的数据结构,提供统一的访问机制,任何数据结构只要部署Iterator接口,就可以完成遍历操作,而且这种遍历操作是依次处理数据结构的所有成员
1 | const arr = [1, 2] |
- Iterator遍历(使用
for of
) 为各种数据结构,提供统一简便的访问接口使成员能够按某种次序排列 Iterator的遍历过程
- 创建一个指针对象,指向当前数据结构的起始位置,遍历器对象本质就是指针对象
- 每一次调用next方法都会返回当前指针所对应的成员的信息,返回一个包含value和done两个属性的对象,其中,value属性就是当前成员的值,done属性是布尔值,表示遍历是否结束.
- 凡是具有Symbol.iterator 属性的数据结构都具有Iterator接口 (数组 Set Map 类数组)
- 对象是没有Symbol.iterator属性
1
2
3
4
5
6
7
8
9const arr = [1,2,3]
const set = new Set(["a",2])
const map = new Map([["a", 1]])
const obj = {a: 1}
console.log(arr[Symbol.iterator]) // ƒ values() { [native code] }
console.log(arr[Symbol.iterator]()) // Array Iterator {}
console.log(set[Symbol.iterator]()) // SetIterator {"a", 2}
console.log(map[Symbol.iterator]()) // MapIterator {"a" => 1}
console.log(obj[Symbol.iterator]) // undefiend
具备iterator接口的数据机构都可以进行
解构赋值
和扩展运算符
、for of遍历
操作for-in和for-of的区别
1
2
3
4
5
6
7
8/* for...in 主要是为遍历对象而设计的,某些情况下会以任意顺序遍历键名
for...of 不能遍历对象(没有Symbol.iterator属性的对象),可以与break、continue和return配合使用
*/
var arr = [1, 5, 20, 6]
for (var n of arr) {
if (n > 10) break
console.log(n)
}