简介

说明

        本文介绍ES6的新特性。

        ECMAScript 6.0(ES6)是JavaScript语言的标准。ES6在2015年6月正式发布,所以ES6又称ECMAScript 2015。

ES6新特性简介

ES6改动很大,可以简单分为四类


  1. 解决原有语法的不足
  1. 如:let,const
  1. 对原有语法的增强
  1. 如:解构、扩展、模板字符串、...操作符、箭头函数
  1. 新的功能
  1. 如:Object.assign()、Promise、Proxy、Reflect
  1. 新的数据类型和数据结构
  1. 如:Set、Map、class、迭代器、generator(生成器)

解决原有语法的不足

let


  1. 块级作用域
  2. 没有变量提升
  3. 不允许重复声明

const


  1. 声明一个只读的常量
  2. 其他与let相同。

对原有语法的增强

解构

数组的解构

根据数组对应的位置提取对应的值赋给对应的变量。

let arr = [1,2,3]
let [x, y, z] = arr;
console.log(x); //1
console.log(y); //2
console.log(z); //3

如果未取到对应的值,赋值“undefined”。

可以用...运算符

let [x, ...other] = arr

可以设置默认值

let [x='0', y, z] = arr

用途:字符串截取

const str = 'http://www.baidu.com?titile=article'
let [, strParam] = str.split('?')

对象的解构

根据属性名提取。

示例

const obj = {name: 'Tony', age: 18};
const {name, age} = obj;
console.log(name); //Tony
console.log(age); //18

如果想换一个变量名而且添加默认值

const {name: objName='www', age} = obj

用途:代码简化

const {log} = console
log('This is log')

对象简化写法


  1. 如果key与value变量名相同,省略“: value”
  2. 省略函数:function
  3. 计算属性:[表达式]

let name = 'Tony'

const user = {
name,
sayHi(){
console.log('hello')
},
[Math.random()]: 'This is computed'
}

// 等价于
// const user = {
// name: name,
// sayHi: function (){
// console.log('hello')
// },
// [Math.random()]: 'This is computed'
// }

console.log(user)

箭头函数

箭头函数内的this指向上层对象。

普通函数内的this指向调用其函数的对象。

const name = 'Tony';

const person = {
name: 'Tom',

// 正常函数
fnNormal: function () {
console.log(this.name)
},

// 箭头函数
fnArrow: () => console.log(this.name),

// 异步函数
fnAsync: function () {
setTimeout(function () {
console.log(this.name)
}, 500)
},

// 异步箭头函数
fnAsyncArrow: function () {
setTimeout(() => console.log(this.name), 500)
}
}

person.fnNormal() //Tom
person.fnArrow() //Tony
person.fnAsync() //Tony
person.fnAsyncArrow() //Tom

...操作符

展开数组

const spreadArr = [1,2,3,4]
console.log(...spreadArr) //1 2 3 4
// ES5代替方案
console.log.apply(this, spreadArr) //1 2 3 4

收起剩余数据

        收取剩余参数:取代arguments,arguments是一个类数组,...操作符是一个数组类型,可以使用数组方法。

1、仅使用一次

2、放在参数最后

const fn = function (x, ...y) {
console.log(y.slice(0))
}
fn(1,2,3,4,5); //[2, 3, 4, 5]

模板字符串

1、可换行

2、可使用插值表达式添加变量,变量也可以替换为可执行的js语句:

let str = `生成一个随机数:${ Math.random() }`

        标签模板字符串,标签相当于一个自定义函数,自定义函数的第一个参数是被差值表达式截取的数组。例如:

const name = 'Tony';
const isMan = true
const tagFn = function (strings, name, isMan) {
let sex = isMan ? 'man' : 'woman';
return strings[0] + name + strings[1] + sex + strings[2]
}
const result = tagFn`hey, ${name} is a ${isMan}.`;
console.log(result); //hey, Tony is a man.

字符串的扩展方法

1、includes

2、startWith

3、endsWith

函数参数:支持默认值

只有当参数为不传或传入undefined时使用默认值。

const fn = function (x=1, y) {
console.log(x)
console.log(y)
}
fn();

结果

1
undefined

新的功能

Object.assign()

