介绍
ECMA标准简称ES,ES6.0发布于2015年6月故也称为ES2015,之后发布的版本统称为ES6。
变量与常量
作用域
- 全局
- 函数作用域
- 块级作用域(新增):相对于let、const而言
let变量
- let不存在变量提升,必须先定义再使用
- 在同一个作用域中,let不能重复定义变量
- for循环中使用let,()中相当于父级作用域,{} 相当于子级作用域
const常量
- 不存在提升,必须先定义再使用
- 在同一个作用域中,不能重复定义
- 定义时必须赋值
- 一经定义不允许修改
Symbol
- 新增数据类型
- 不可以使用new关键字
- 返回一个唯一值:一般用作对象的key,定义一些唯一或者私有的东西
- 属于基本类型
- 作为对象的key时,用for-in循环不出来(Reflect.ownKeys())
let s = Symbol('a')
console.log(s)
解构赋值
- 数组解构赋值
let [a, b, c] = [0, 1, 2]
console.log(a, b, c)
- 对象解构赋值
//可以为某一个键设置别名,例如:将name设置为ename
let {name:ename, age} = {name: 'ann', age: 18}
console.log(ename, age)
- 注意:左右结构格式必须保持一致
- 结构时可以设置默认值(当该元素为undefined时生效,null不生效)
let [a, b, c = '默认'] = [1, 2]
console.log(a, b, c)
let [x, y, z = '默认'] = [1, 2, null]
console.log(x, y, z)
- 交换两个数的位置
let a = 123
let b = 456;
[a, b] = [b, a]
Set
- 一种新的数据解构,类似于数组,但不能有重复值
//语法
let setArr = new Set([1,2])
//方法
//添加
setArr.add(3)
//删除
setArr.delete(3)
//清空
setArr.clear()
//查找
setArr.has(3)
//属性
//查看长度
setArr.size
//for-of循环:key与value相同
- 利用其不重复但特性,可以用于数组去重
let arr = [1,2,3,1]
let setArr = new Set(arr)
console.log([...setArr])
- new Set([]),new WeakSet({})
- WeakSet没有size,clear
Map
- 一种新的数据结构,类似于json,但json的key只能是字符串,而Map的key可以是任意类型
//语法
let mapJson = new Map()
//方法
//设置
mapJson.set(key, value)
//获取
mapJson.get(key)
//删除
mapJson.delete(key)
//清空
mapJson.clear(key)
//查找
mapJson.has(key)
//for-of循环
- WeakMap的key只能是对象
字符串
字符串模版
//优点:更加优雅直观
let name = 'ann'
console.log(`Hello,I am ${name}`)
新增方法
- includes():查找,返回true/false
- startsWith(target):是否以谁开头
- endsWith(target):是否以谁结尾
- padStart(strLength,target):往前填充
- padEnd(strLength,target):往后填充
- repeat(count):重复
数字
Number新增方法
- Number.isNaN():判断是否是NaN
- Number.isFinite():判断是否是数字
- Number.isInteger():判断是否是整数
- Number.parseInt():转化为整数
- Number.parseFloat():转化为浮点数
- Number.isSafeInteger():判断是否是安全整数
//安全整数范围:-(2^53-1)~2^53-1
//次方在程序中可以用**表示,比如2的53次方为2**53
//安全整数常量:Number.MAX_SAFE_INTEGER,Number.MIN_SAFE_INTEGER
Math新增方法
- Math.trunc():截取整数部分
- Math.sign():判断一个数到底是正数(1)、负数(-1)、0,如果参数不是数字则返回NaN
- Math.cbrt():计算一个数的立方根
函数
默认参数
function func1({x=1,y=2}={}){
}
func1()
箭头参数
() => {}
//this指向其上下文
//因为没有自己的this,所以不能当作构造函数,无法实例化
//没有arguments参数,可以使用...arr获取参数
…
//扩展运算符
let a = [1,2,3]
console.log(...a)
//重置运算符
let func2 = (...a) => {
console.log(a)
}
func2(1,2,3)
//剩余参数(必须放在最后)
let func3 = (a,b,...c) => {
console.log(a,b,c)
}
func3(1,2,3,4,5)
数组
ES5循环
- forEach(callback(item,index){},this指向):循环
- map(callback(item,index){},this指向):映射,配合return返回一个新的数组
- filter(callback(item,index){},this指向):过滤,只留下符合条件的元素
- some(callback(item,index){},this指向):类似于查找,数组中只要有一个元素符合条件就返回true
- every(callback(item,index){},this指向):数组中所有元素都符合条件返回true
- 注意: 当循环回调函数为箭头函数时,this始终指向其上下文
ES6循环
- for…of…
let arr = [0, 1, 2];
for(let [index,val] of arr.entries()){
console.log(index, val);
}
- 新增Array.keys():数组中的下标集合
- 新增Array.entries():数组中的项集合,每一项是下标和值的数组
新增方法
- Array.from():将类数组转换成数组
- Array.of():将一组值转换成数组
- 扩展运算符:复制数组
let arr1 = [1,2,3]
let arr2 = [...arr1]
- Array.find((item,index,arr)=>{}):查找,找到第一个符合条件的数组成员,没有则返回undefined
- Array.findIndex((item,index,arr)=>{}):查找,找到第一个符合条件的数组成员位置,没有则返回-1
- Array.fill(target,start,end):填充
- Array.includes(target):替代indexOf,返回值为true/false
对象
简洁语法
let obj = {
name,
get(){}
}
新增方法
- Object.is(target1,target2):判断是否相等
- Object.assign(target,source1,source2,…):合并对象。使用场景:合并参数;复制对象。
- Object.keys(),Object.values(),Object.entries()
Promise
- 作用:解决异步回调问题
- 基本用法
new Promise((resolve,reject)=>{
if(true){
resolve();
} else {
reject();
}
}).then(res=>{},err=>{}).catch(err=>{})
Promise.resolve()
//将现有的东西转换成一个Promise对象,resolve状态
//相当于如下
new Promise(resolve=>{resolve()})
Promise.reject()
//将现有的东西转换成一个Promise对象,reject状态
//相当于如下
new Promise((resolve,reject)=>{reject()})
Promise.all([p1,p2,p3]).then(res=>{
console.log(...res)//返回的是一个数组
})
//把一组promise打包放到一个数组中,打包后还是一个promise对象。必须确保每一个promise对象都是resolve状态
Promise.race([p1,p2,p3])
//把一组promise打包放到一个数组中,打包后还是一个promise对象。只要有一个promise对象是resolve的就返回
- 构造函数中的 resolve 或 reject 只有第一次执行有效,多次调用没有任何作用
generator
1. 基础
- Iterator接口的具体实现方式
- 解决异步深度嵌套问题
- 缺点:需要手动调用
//语法
//定义
function * show(){}
//或者function* show(){}
//执行
show().next()
//配合yield使用
function * show(){
yield 'step1'
yield 'step2'
return 'end'
}
let g = show()
g.next() //{value: "step1", done: false}
g.next() //{value: "step2", done: false}
g.next() //{value: "end", done: true}
g.next() //{value: undefined, done: true}
2. 循环
- 使用for-of
- 使用解构
- 使用扩展运算符
- 只能遍历yield,不执行return
3. 使用场景
//结合axios数据请求
function * getUserInfo(){
let name = yield 'ann'
yield axios.get(`https://api.github.com/users/${name}`)
}
let g = getUserInfo()
let userName = g.next().value
g.next(userName).value.then(res=>{
console.log(res.data)
})
解决异步问题
- 回调函数
- 事件监听
- 发布订阅
- Promise对象
async
语法
async function fn(){ //表示异步
let result = await xxx //表示后面结果需要等待
}
特点
- await只能放在async函数中
- 相比genrator语义化更强
- await后面一般跟promise对象,也可以是数字、字符串、布尔值
- async函数返回的是promise对象
- await后面的Promise状态变为reject时,async整个函数都会中断执行
为了避免reject状态中断执行,可以使用
- try{}catch(e){}
- promise对象的catch(err=>{})
模块化
ES6统一了服务端和客户端模块规范
- 如何定义模块?如何使用模块?
//常规
export const a = 1
export const b = 2
import {a,b} from 'xxx'
console.log(a,b)
//解构
const a = 1
const b = 2
export {a,b}
import {a,b} from 'xxx'
console.log(a,b)
//别名
//定义时别名
const a = 1
const b = 2
export a as x
export b as y
import {x,y} from 'xxx'
console.log(x,y)
//使用时别名
export const a = 1
export const b = 2
import {a as x, b as y} from 'xxx'
console.log(x,y)
//整体引用
export const a = 1
export const b = 2
import * as modules1 from 'xxx'
console.log(modules1.a, modules1.b)
//整体定义
export default const a = 1
import modules1 from 'xxx'
console.log(modules1)
//混合
export default const a = 1
export const b = 2
import a,{b} from 'xxx'
console.log(a, b)
- import特点:
- ‘import 路径’相当于直接引入文件
- 无论引用多少次,只会导入一次。
- 提升,首先执行。
- 模块中的数据更新时,引用的地方也会更新。
- ‘import 路径’不能写在if判断中。
- import(路径)
- 类似于require,返回的是一个Promise对象,可以使用.then()
- 按需加载
- 动态加载
- 可以放在if判断中
- 可以结合Promise.all()使用
Promise.all([
import('xxx1'),
import('xxx2'),
]).then([module1, module2]=>{
//模块都加载完后执行
})
类与继承
ES5中的类(用函数模拟)
function Person(name){
this.name = name;//属性
}
Person.prototype.showName = function(){//方法
console.log(this.name);
}
let person = new Person('ann');
ES6中的类(class)
- 基础
//注意:类中的方法分隔切勿加逗号
class Person{
constructor(name){//属性
this.name = name;
}
showName(){//方法
console.log(this.name);
}
}
//以上或者可以写成变量声明形式const Person = class{}(不推荐)
let person = new Person('ann');
- 注意
//1 class不存在提升
//2 this指向其上下文
//3 getter、setter:
class Person{
constructor(){}
get name(){
console.log('监听:获取属性“name”');
}
set name(val){
console.log('监听:设置属性“name”为'+val);
}
}
let person = new Person();
- 静态方法:类自身的方法
class Person{
constructor(){}
showName(){
console.log(this.name);
}
static showPerson(){
console.log('这是静态方法');
}
}
Person.showPerson();//调用
- extends继承
//父类
class Person{
constructor(name){
this.name = name;
}
showName(){
console.log(this.name);
}
}
//子类
class Student extends Person{
constructor(name, skill){
super(name);
this.skill = skill;
}
showName(){
super.showName();
console.log('I am a student');
}
}
//super指代父级
Proxy
Reflect
ES2018新增(了解)
正则
- 命名捕获
//格式:(?<捕获名称>)
let time = '2019-10-29'
const r = /(?<year>\d{4})-(?<month>\d{2})-(?<date>\d{2})/
let {year, month, date} = time.match(r).groups
console.log(year,month,date)
- 反向命名捕获
//格式:\k<捕获名称>
let ename = 'zhu-zhu'
const r = /^(?<name>zhu)-\k<name>$/
//const r = /^(zhu)-\1$/ //旧: \次数
console.log(r.test(ename))
- 替换
//格式:$<捕获名称>
//=>xx/xx/xxxx
let time = '2019-10-29'
const r = /(?<year>\d{4})-(?<month>\d{2})-(?<date>\d{2})/
console.log(time.replace(r,'$<month>/$<date>/$<year>'))
- dotAll模式:正则中.表示任意东西但不包括\n,该模式正是修复了这一问题,用s表达。