ES6基础

111 阅读8分钟

ECMAScript 6.0(简称ES6)是javascript下一代标准,它的目标是使javascript可以编写大型复杂的应用程序,成为企业级开发语言。

异步方案

  • Promise
  • async/await
  • Generator(生成器)

Promise

解决回调地狱(如ajax请求根据上一次请求结果做下一次请求,层层回调,难以维护) 三种状态

  • pending
  • rejected
  • resolved

实例方法

  • then(resolve, reject)接受成功和失败两个回调函数。可以不写reject回调,在catch方法中捕获异常信息
  • catch()捕获异常信息
  • finally()成功与否都会执行

对象方法

  • all()

传入一个promise数组,所有promise都成功,才会之行resolve回调,只要有一个失败,执行reject,返回第一个执行失败的结果。

Promise.all([pro1, pro2, pro3]).then(function(res){
    console.log(res) // res为数组,分别几个promise执行成功的结果
}, function(err){
    console.log(err) // err为第一个失败结果
})
  • race()

同样传入一个promise数组,一旦有一个promise执行完毕,就返回结果。

let a = new Promise(function(resolve, reject){
    setTimeout(() => {
        reject(1)
    }, 1000);
})
let b = new Promise(function(resolve, reject){
    setTimeout(() => {
        resolve(2)
    }, 2000);
})
let c = new Promise(function(resolve, reject){
    setTimeout(() => {
        resolve(3)
    }, 3000);
})
Promise.race([a, b, c]).then(function(res) {
    console.log(res, 'resolved')
}, function(err) {
    console.log(err, 'err') //1 'err'
})

手撕Promise

// TODO

async/await

采用同步思想处理异步代码

  • await只能在async函数内部使用,否则会报语法错误

  • await阻塞程序,直到promise执行resolve后才会继续执行

  • 自动将常规函数转换成Promise(即使函数内部返回非promise, 也会包装成promise),返回值也是一个Promise对象

  • 如果async函数return一个值,这个值就是Promise对象中resolve的值,若无return,这个值为undefined

  • 如果async函数throw一个值,这个值就是promise对象种reject的值

async函数写法:

async function imAsync(num) {
  if (num > 0) {
    return num // 这里相当于resolve(num)
  } else {
    throw num // 这里相当于reject(num)
  }
}

imAsync(1).then(function (v) {
  console.log(v); // 1
});

// 注意这里是catch
imAsync(0).catch(function (v) {
  console.log(v); // 0
})

Promise写法:

function imPromise(num) {

    return new Promise(function (resolve, reject) {
      if (num > 0) {
        resolve(num);
      } else {
        reject(num);
      }
    })
  }
  
  imPromise(1).then(function (v) {
    console.log(v); // 1
  })
  
  imPromise(0).then(function (v) {
    console.log(v);
  }, function(v){
    console.log(v); // 0
  })
  

错误处理

在async函数里,无论是Promise reject的数据还是逻辑报错,都会被默默吞掉,所以最好把await放入try{}catch{}中,catch能够捕捉到Promise对象rejected的数据或者抛出的异常


function timeout(ms) {

  return new Promise((resolve, reject) => {
    setTimeout(() => {reject('error')}, ms);  //reject模拟出错,返回error
  });

}
// 方式一
async function asyncPrint(ms) {

  try {

     console.log('start');

     await timeout(ms);  //这里返回了错误

     console.log('end');  //所以这句代码不会被执行了

  } catch(err) {

     console.log(err); //这里捕捉到错误error

  }

}

asyncPrint(1000);

// 方式二
async function asyncPrint(ms) {

  console.log('start');

  await timeout(ms)

  console.log('end');  //这句代码不会被执行了

}

asyncPrint(1000).catch(err => {

    console.log(err); // 从这里捕捉到错误

});

// 方式三
async function asyncPrint(ms) {

  console.log('start');

  await timeout(ms).catch(err => {  // 注意要用catch

    console.log(err) 

  })

  console.log('end');  //这句代码会被执行

}

