ES6
ES6 基础概念
let、const- 模板字符串
- 解构赋值
- 扩展运算符
- 箭头函数
classSet、MapPromiseProxy、ReflectSymbolimportGenerator、async、awaitIterator和for...of
变量声明 let 、 const
在 ES6 之前,通常使用 var 来声明变量,但是 var 声明变量存在诸多问题
- 只有 全局作用域 和 函数作用域
- 存在变量提升问题
详细可见 JS 变量提升
而 ES6 引入了 let 和 const 来声明变量,来避免上述问题
let通常用于声明变量const用于声明常量- 不会有变量提升问题,都是块级作用域
- 在声明变量之前的地方,存在暂时性死区,获取变量会报错
模板字符串
模板字符串使用反引号 `` 来包裹,支持字符串拼接,支持表达式,甚至调用函数
const name = 'lafen'
const getAge = () => 18
const str = `my name is ${name}, i am ${getAge()}`
// 甚至用来调用函数
getAge``解构赋值
按照一定的模式,从对象和数组中提取值,简化赋值过程
- 对象解构
- 数组解构
- 字符串解构
// 解构对象
const obj = { x: 1, y: 2 }
const { x, y } = obj
// 解构数组
const arr = [1, 2]
const [a, b] = arr
// 解构字符串
const str = 'hello'
const [c, d] = str扩展运算符
扩展运算符 ... 用来将一个数组或者字符串拆分成单个元素,也可以做剩余参数
const name = 'lafen'
// 展开字符串成数组
const arr = [...name]
const obj = {
name,
age: 18,
}
// 展开对象
const params = {
...obj,
}
// 剩余参数
const getArgs = (...args) => args箭头函数
ES6 箭头函数的提出是为了消除函数的二义性。
早期 js 设计简单,普通函数即作为函数调用,也作为类使用,但这就容易导致混乱,虽然可以通过函数名首字母大写来约定是类,但总有不规范书写或随意混用的情况
所以 ES6 中做了新的规范,函数使用箭头函数声明
- 无
this - 无
arguments - 无 原型链
- 不可
new - 可以省略
return
const double = a => a * 2class
类用 class 声明
constructor构造函数,可用来初始化实例属性- 属性描述符
public默认值,可访问protected受保护属性,可被子类访问private私有属性,只在当前类中使用,可以用#简写static静态属性、静态块,直接通过类访问
- 取值函数
get、存值函数set可以拦截该属性的读写操作 new.target获取当前类extends继承
Set 、 Map
Set
Set 实例类似数组,但成员值都是唯一的
sizeadd()delete()has()keys()values()forEach()entries()union()并集intersection()交集difference()差集,返回第一个集合存在但第二个集合不存在的元素symmetricDifference()对称差集,返回两个集合所有独一无二的元素,即去除重复成员isSubsetOf()判断是否为子集isSupersetOf()判断是否为超集isDisjointFrom()判断两个集合是否不相交,即无共同成员
WeakSet
WeakSet 与 Set 类似,但成员只能是 对象 和 Symbol 值,并且键是弱引用,元素可能随着垃圾回收被回收,所以元素不可遍历,不可获取 size
Map
js 的对象,本质上是键值对的集合,即 hash 结构,但只能用字符串做 key ,而 Map 可以用各种类型的数据做 key
WeakMap
WeakMap 与 Map 类似,但键只能是 对象 和 Symbol 值,并且键是弱引用,不会导致内存泄漏,所以键不可遍历,不可获取 size
WeakRef
WeakRef 对象用于直接创建目标对象的弱引用,垃圾回收机制不会计入这个引用,不会影响目标对象的垃圾回收(但是创建弱引用当次事件循环不会被垃圾回收)
deref()判断原始对象是否被垃圾回收
Promise
异步编程必备
then()catch()finally()Promise.all()Promise.race()Promise.allSettled()Promise.any()Promise.resolve()Promise.reject()Promise.try()Promise.withResolvers()
注意区别以下
Promise.all()所有的状态都成功才返回成功,否则失败Promise.race()哪个状态先变就取哪个,无论成功或失败Promise.allSettled()所有状态都变了才返回一个数组,无论成功或失败Promise.any()只要有一个状态成功就返回成功,所有状态失败了就返回失败Promise.try(cb)尝试使用异步方式执行回调函数cb,否则为同步调用,取决于cb是否为异步函数Promise.withResolvers()获取Promise的resolve、reject方法 和promise实例,方便异地操作
Proxy 、 Reflect
两个是非常强大的内置对象,通常一起使用来提供更方便的对象操作和控制
Proxy
Proxy 是一个构造函数,用于创建一个对象的代理,从而可以对对象进行自定义操作,例如属性查找、赋值、枚举等
const target = {}
const handler = {
get(target, prop, receiver) {
console.log('get: ', prop)
return Reflect.get(target, prop, receiver)
},
set(target, prop, value, receiver) {
console.log('set: ', prop, '=', value)
return Reflect.set(target, prop, value, receiver)
}
}
const proxy = new Proxy(target, handler)
proxy.foo = 123 // set: foo=123
console.log(proxy.foo) // get: foo 然后再输出 123以上例子即 Proxy 拦截 target 的 get 和 set 操作
Reflect
Reflect 是一个内置的静态对象,它提供拦截 js 操作的方法。这些方法与 Proxy 的 handler 方法一一对应
Reflect 主要目的是提供一个标准化的方法拦截 js 操作,以便开发者进行对象的元编程操作
const obj = { foo: 123 }
console.log(Reflect.get(obj, 'foo')) // 123
Reflect.set(obj, 'foo', 456)
console.log(obj.foo) // 456Symbol
ES6 新的数据类型,表示独一无二的值,传入的参数为当前 Symbol 的描述,可以不传
Symbol可以作为对象唯一keySymbol作为key时不可遍历,但可以通过Object.getOwnPropertySymbols()获取,另外Reflect.ownKeys()也可以获取到Symbol类型的keySymbol.describe()获取Symbol的描述Symbol.for()获取Symbol,传入相同的参数,返回相同的Symbol,无此Symbol时会创建新的Symbol,注意返回值是全局的,无论在iframe中还是service worker中都是同一个SymbolSymbol.keyFor()获取Symbol类型值的key
import
ES6 模块化规范,即 import 和 export 模块导入、导出语法
export只能导出三种类型:变量、函数、类export只能出现在模块顶层作用域export导出的变量就是本来的名字,但是也可以使用as来重命名export default导出一个默认变量,只能有一个默认import导入的变量都是只读的import时可以使用as做符号绑定import是静态编译的,编译阶段就执行,不可使用表达式和变量这些运行阶段才能得到的语法结构,同样是模块顶层使用export和import可以结合一起使用,相当于转发一下,当前模块并没有导入
此外还可以使用 import() 来动态加载模块,返回一个 Promise 对象,因此可以做到 按需加载、条件加载、动态模块路径 等功能
import 还可以暴露一些模块内部元信息
import.meta获取当前模块的元信息,在模块内部使用import.meta.url获取当前模块的路径 URLimport.meta.scriptElement获取加载当前模块的script标签,相当于document.currentScript
Generator 生成器的了解
Generator (生成器)是一种特殊的函数,它可以暂停执行并在需要时恢复执行。由 ES6 引入,使用 function* 定义
- 暂停和恢复执行:在函数体内部,使用
yield关键字暂停,并产生一个值,然后使用next()恢复执行,并将新的值传递给yield表达式 - 迭代器和可迭代对象:
Generator函数返回一个迭代器对象,可直接使用for...of来遍历生成的值 - 惰性求值
- 状态保存
function* generatorFunction() {
yield 'Hello';
yield 'World';
return 'Ending';
}
const generator = generatorFunction(); // 返回可迭代对象
console.log(generator.next().value); // 输出: Hello
console.log(generator.next().value); // 输出: World
console.log(generator.next().value); // 输出: Ending
console.log(generator.next().done); // 输出: true,表示迭代器已完成Generator 函数适合用于处理 异步编程 和 迭代。但目前通常都使用 async/await 来做异步编程更直观
Iterator 和 for...of
JS 中原来表示集合的有 Array 和 Object ,但是现在加了 Set 和 Map ,所以需要一种统一的接口机制来遍历处理不同的集合结构,即 遍历器 Iterator
Iterator 提供统一的访问机制 for...of ,任何数据结构只要部署 Symbol.iterator 接口,就可以被 for...of 循环遍历
ArrayMapSetStringTypedArray- 函数
arguments对象 NodeList对象
以上数据结构原生即具有 Symbol.iterator 接口,在 解构赋值、扩展运算符 当中,会默认调用 Symbol.iterator 方法
注意 Object 没有 Symbol.iterator 接口,但可以通过 Object.keys() 后再遍历,或 使用 for...in 遍历,但 for...in 遍历时,会遍历原型上的自定义属性