合并多个对象,第一个参数就是最终的返回值,如果对象的属性名相同,后面的覆盖前面的。

用途:复制对象,给options属性赋默认值。

let objA = {
a: 'aa',
b: 'bb'
}

let objB = {
b: 'dd',
c: 'ee'
}

let result = Object.assign({}, objA, objB)
result.a = 'cc'
console.log(objA, result) //{a: "aa", b: "bb"} {a: "cc", b: "dd", c: "ee"}

Object.is()

判断两个值是否相等,返回布尔值

用途:ES5中,对于0的判断不区分正负值,-0 == +0返回true,NaN == NaN返回 返回false;

Object.is()规避了这些问题

console.log(Object.is(+0, -0));   //false
console.log(Object.is(NaN, NaN)); //true

Promise

说明

        异步编程的一种解决方案。语法上Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果

特点


  1. 状态不受外界影响(有三种状态:padding, fulfilled, rejected)
  2. 一旦状态改变就不会再变。

示例

// 实例化Promise对象
const p = new Promise(function(resolve, reject){
setTimeout(()=>{
let data = '数据库中的用户数据'
// resolve(data)
let err = '数据读取失败'
reject(err)
}, 1000)
})

p.then((value)=>{
console.log('success')
console.log(value)
},err=>{
console.log('failure')
console.log(err)
})

结果

failure
数据读取失败

Proxy

说明

可以为对象创建代理。

示例

const person = {
name: 'www',
age: '20'
}

const personProxy = new Proxy(person, {
get(target, key) {
return target[key] ? target[key] : 'default'
},
set(target, key, value) {
target[key] = value % 2 ? value : 99
}
})
console.log(person.xxx) // undefined
console.log(personProxy.xxx) // default
console.log(personProxy.age) // 20
personProxy.age = 100
console.log(personProxy) //{name: "www", age: 99}

这里注意的一点是,这里被拦截的是”personProxy“,而不是”person“。

Proxy与Object.definedProperty()的比较:

Proxy

Object.definedProperty()

监听的项

get, set,has、deleteProperty ... 等

只能监听get,set

数组操作

监听的整个对象的行为,所以通过set方法能够监听到

需要指定该对象的属性名。对于数组来说,就是指定数组的下标,是监听不到数组的push,pop等操作的。

侵入性

非侵入


需要指定具体需要监听对象的属性名。

如果想要监听一个含有多个属性的对象的读写行为,definedProperty需要遍历这个对象的所有属性


Reflect

        Reflect是封装操作对象的统一API。

在之前的ES5中,操作对象有很多种方式,对于不同的操作行为,使用的方式却不同。例如:

const obj = {
name: '111',
age: '22'
}
// 判断对象某个属性是否存在
console.log('name' in obj)
// 删除某个属性
console.log(delete obj['name'])
// 获取对象key
console.log(Object.keys(obj))

Reflect的目的是使用同一套方式去操作对象 :

const obj = {
name: '111',
age: '22'
}
// 判断对象某个属性是否存在
console.log(Reflect.has(obj,'name'))
// 删除某个属性
console.log(Reflect.deleteProperty(obj, 'name'))
// 获取对象key
console.log(Reflect.ownKeys(obj))

新的结构

class

说明

        原ES5语法的没有成型的类的概念。而面向对象编程又离不开类的概念。因此ES6加入class。

class的特点是:


  1. constructor方法是类的默认方法,通过new 命令生成对象时会调用该方法,如果声明类时没有定义constructor,会默认定义一个空的。
  2. 生成实例时必须用new ,不用会报错
  3. 不存在变里提升(先定义类,再new实例)

示例

class People {
constructor (name) {
this.name = name
}
say () {
console.log(this.name)
}
}
const p = new People('tony')
p.say()

ES5的写法是:

function People (name) {
// 设置实例属性
this.name = name;
}
// 设置实例的共享方法
People.prototype.sayHi = function () {
console.log(this.name)
}
let p = new People('tom')
p.sayHi()

Set

说明

不重复的集合。

示例

const s = new Set()
s.add(1).add(2).add(3)
console.log(s) //{1, 2, 3}
console.log(s.size) // 3

