ES6 万字极简总结,帮你快速过一遍知识点!
前言
由于常用es6语法不多,有时需要查阅一些不常用的函数或特性,需要重新查看阮一峰大佬的《ESCAScript 6 入门》,这段时间有空余,正好整理出来所有知识点,并附带解释。帮你快速唤醒es6的已经忘记的知识点!
来自阮一峰大佬《EMCAScript 6入门》总结精炼 部分解释取自MDN 内部包含部分
ES2017至ES2022标准知识点穿插
正文
let 和 const
let: 声明变量
const: 声明只读常量 声明必须赋初始值 常量值不可修改
共性特点
- 没有变量提升(即:脚本开始运行时提前声明为
unefined的变量)、拥有临时性死区(声明前调用会报错) - 不允许重复声明同名变量
- 拥有块级作用域(即:超出当前变量声明作用域无法调用该变量)
解构赋值
数组:位置顺序解构
对象:数据结构相同且同名变量解构
字符串 :位置顺序解构,可解构length(let {length:len} = 'test')
函数:根据传入参数类型不同 按照以上规则解构
共性特点
- 可指定默认值(即:
let [f = 'ff'] = []) - 可完全解构(即:等号两边数据结构完全相等)
- 可不完全解构(即:等号两边数据结构相等,但等号左边只解构部分变量)
模板字符串
`` 使用模板字符串
${}在模板字符串中使用变量
- 可多行使用(即``可换行)
- 可使用反斜杠转义
\(即 \ ` 使用) - 可通过
${}调用函数(即${fn()}) - 可嵌套模板字符串
字符串拓展方法
includes() :返回布尔值,表示是否找到了参数字符串。
let s = 'Hello world!';
s.includes('o') // true
startsWith() :返回布尔值,表示参数字符串是否在原字符串的头部。
s.startsWith('Hello') // true
endsWith() :返回布尔值,表示参数字符串是否在原字符串的尾部。
s.endsWith('!') // true
repeat() : 返回一个新字符串,表示将原字符串重复n次。
'hello'.repeat(2) // "hellohello"
padStart() : 字符串不够指定长度,将头部补全
'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
padEnd() : 字符串不够指定长度,将尾部补全。
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'
trimStart() : 消除字符串头部的空格(返回的都是新字符串,不会修改原始字符串)
const s = ' abc ';
s.trimStart() // "abc "
trimEnd() : 消除尾部的空格 (返回的都是新字符串,不会修改原始字符串)
s.trimEnd() // " abc"
matchAll() : 返回一个正则表达式在当前字符串的所有匹配
replaceAll() : 可以一次性替换所有匹配。
'aabbcc'.replaceAll('b', '_') // 'aa__cc'
at() :接受一个整数作为参数,返回参数指定位置的字符,支持负索引
const str = 'hello';
str.at(1) // "e"
数值拓展
二进制
- 前缀用
0b或0b表示(即:0b111110111 === 503 // true)
八进制
- 前缀用
0o标识(即:0o767 === 503 // true)
数值分隔符
- 为了增加数值可读性 使用下划线(
_)作为分隔符 (即let budget = 1_000_000_000_000;)
- 不能放在数值的最前面(leading)或最后面(trailing)。
- 不能两个或两个以上的分隔符连在一起。
- 小数点的前后不能有分隔符。
- 科学计数法里面,表示指数的
e或E前后不能有分隔符。
BigInt 只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示
- 可以使用
BigInt()进行类型转换- BigInt 类型的数据必须添加后缀
n。- BigInt 不能与普通数值进行混合运算。
- 可以使用
Boolean()、Number()和String()这三个方法,将 BigInt 可以转为布尔值、数值和字符串类型,转为字符串时后缀n会消失。- BigInt 与字符串混合运算时,会先转为字符串,再进行运算。
实例方法
-
Number.isFinite():用来检查一个数值是否为有限的(finite),即不是Infinity -
Number.isNaN():用来检查一个值是否为NaN -
Number.isInteger()用来判断一个数值是否为整数 -
Number.parseInt:用来转换为正整数数值 -
Number.parseFloat:来转换为双浮点数值 -
Number.EPSILON:极小的常量,它表示 1 与大于 1 的最小浮点数之间的差 -
Number.MAX_SAFE_INTEGER: 表示javascript能精表示的整数最大值 -
Number.MIN_SAFE_INTEGER: 表示javascript能精表示的整数最小值 -
Number.isSafeInteger():用来判断一个整数是否落在javascript能表示最大值和最小值之内 -
Math.trunc():用于去除一个数的小数部分,返回整数部分 -
Math.sign():用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值 -
Math.cbrt():用于计算一个数的立方根 -
Math.clz32():将参数转为 32 位无符号整数的形式,然后返回这个 32 位值里面有多少个前导 0 -
Math.imul:返回两个数以 32 位带符号整数形式相乘的结果,返回的也是一个 32 位的带符号整数 -
Math.fround:返回一个数的32位单精度浮点数形式 -
Math.hypot:返回所有参数的平方和的平方根 -
Math.expm1(x):返回 ex - 1,即Math.exp(x) - 1 -
Math.log1p(x):返回1 + x的自然对数,即Math.log(1 + x)。如果x小于-1,返回NaN -
Math.log10(x):返回以 10 为底的x的对数。如果x小于 0,则返回 NaN -
Math.log2(x):返回以 2 为底的x的对数。如果x小于 0,则返回 NaN -
Math.sinh(x)返回x的双曲正弦 -
Math.cosh(x)返回x的双曲余弦 -
Math.tanh(x)返回x的双曲正切 -
Math.asinh(x)返回x的反双曲正弦 -
Math.acosh(x)返回x的反双曲余弦 -
Math.atanh(x)返回x的反双曲正切
函数拓展
函数默认值
- (即:函数的参数指定默认值)
- 可以和解构一起使用(即:
function foo({x, y = 5}){}) - 通常参数默认值的位置在尾部,方便使用默认值忽略(即:
function f(x = 1, y),只穿一个参数则x无法正常使用默认值忽略) - 使用默认值会导致函数了
length属性失真(即:因为length属性的含义是,该函数预期传入的参数个数。某个参数指定默认值以后,预期传入的参数个数就不包括这个参数了) - 设置默认值会在函数初始化时产生单独作用域,初始化结束作用域消失 即:
var x = 1; function f(x, y = x) { console.log(y); } f(2) // 2 - 可以和解构一起使用(即:
rest参数
- (即:
...变量用于接受函数多余参数)
name属性
- (即:返回该函数的函数名
函数名.name)
箭头函数
=>(即:function foo = () => {})- 没有自己的
this对象,内部使用this会采用调用时上级作用域this - 不可以对箭头函数使用
new命令,否则会抛出错误 - 不可以使用
arguments对象,如果要用,可以用rest参数代替 - 不可以使用
yield命令,箭头函数不能用作Generator函数
- 没有自己的
Function.prototype.toString()(即:方法返回函数代码本身,以前会省略注释和空格)catch的参数省略(即:try {} catch {})
数组拓展
拓展运算符
...将一个数组转为用逗号分隔的参数序列
数组空位
- 数组的某一个位置没有任何值,
ES6则是明确将空位转为undefined
静态方法
Array.from()用于将两类对象转为真正的数组: (array-like object)和(iterable)和 (Set) 和(Map) 即:
let s = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
let arr2 = Array.from(s); // ['a', 'b', 'c']
Array.of()用于将一组值,转换为数组 (即:Array.of(3, 11, 8) // [3,11,8])
实例方法
-
copyWithin()在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原数组),返回当前数组。会修改当前数组 (即:[1, 2, 3, 4, 5].copyWithin(0, 3) // [4, 5, 3, 4, 5]) -
find()用于找出第一个符合条件的数组成员。然后返回该成员。如果没有符合条件的成员,则返回undefined。 -
findIndex()返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。 -
fill()使用给定值,填充一个数组 (即:['a', 'b', 'c'].fill(7) // [7, 7, 7]) -
includes()返回一个布尔值,表示某个数组是否包含给定的值 -
flat()将多维数组处理成一维数组,返回一个新数组 -
flatMap()使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与 map 连着深度值为 1 的 flat 几乎相同 (即:[1, 2, [3], [4, 5], 6].flatMap(num => num) // [1, 2, 3, 4, 5, 6]) -
ES2022新增
at(),接受一个整数作为参数,返回对应位置的成员,并支持负索引。这个方法不仅可用于数组,也可用于字符串和类型数组 (即:[5, 12, 8, 130, 44].at(-2) // 130)
对象拓展
属性简洁表示法
- 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法
- (即:
const foo = {name:name,method(){}})
- (即:
- 属性名表达式 字面量定义对象(即:
obj['a'+'bc'] = 123;) - 方法
name属性 将对象方法函数,返回函数名 如果使用取值函数和存值函数则如下:
const obj = {
get foo() {},
set foo(x) {}
};
const descriptor = Object.getOwnPropertyDescriptor(obj, 'foo');
descriptor.get.name // "get foo"
descriptor.set.name // "set foo"
有两种特殊情况:
bind方法创造的函数,name属性返回bound加上原函数的名字;Function构造函数创造的函数,name属性返回anonymous。
super
- 指向当前对象的原型对象。(即:
super.xxx等同于Object.getPrototypeOf(this).xxx)
静态方法
-
Object.getOwnPropertyNames()返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。 -
Object.getOwnPropertySymbols()返回一个数组,包含对象自身的所有 Symbol 属性的键名。 -
Reflect.ownKeys()返回一个数组,包含对象自身的(不含继承的)所有键名
Object.getOwnPropertyNames()、Object.getOwnPropertySymbols()、Reflect.ownKeys()都遵守同样的属性遍历的次序规则
- 首先遍历所有数值键,按照数值升序排列。
- 其次遍历所有字符串键,按照加入时间升序排列。
- 最后遍历所有 Symbol 键,按照加入时间升序排列。
-
Object.is()方法判断两个值是否为同一个值。 -
Object.assign()忽略enumerable为false的属性,属性从一个或多个源对象复制到目标对象,返回修改后的对象。
因为
Object.assign()只复制属性值,假如源对象是一个对象的引用,它仅仅会复制其引用值。
-
Object.getOwnPropertyDescriptors()所指定对象的所有自身属性的描述符,如果没有任何自身属性,则返回空对象。主要是为了解决Object.assign()无法正确拷贝get属性和set属性的问题。 -
__proto__属性 用来读取或设置当前对象的原型对象 -
Object.setPrototypeOf()用来设置一个对象的原型对象(prototype),返回参数对象本身 -
Object.getPrototypeOf()用于读取一个对象的原型对象 -
Object.entries()返回数据的迭代对象,包含该对象的键值对数组 -
Object.keys()返回数据的迭代对象,包含该对象的键名数组 -
Object.values()返回数据的迭代对象,包含该对象的值名数组 -
Object.fromEntries()用于将一个键值对数组转为对象。 -
Object.hasOwn()判断是否为自身的属性
JavaScript 对象的属性分成两种:自身的属性和继承的属性。对象实例有一个
hasOwnProperty()方法,可以判断某个属性是否为原生属性。ES2022 在Object对象上面新增了一个静态方法Object.hasOwn(),也可以判断是否为自身的属性
运算符拓展
指数运算符
- (即:
**) 右结合,多个指数运算符连用时,是从最右边开始计算
链判断运算符
- ES2020 引入了“链判断运算符” 判断对象是否存在。
- 短路机制
?.运算符相当于一种短路机制,只要不满足条件,就不再往下执行 - 括号的影响 如果有圆括号包裹,只对圆括号颞部产生影响 (即
(a?.b).c) - 右侧不得为十进制数值 (即:
foo?.3:0会被解析成三元运算符进行处理)
- 短路机制
obj?.prop// 对象属性是否存在obj?.[expr]// 同上func?.(...args)// 函数或对象方法是否存在
Null 判断运算符
- ES2020
Null判断运算符??只有运算符左侧的值为null或undefined时,才会返回右侧的值 (即:user.name ?? 'zhangsan')
逻辑赋值运算符
- ES2021 引入 三个运算符
||=、&&=、??=相当于先进行逻辑运算,然后根据运算结果,再视情况进行赋值运算。
x ||= y==x || (x = y)x &&= y==x && (x = y)x ??= y==x ?? (x = y)
正则拓展
RegExp允许第二个参数添加修饰符(即:new RegExp(/abc/ig, 'i').flags)- 字符串正则方法 (即:这 4 个方法,在语言内部全部调用
RegExp的实例方法)
String.prototype.match调用RegExp.prototype[Symbol.match]String.prototype.replace调用RegExp.prototype[Symbol.replace]String.prototype.search调用RegExp.prototype[Symbol.search]String.prototype.split调用RegExp.prototype[Symbol.split]
u修饰符
- 含义为“Unicode 模式”,用来正确处理大于
\uFFFF的 Unicode 字符/^\uD83D/u.test('\uD83D\uDC2A') // false-
点字符 除了换行符以外的任意单个字符。对于码点大于
0xFFFF的Unicode字符,点字符不能识别,必须加上u修饰符。(即:/^.$/u.test('𠮷') // true) -
Unicode字符表示法 使用大括号表示Unicode字符,在正则表达式中必须加上u修饰符,才能识别当中的大括号,否则会被解读为量词(即:/\u{20BB7}/u.test('𠮷') // true) -
量词 使用
u修饰符后,所有量词都会正确识别码点大于0xFFFF的Unicode字符(即:/𠮷{2}/.test('𠮷𠮷') // false) -
预定义模式
u修饰符影响到预定义模式,能否正确识别码点大于0xFFFF的Unicode字符\S是预定义模式 (即:/^\S$/u.test('𠮷') // true) -
i 修饰符
Unicode字符的编码不同,但是字型很相近,加u修饰符 识别非规范的字符(即:/[a-z]/iu.test('\u212A') // true) -
转义会在u模式下报错(即:
/,/u // 报错)
-
y修饰符
- 全局匹配 确保匹配必须从剩余的第一个位置开始
实例属性
RegExp.prototype.unicode属性 表示是否设置了u修饰符。
const r2 = /hello/u;
r2.unicode // true
RegExp.prototype.sticky属性 表示是否设置了y修饰符 (即:var r = /hello\d/y; r.sticky // true)RegExp.prototype.flags属性 会返回正则表达式的修饰符 (即:/abc/ig.flags)
Symbol
- 表示独一无二的值
let s = Symbol(); - 不能使用
new命令 (即:因为生成的Symbol是一个原始类型的值) - 接受一个字符串作为参数
Symbol值不能与其他类型的值进行运算Symbol值不能转换成数值 (即:Number(xxx) //typeError))Symbol作为属性名,遍历对象的时候,该属性不会出现在for...in、for...of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。 (可以通过Object.getOwnPropertySymbols()方法获取所有Symbol属性名)
实例属性
Symbol.prototype.descriptionES2019 提供了一个实例属性description,直接返回Symbol的描述。(即:const sym = Symbol('foo'); sym.description // "foo")
实例方法
Symbol.for()传入字符串参数搜索是否有同名Symbol值,有返回Symbol值,没有就新建一个以该字符串为名称的Symbol值.Symbol.keyFor()方法返回一个已登记的Symbol类型值的key。
内部属性
Symbol.hasInstance指向一个内部方法。当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法Symbol.isConcatSpreadable等于一个布尔值,表示该对象用于Array.prototype.concat()时,是否可以展开。
arr2[Symbol.isConcatSpreadable] = false;
['a', 'b'].concat(arr2, 'e') // ['a', 'b', ['c','d'], 'e']
-
Symbol.species一个用于创建派生对象的构造器函数。创建衍生对象时,会使用该属性 -
Symbol.match一个对字符串进行匹配的方法,也确定一个对象是否可以作为正则表达式使用。被String.prototype.match()使用。 -
Symbol.replace一个替换匹配字符串的子串的方法。被String.prototype.replace()使用。 -
Symbol.search一个返回一个字符串中与正则表达式相匹配的索引的方法。被String.prototype.search()使用 -
Symbol.split一个在匹配正则表达式的索引处拆分一个字符串的方法.。被String.prototype.split()使用。 -
Symbol.iterator一个返回一个对象默认迭代器的方法。被for...of使用。 -
Symbol.toPrimitive- 指向一个方法。该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。会接受一个字符串参数,表示当前运算的模式,一共有三种模式。Number:该场合需要转成数值String:该场合需要转成字符串Default:该场合可以转成数值,也可以转成字符串
-
Symbol.toStringTag指向一个方法。在该对象上面调用Object.prototype.toString方法时,如果这个属性存在,它的返回值会出现在toString方法返回的字符串之中,表示对象的类型。 -
Symbol.unscopables指向一个对象。该对象指定了使用with关键字时,哪些属性会被with环境排除。
Set 和 Map
Set
- 存储任何类型的唯一值,无论是原始值或者是对象引用。
NaN和undefined都可以被存储在Set中,NaN之间被视为相同的值Set内部判断两个值是否不同,会采用精确相等运算符(===),因此可以成员去重,但是对于相同属性的对象成员,除非它们指向同一个对象,否则不会去重。
声明示例:
const s = new Set([1,2,3]);
实例属性
Set.prototype.constructor:构造函数,默认就是Set函数。Set.prototype.size:返回Set实例的成员总数。
实例方法
-
Set.prototype.add(value):添加某个值,返回Set结构本身。 -
Set.prototype.delete(value):删除某个值,返回一个布尔值,表示删除是否成功。 -
Set.prototype.has(value):返回一个布尔值,表示该值是否为Set的成员。 -
Set.prototype.clear():清除所有成员,没有返回值。 -
Set.prototype.keys():返回键名的遍历器 -
Set.prototype.values():返回键值的遍历器 -
Set.prototype.entries():返回键值对的遍历器 -
Set.prototype.forEach():使用回调函数遍历每个成员
WeakSet
- 成员只能是对象
WeakSet中的对象都是弱引用- 垃圾回收机制不考虑
WeakSet对该对象的引用 (即:其他对象都不再引用该对象,垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于WeakSet之中) WeakSet不可遍历WeakSet没有size属性- 其余规则和
Set相同
声明示例:
const ws = new WeakSet([[1, 2], [3, 4]]);WeakSet 的一个用处,是储存 DOM 节点 而不用担心这些节点从文档移除时,会引发内存泄漏
实例方法
WeakSet.prototype.add(value):向WeakSet实例添加一个新成员WeakSet.prototype.delete(value):清除WeakSet实例的指定成员WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在WeakSet实例之中
Map
- 对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者基本类型)都可以作为一个键或一个值。
- Map 键名相等判断规则
NaN是与NaN相等的(虽然NaN !== NaN),剩下所有其它的值是根据===运算符的结果判断是否相等。Map的键是跟内存地址绑定的,只要内存地址不一样,就视为两个键
声明示例:
new Map([['baz', 3]])
实例属性
size 属性返回 Map 结构的成员总数。
实例方法
-
Map.prototype.set(key, value)设置键名key对应的键值为value,然后返回整个Map结构。如果key已经有值,则键值会被更新,否则就新生成该键。可以使用链式写法 -
Map.prototype.get(key)读取key对应的键值,如果找不到key,返回undefined -
Map.prototype.has(key)返回一个布尔值,表示某个键是否在当前 Map 对象之中 -
Map.prototype.delete(key)删除某个键值,返回true。如果删除失败,返回false -
Map.prototype.clear()清除所有成员,没有返回值。 -
Map.prototype.keys():返回键名的遍历器。 -
Map.prototype.values():返回键值的遍历器。 -
Map.prototype.entries():返回所有成员的遍历器。 -
Map.prototype.forEach():遍历 Map 的所有成员。
WeakMap
WeakMap只接受对象作为键名(null除外)WeakMap的键名所指向的对象,不计入垃圾回收机制WeakMap不可遍历WeakMap没有size属性- 不支持
clear方法 - 其余规则和
Map相同
声明示例:
new WeakMap([[k1, 'foo'], [k2, 'bar']])
实例方法
WeakMap.prototype.delete(key)删除WeakMap中与key相关联的值。删除之后,返回false。WeakMap.prototype.get(key)返回WeakMap中与key相关联的值,如果key不存在则返回undefined。WeakMap.prototype.has(key)返回一个布尔值,断言一个值是否已经与WeakMap对象中的key关联。WeakMap.prototype.set(key, value)给WeakMap中的key设置一个value。该方法返回一个WeakMap对象。
Proxy
Proxy对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。Proxy目标对象的透明代理 即不做任何拦截的情况下,也无法保证与目标对象的行为一致 ,因为Proxy代理目标对象内部的this关键字会指向Proxy代理
支持的拦截方法
-
get(target, propKey, receiver)拦截对象属性的读取 (即:proxy.foo和proxy['foo']) -
set(target, propKey, value, receiver)拦截对象属性的设置,返回一个布尔值(即:proxy.foo = v或proxy['foo'] = v) -
has(target, propKey)拦截in操作符的捕捉器。(即:propKey in proxy) -
deleteProperty(target, propKey)拦截delete操作符的捕捉器。(即:delete proxy[propKey]) -
ownKeys(target)拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性 -
getOwnPropertyDescriptor(target, propKey)拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。 -
defineProperty(target, propKey, propDesc)拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。 -
preventExtensions(target)拦截Object.preventExtensions(proxy),返回一个布尔值。 -
getPrototypeOf(target)拦截Object.getPrototypeOf(proxy),返回一个对象。 -
isExtensible(target)拦截Object.isExtensible(proxy),返回一个布尔值。 -
setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。 -
apply(target, object, args)拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。 -
construct(target, args)拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)。
Proxy.revicable()
- 返回一个可取消的 Proxy 实例。
revoke属性是一个函数,可以取消Proxy实例。当执行revoke函数之后,再访问Proxy实例,会抛出错误。(即:let {proxy, revoke} = Proxy.revocable(target, handler))
Reflect
-
Reflect是一个内置的对象,它提供拦截 JavaScript 操作的方法 -
将某些
Object方法 移植到Reflect并修改的更合理 (即:修改属性添加返回值等) -
Reflect并非一个构造函数,所以不能通过new 运算符对其进行调用 -
Reflect的所有属性和方法都是静态的 -
Reflect对象的方法与Proxy对象的方法一一对应,通常可以调用Reflect方法,完成默认行为 (即:不管Proxy怎么修改默认行为,你总可以在Reflect上获取默认行为。)
静态方法
-
Reflect.apply(func, thisArg, args)对一个函数进行调用操作,同时可以传入一个数组作为调用参数。和Function.prototype.apply()功能类似。 -
Reflect.get(target, name, receiver)查找并返回target对象的name属性,如果没有该属性,则返回undefined。 -
Reflect.set(target, name, value, receiver)设置target对象的name属性等于value。 -
Reflect.has(obj, name)判断一个对象是否存在某个属性,和in运算符的功能完全相同。 -
Reflect.deleteProperty(obj, name)等同于delete obj[name],用于删除对象的属性 -
Reflect.construct(target, args)对构造函数进行new操作,相当于执行new target(...args) -
Reflect.getPrototypeOf(obj)用于读取对象的__proto__属性,对应Object.getPrototypeOf(obj) -
Reflect.setPrototypeOf(obj, newProto)用于设置目标对象的原型(prototype),对应Object.setPrototypeOf(obj, newProto)方法。它返回一个布尔值,表示是否设置成功。 -
Reflect.defineProperty(target, propertyKey, attributes)基本等同于Object.defineProperty,用来为对象定义属性,如果设置成功就会返回true -
Reflect.getOwnPropertyDescriptor(target, propertyKey)等同于Object.getOwnPropertyDescriptor,用于得到指定属性的描述对象,如果对象中存在该属性,则返回对应的属性描述符,否则返回undefined -
Reflect.isExtensible (target)对应Object.isExtensible,返回一个布尔值,表示当前对象是否可扩展 -
Reflect.preventExtensions(target)对应Object.preventExtensions方法,用于让一个对象变为不可扩展。它返回一个布尔值,表示是否操作成功 -
Reflect.ownKeys (target)返回一个包含所有自身属性(不包含继承属性)的数组。(类似于Object.keys(), 但不会受enumerable影响)
Promise
- 是异步编程的一种解决方案,用于解决回调地狱问题
- 对象的状态不受外界影响
pending初始状态,待处理fulfilled意味着操作成功完成,已完成rejected意味着操作失败,已拒绝
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果
- 无法取消
Promise,一旦新建它就会立即执行 - 将异步操作最终的成功返回值或者失败原因和相应的处理程序关联起来做到可以像同步方法一样返回值
- 不会立即返回最终的值,而是会返回一个
Promise实例
实例方法
-
Promise.prototype.then()是为Promise实例添加状态改变时的回调函数,返回的是一个新的Promise实例 -
Promise.prototype.catch()用于指定发生错误时的回调函数,若回调函数被调用,则兑现其返回值,否则兑现原来的Promise兑现的值。 -
Promise.prototype.finally()指定不管 Promise 对象最后状态如何,都会执行的操作,ES2018引入标准
静态方法
Promise.all()将多个Promise实例,包装成一个新的Promise实例-
参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是
Promise实例 -
执行多个
Promise,虽然按顺序执行,但是由于异步回调时间不固定的情况下并不能保证执行顺序。 -
不会阻塞线程,只会在合适的时机调用整体
fulfilled或rejected的回调函数 -
遇到执行回调中第一个失败。会立刻执行自身的
rejected的回调函数,并且只会抛出第一个失败rejected,后续遇到rejected均不执行 -
不会因为内部异步函数的失败,而中断后续所有的异步函数执行
-
可以更快的捕获异常问题。 详情参见: 关于 Promise.all 和 async await 这档子事儿
-
let p1 = new Promise(()=>{});
let p2 = new Promise(()=>{});
const p = Promise.all([p1, p2]);
Promise.race()同时接受多个 Promise 实例,包装成一个新的Promise实例。一旦迭代器中的某个Promise解决或拒绝,返回的Promise就会解决或拒绝。-
传的参数迭代是空的,则返回的
Promise将永远等待 -
如果迭代包含一个或多个非承诺值和/或已解决/拒绝的承诺,则
Promise.race将解析为迭代中找到的第一个值。
-
var p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, "one");
});
var p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, "two");
});
Promise.race([p1, p2]).then(function(value) {
console.log(value); // "two"
// 两个都完成,但 p2 更快
});
Promise.allSettled()接受多个Promise实例, ES2020 引入了Promise.allSettled()方法,用来确定一组异步操作是否都结束了(不管成功或失败)-
返回一个在所有给定的
Promise都已经fulfilled或rejected后的Promise,并带有一个对象数组,每个对象表示对应的Promise结果 -
接受一个数组作为参数,数组的每个成员都是一个
Promise对象
-
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];
Promise.allSettled(promises).
then((results) => results.forEach((result) => console.log(result.status)));
Promise.any()ES2021 引入了Promise.any()接受一组Promise实例作为参数,包装成一个新的Promise实例返回。如果有一个成功就返回第一个,后续不返回,如果失败需要等到所有失败才会返回失败Promise-
接收一个
Promise可迭代对象,只要其中的一个Promise成功,就返回那个已经成功的Promise。如果可迭代对象中没有一个Promise成功(即所有的Promises都失败/拒绝),就返回一个失败的Promise -
抛出的错误是一个
AggregateError实例 , 这个AggregateError实例对象的errors属性是一个数组,包含了所有成员的错误
-
Promise.resolve()接受一个对象参数,返回一个以给定值解析后的Promise对象-
如果参数是 Promise 实例,将不做任何修改、原封不动地返回这个实例
-
参数是一个
thenable对象(即:对象指的是具有then方法的对象),将这个对象转为Promise对象,然后就立即执行then()方法
不要在解析为自身的 thenable 上调用
Promise.resolve。这将导致无限递归,因为它试图展平无限嵌套的 promiselet thenable = { then: (resolve, reject) => { resolve(thenable) } } Promise.resolve(thenable) //这会造成一个死循环-
如果参数是一个原始值,返回一个新的 Promise 对象,状态为
resolved -
不带参数,直接返回一个
resolved状态的 Promise 对象。
-
Promise.reject()返回一个带有拒绝原因的Promise对象
Iterator 和 for...of
Iterator 迭代器
- 它是一种接口,为各种不同的数据结构提供统一的访问机制
- 使得数据结构的成员能够按某种次序排列
Iterator接口主要供for...of操作- 迭代器对象可以通过重复调用显式迭代
next()。迭代一个迭代器被称为消耗迭代器,因为它通常只能做一次。在产生终止值后,next()应继续返回额外的调用{done: true}。
Iterator遍历过程
- 创建一个指针对象,指向当前数据结构的起始位置。也就是说,迭代器对象本质上,就是一个指针对象。
- 第一次调用指针对象的
next方法,可以将指针指向数据结构的第一个成员。 - 第二次调用指针对象的
next方法,指针就指向数据结构的第二个成员。 - 不断调用指针对象的
next方法,直到它指向数据结构的结束位置。
let arr = ['a', 'b', 'c'];
let iter = arr[Symbol.iterator]();
iter.next() // { value: 'a', done: false }
iter.next() // { value: 'b', done: false }
iter.next() // { value: 'c', done: false }
iter.next() // { value: undefined, done: true }
具备 Iterator 接口的数据结构
- Array
- Map
- Set
- String
- TypedArray
- 函数的 arguments 对象
NodeList对象
会默认调用 Iterator 接口的场合
- 对数组和
Set结构进行解构赋值时,会默认调用Symbol.iterator方法。 - 扩展运算符
yield*后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口for...ofArray.from()Map(),Set(),WeakMap(),WeakSet()Promise.all()Promise.race()
for...of
- 一个数据结构只要部署了
Symbol.iterator属性,就被视为具有iterator接口,就可以用for...of循环遍历它的成员 - 它可以由
break,throw或return终止,迭代器关闭 - 提供了遍历所有数据结构的统一操作接口。
Generator
-
异步编程解决方案,执行
Generator函数会返回一个迭代器对象 -
Generator可以暂停函数执行,返回任意表达式的值 -
对象的属性是
Generator函数,可简写为* myGeneratorMethod() {···} -
function关键字与函数名之间有一个星号 (即:function* helloWorldGenerator(){}) 星号不验证位置。 -
函数体内部使用
yield表达式,定义不同的内部状态 -
可以调用迭代器对象的
next方法,使得指针移向下一个状态 -
yield表达式是暂停执行的标记,而next方法可以恢复执行 -
for...of可以自动遍历Generator函数运行时生成的Iterator对象,并且不需要调用next方法 -
可以把
Generator赋值给对象的Symbol.iterator属性,从而使得该对象具有Iterator接口,并支持扩展运算符遍历
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
[...myIterable] // [1, 2, 3]
通常
Generator函数用于解决异步任务,或者存放异步任务,可以通过yield,交出函数的执行权。
yield
-
yield表达式本身没有返回值,默认返回undefined -
迭代器对象的
next方法的运行逻辑如下。-
遇到
yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。 -
下一次调用
next方法时,再继续往下执行,直到遇到下一个yield表达式。 -
如果没有再遇到新的
yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。 -
如果该函数没有
return语句,则返回的对象的value属性值为undefined
-
yield* 表达式
-
一个
Generator函数里面执行另一个Generator函数,可返回一个可迭代对象的表达式 (即yield* foo();) -
在有
return语句时,需要用var value = yield* iterator的形式获取return语句的值 -
任何数据结构只要有
Iterator接口,就可以被yield*遍历,换种说话,yield*可以很方便地取出嵌Iterator数据下的所有成员
方便查看运行逻辑的 demo
next
next传参会被当作上一个yield表达式的返回值。
实例方法
-
Generator.prototype.throw()可以在函数体外抛出错误,然后在Generator函数体内捕获,返回带有done及value两个属性的对象 即:g.throw(new Error("Something went wrong"))-
如果
Generator函数内部没有部署try...catch代码块,那么throw方法抛出的错误,将被外部try...catch代码块捕获 -
只要函数内部部署了
try...catch代码块,那么迭代器的throw方法抛出的错误,不影响下一次遍历
-
-
Generator.prototype.return()返回给定的值并结束迭代器 (即:g.return('foo'))- 如果函数内部有
try...finally代码块,且正在执行try代码块,那么return()方法会导致立刻进入finally代码块,执行完后,整个函数才会结束
- 如果函数内部有
async 函数
ES2017 引入了 async 函数,异步操作变得更加方便
-
async函数 相当于Promise和Generator组合成的语法糖 -
await表达式会暂停整个 async 函数的执行进程并出让其控制权,只有当其等待的基于 promise 的异步操作被兑现或被拒绝之后才会恢复进程 -
await返回值如果不是Promise则会被隐式包装成一个Promise中 -
await关键字只在async函数内有效 -
async函数会返回一个Promise对象,return命令返回的值,会被then方法回调函数接收到,async函数内部抛出错误,会导致返回的Promise对象变为reject状态 -
同步执行异步任务,按顺序执行,并阻塞线程保证执行顺序。
-
会阻塞线程
-
遇到执行回调中第一个失败,报错如果不加
try...catch会直接中断后续代码执行 -
依次执行保证指定顺序调用异步函数
-
简洁的使用语法糖 详情参见 关于 Promise.all 和 async await 这档子事儿
例子
function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value);
}
asyncPrint('hello world', 50);
Class
class写法可以让对象原型的写法更加清晰、更像面向对象编程的语法- 类必须使用
new调用,否则会报错 - 类的属性和方法,除非显式定义在其本身(即定义在
this对象上),否则都是定义在原型上 - 类的属性名,可以采用表达式 (即:
[methodName]() {}) Class表达式 可以定义一个只在类内部使用的类名指代当前类 (即:const MyClass = class Me {})- 类不存在变量提升
- 类和模块的内部,默认就是严格模式
constructor()
- 是类的默认方法,创建对象实例时,自动调用该方法。一个类必须有
constructor()方法,如果没有显式定义,一个空的constructor()方法会被默认添加 constructor()方法默认返回实例对象(即this),可以重新指定返回另外一个对象
getter 和 setter
- 在
class的内部可以使用get和set关键字,对某个属性的存值和取值,进行自定义行为。 - 使用
Object.getOwnPropertyDescriptor()可以获取到类,属性是否设置了get或set
静态方法
- 使用
static声明静态方法 ,该方法不会被实例继承,而是直接通过类来调用 - 静态方法包含
this关键字,指代的是类,而非实例 - 静态方法可以被继承,子类可以通过
super调用父类静态方法
静态属性
class Foo {} Foo.prop = 1;可通过此方式定义静态属性 或者使用提案提供了类的静态属性,写法是在实例属性的前面,加上static关键字- 其余规则与
静态方法一致
new.target
- 该属性一般用在构造函数之中,返回
new命令作用于的那个构造函数。如果构造函数不是通过new命令或Reflect.construct()调用的,new.target会返回undefined - 在函数外部,使用
new.target会报错
继承
Class可以通过extends关键字实现继承,让子类继承父类的属性和方法- 子类必须在
constructor()方法中调用super(),否则就会报错 (即:先将父类的属性和方法,加到一个空的对象上面,然后再将该对象作为子类的实例) Object.getPrototypeOf()方法可以用来从子类上获取父类
super
- 可以通过 super 调用父类的静态方法
- 不能使用 delete 操作符 加
super.prop或者super[expr]去删除父类的属性,这样做会抛出ReferenceError - 当使用
Object.defineProperty定义一个属性为不可写时,super将不能重写这个属性的值 - 使用
super的时候,必须显式指定是作为函数、还是作为对象使用,否则会报错 (即:console.log(super))
Module
- ES6 模块是编译时加载
- ES6 的模块自动采用严格模式
严格模式限制如下:
- 变量必须声明后再使用
- 函数的参数不能有同名属性,否则报错
- 不能使用
with语句- 不能对只读属性赋值,否则报错
- 不能使用前缀 0 表示八进制数,否则报错
- 不能删除不可删除的属性,否则报错
- 不能删除变量
delete prop,会报错,只能删除属性delete global[prop]eval不会在它的外层作用域引入变量eval和arguments不能被重新赋值arguments不会自动反映函数参数的变化- 不能使用
arguments.callee- 不能使用
arguments.caller- 禁止
this指向全局对象- 不能使用
fn.caller和fn.arguments获取函数调用的堆栈- 增加了保留字(比如
protected、static和interface)
export用于规定模块的对外接口,import用于输入其他模块提供的功能export和import处于块级作用域内,就会报错
export
- 于从模块中导出实时绑定的函数、对象或原始值,以便其他程序可以通过
import语句使用它们 - 导出单个变量
export let name1, name2, …, nameN;
- 导出对象
export { name1, name2, …, nameN };
- 重命名导出
export { variable1 as name1, variable2 as name2, …, nameN };
- 默认导出
export default expression;
- 导出模块合集
export * from …;
import
- 用于导入由另一个模块导出的绑定
import命令会被 `JavaScript· 引擎静态分析,先于模块内的其他语句执行- 导入整个模块
import * as myModule from '/modules/my-module.js';
- 导入多个变量
import {foo, bar} from '/modules/my-module.js';
- 导入带别名的变量
import {reallyReallyLongModuleExportName as shortName}
from '/modules/my-module.js';
- 导入默认值
import myDefault from '/modules/my-module.js';
import()
- ES2020提案 引入
import()函数,支持动态加载模块。 import()函数可以用在任何地方,非模块的脚本也可以使用。它是运行时执行import()返回 Promise 对象import()允许模块路径动态生成
import('/modules/my-module.js')
.then((module) => {});
写在最后
阿江,最近新建了一个前端摸鱼交流群,欢迎同好的小伙伴一起热闹热闹 快戳这里
转载自:https://juejin.cn/post/7119401211471609886