asyncPrint(1000);

Generator

执行生成器函数,会返回一个迭代器对象(Iterator) 特征:

  • function关键字与函数名之间有一个星号
  • 函数内部使用yield标志内部状态

Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。调用return方法,会结束遍历并返回传入的值

function* gen() {  
    yield 1;  
    yield 2;  
    yield 3;  
    return 'ending';  
}  
  
let g = gen(); 
  
console.log(g.next());    // { value: 1, done: false }  
console.log(g.next());    // { value: 2, done: false }  
console.log(g.return(5));    // { value: 5, done: true }  
console.log(g.next());    // { value: undefined, done: true }

Symbol

基本数据类型,用来表示独一无二的值,它是JavaScript中的第七种数据类型,与undefined、null、Number(数值)、String(字符串)、Boolean(布尔值)、Object(对象)并列。

// 创建一个symbol值
const name = Symbol();
 
console.log(name);  //Symbol()
//只能转化为字符串和布尔值
console.log(String(name)); //Symbol()
console.log(Boolean(name)); // true
console.log(Number(name)) //error: Cannot convert a Symbol value to a number

// symbol值是唯一的,传参数没有意义仅用于辨别,即使传参一样,这两个变量也是不相等的
let a = Symbol('a');
let b = Symbol('b');

console.log(a === b) //false

  • Symbol.for()

通过传入的参数(假设为x),全局查找symbol,如找到返回该symbol。否则使用给定的key(x)在全局创建一个新的symbol。

const a = Symbol.for("aa");
const b = Symbol.for("aa");
console.info("a===b", a === b);  // a===b true
console.info("type", typeof a);  // type symbol
  • Symbol.keyFor()

用来获取全局 symbol 注册表中与某个 symbol 关联的键

let a = Symbol('hello');
let b = Symbol.for('world');

// 没有注册在全局
console.log(Symbol.keyFor(a)) // undefined 
// 注册在全局因此能找到
console.log(Symbol.keyFor(b)) // world 
  • 用途:作为属性名

symbol变量名作为对象属性名,可以避免属性重复被覆盖和重写,symbol变量作为属性名有三种写法:

let symValue = Symbol("a");

// 通过 [] 添加 symbol 值属性
let obj1 = {};
obj[symValue] = "Hi";

// 定义含有该 属性 的对象
let obj2 = {
  [symValue]: "Hi",
};

// 通过 defineProperty 添加该 symbol 属性
let obj3 = {};
Object.defineProperty(obj3, symValue, { value: "Hi" });

const / let

const

  • 不允许重复声明
  • 声明必须初始化
  • 值不允许修改
  • 块级作用域

let

  • 不允许重复声明
  • 块级作用域
  • 不存在变量提升

class类

class语法糖,让对象原型的写法更加清晰、更像面向对象编程的语法。

  • class声明类
  • constructor定义构造函数初始化
  • extends继承父类
  • super调用父级构造方法
  • static定义静态方法和属性
  • 父类方法可以重写

变量解构赋值

// 数组解构
const age = [8, 7, 9];
let [Mike, Lucy, Jay] = age;
console.log(Mike, Lucy, Jay) // 8, 7, 9

// 对象解构
const Susan = {
    age: 8,
    sex: 'Male',
    say: function() {
        console.log('hello');
    }
}
let {age, sex, say} = Susan
console.log(age) //8
say() // hello

箭头函数

  • 如果形参只有一个,则小括号可以省略
  • 函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的执行结果
  • 箭头函数 this指向声明时所在作用域下 this 的值
  • 箭头函数不能作为构造函数实例化
  • 不能使用 arguments

rest参数

rest参数是一个数组

function add(...args) {
    let sum = 0;
    for(let val of args) {
        sum += val;
    }
    return sum
}

add(2, 5, 3)  // 10

rest必须是最后一个形参

function(...args, val) {} // error

函数的length属性不包括rest参数

function add(a, b, c, ...args) {}
console.log(add.length) // 3