const arr = [1,2,3,2,4]
console.log([... new Set(arr)]) //[1,2,3,4]

Map

说明

        ES5中的对象key只能是字符串,Map的key可以是任意数据类型, 可以通过get, set, has等操作map。

示例

const m = new Map()
const tom = {name: '99'}
m.set(tom, 90)
console.log(m.get(tom)) //90
m.forEach((value, key) => {
console.log(value, key) //90 {name: '99'}
})

Symbol

说明

用途


  1. 防止全局对象中,某个属性名重名,产生冲突
  2. 定义私有属性,外部访问不到,且遍历不到。

示例

const s = Symbol('描述')
console.log(s); //Symbol(描述)
const obj = {
[Symbol('私有属性')]: '11'
}
console.log(obj) //obj对象Symbol('私有属性')这个属性外部访问不到
console.log(Object.keys(obj)) //[]
console.log(Object.getOwnPropertySymbols(obj)) //[Symbol(私有属性)]

const s1 = Symbol.for('111')
const s2 = Symbol.for('111')
console.log(s1 === s2) //true

Iterator(迭代器)

Iterator的3个作用:


  1. 为各种数据提供统一的,简便的访问接口
  2. 使数据结构的成员能按某种次序排列
  3. 主要供for...of用

原生具备iterator接口的数据(可用for...of遍历)


  1. String
  2. Array
  3. Arguments
  4. Set
  5. Map
  6. TypedArray
  7. NodeList

流程

        数组的原型对象上有一个Symbol内置属性Symbol.iterator方法,该方法会返回一个iterator对象,该对象包含一个next()方法。

        调用iterator.next()会返回一个迭代器结果对象它包含两个值:value和done。value为遍历的item,done为当前数据是否遍历完成。

示例

const food = ['鱼香肉丝','糖醋里脊','酸菜鱼']
for(let item of food){
console.log(item)
}

let iterator = food[Symbol.iterator]()

console.log(iterator.next()) // {value: "鱼香肉丝", done: false}
console.log(iterator.next()) // {value: "糖醋里脊", done: false}
console.log(iterator.next()) // {value: "酸菜鱼", done: false}
console.log(iterator.next()) // {value: undefined, done: true} true 表示遍历已经结束

for...of遍历

ES5:使用for ... in 遍历键值对结构数据,使用forEach遍历数组

ES6:使用for...of来统一遍历可迭代的数据类型。

// 遍历数组
const arr = [1,2,3]
for (const item of arr) {
console.log(item)
}

// 遍历Set
const s = new Set()
s.add(1).add(2).add(3)
for (const item of s) {
console.log(item)
}

// 遍历Map
const m = new Map([
['name','昵称'],
['title', '标题']
])
for (const [key, value] of m) {
console.log(key)
console.log(value)
console.log(m.get(key))
}

// 遍历set初始化后的map结构
const newSet = new Set([
['name','昵称'],
['title', '标题']
])
const newMap = new Map(newSet)
for (const [key, val] of newMap) {
console.log(key)
console.log(val)
}

// 遍历对象报错 Uncaught TypeError: obj is not iterable
const obj = {
name: 'ttt',
age: '19'
}
for (const [key, val] of obj) {
console.log(key, val)
}

Generator

说明

用途:处理异步调用回调嵌套的问题。

        在函数名前面加一个"*",函数就变为生成器函数,执行该函数时,里面的函数不会立即执行,而是会返回一个生成器对象,调用生成器对象的.next方法函数开始执行,当遇到”yield“关键字,函数会停止执行,并把yield的值当做next方法返回对象的value; 当下次调用next方法时,函数从当前位置开始继续执行。

        生成器函数执行后返回的生成器对象generator,内部也是实现了迭代器接口,所以可以使用for...of来遍历。

示例

function *generateFunction () {
console.log('111')
yield 100
console.log('222')
yield 200
console.log('333')
yield 300
}
let generator = generateFunction()

console.log(generator.next()) //111 {value: 100, done: false}
console.log(generator.next()) //222 {value: 200, done: false}
console.log(generator.next()) //333 {value: 300, done: false}

其他网址

​ES6新特性汇总 - 简书​

​面试题之ES6的新特性(详细) - 知乎​