扩展运算符Spread

Spread操作符可以展开Iterable的对象,所以除数组外,Set、Map、Generator等也可以使用。

var map=new Map();
map.set("x",1);
map.set("y",2);
var arr=[...map];    // [["x",1],["y",2]]
 
var set = new Set();
set.add(1);
set.add(2);
set.add(1);
set.add(3);
var arr = [...set];  //[1, 2, 3]
 
function *myGen() {
  yield "hello";
  yield "world";
}
var arr = [...myGen()]; //["hello", "world"]

模块化(import / export)

导入所有的

//   main.js
import * as say from './say.js';

say.sayHi('John');
say.sayBye('John');
  • 统一暴露(export {})
//暴露
const a =()=>{
    console.log(999);
} 
const b = 2
const c = 1 
export{a,b,c}
//引入
import {a,b,c} from '@/api/api'
//使用
created(){
    a()
    console.log(b,c);
  }
  • 分别暴露(分别使用export)
//暴露
export  const a =()=>{
    console.log(999);
} 
export  const b = 2
export  const c = 1 
//引入
import {a,b,c} from '@/api/api'
//使用:可直接通过a,b,c获取
created(){
    a()
    console.log(b,c);
  }
  • 默认暴露(export default{})。
//暴露
const a =(data)=>{
    return data+1
} 
 
export default a
//引入
import a from '@/api/api'
 
//使用
created(){
    console.log(a(5));
  }

Set / Map数据结构

Set

是一种集合,由一堆无序的、相关联的且不重复的元素组成的组合。

  • has(数据):判断set中是否存在对应的数据,返回true/false
  • delete(数据):删除匹配数据
  • clear():清空整个set集合
  • size:获取set元素集合的元素数量(只读,不能赋值,赋值无效)
  • add():向set末尾添加元素,如果该元素存在则不操作

遍历Set

  • for...of...
  • forEach遍历
// Set是一个构造函数
let set = new Set()
set.add(5);
set.add("5)
// set不会用强制类型转换来判断内部值是否重复
console.log(set.size) // 5

let set2 = new Set()
let key1 = {}
let key2 = {};
set2.add(key1);
set2.add(key2)
// 给set添加多个对象,引用类型是两个不同的项
console.log(set2.size) // 2

Object.is(+0,-0) // false,但是在set中,添加+0后再添加-0,则无效

set与数组相互转换

const set = new Set([1,2,3,4,5])
const arr = [...set] // set是一个可迭代对象

//数组利用set去重,再转数组
let arr=[11,22,33,44,55,11,22]
let newArr=[...new Set(arr)]

//字符串去重,再转字符串
let str='asdkjflkajsdlf'
let newStr=[...new Set(str)].join("")

Map

是一种叫做字典的数据结构,是键与相对应的值的集合。跟Object结构的区别在于Map的”键“不仅限于字符串,它可以是任何类型的值。

  • has(key) :判断指定的键是否存在于 Map 中;
  • delete(key) :移除 Map 中的键以及对应的值;
  • clear() :移除 Map 中所有的键与值。
  • size:包含项目个数
  • set()
  • get()

遍历Map

  • for...of...
  • forEach遍历
var m = new Map();
var o = { p: "Hello World" };

m.set(o, "content");
m.get(o); // "content"

m.has(o); // true
m.delete(o); // true
m.has(o); // false

WeakSet

  • 只能是对象的集合,不像Set一样,可以是任何类型的集合。
  • 不可枚举,没有size属性
  • weakset中对象都是弱引用,如果外部没有引用该对象,那么垃圾回收制度会收回该对象所占用的内存,不管该对象是否还存在于weakset中。有助于防止内存泄露。

WeakMap

  • 只接受对象作为键名(null除外)
  • WeakMap的键名所引用的对象都是弱引用,一旦不再需要,键名对象和所对应的键值对会自动消失,不用手动删除引用。
  • 不可遍历,无size属性,不支持clear方法