- ES6
- 1. 新的声明方式:let
- 2. 新的声明方式:const
- 3. ==解构赋值(常用)==
- 4. 数组的各种遍历方式
- ES6 中数组遍历方法
- 5. 数组的扩展
- 6. 函数的参数
- 7. 拓展运算符 与 rest 参数
- 8. 箭头函数
- 9. 对象的扩展
- 10. 深拷贝与浅拷贝
- 11. 面向过程与面向对象
- 12. ES5 中的类与继承
- 13. ES6 中的类与继承
- 14. 新的原始数据类型 Symbol
- 15. 新的数据结构 Set
- 16. 新的数据类型 Map
- 17. 字符串的扩展
- 18. 正则表达式的拓展
- 19. 数值的拓展
- 20. 代理 proxy
- 21. 反射 Reflect
- 22. 异步操作
- 23. Promise
- 24. Generator
- ES7
- ES8
- ES9
- ES10
- ES11
- 1. 全局模式捕获 matchAll()
- 2. 动态导入 Dynamic import()
- 3. 新的原始数据类型 BigInt
- 4. Promise 扩展 allSettled()
- 5. 全局对象 globalThis
- 6. 可选链 Optional chaining
- 7. 空值合并运算符 Nullish coalescing Operator
- ES12
- String.prototype.replaceAll()
- Promise.any
- WeakRefs
- Logical Assignment Operators
- Numeric Separators —— 数字分隔符
- 结语
let p = new Promise((resolve, reject) => { resolve(2) reject(1) }).then(res => { console.log(res) }).catcj(err => { console.log(err) }) //只能输出 2,Promise 状态不能被改变
23.3 使用 Promise 发送 ajax 请求
单纯使用 ajax 需要嵌套非常多层。
使用 Promise 有大量重复代码,抽离出来写成一个函数,使得代码可读性更强,也有利于后期维护。
function getPromise(url) { return new Promise((resolve, reject) => { ajax(url, res => { resolve(res) }) }) } getPromise(...) .then(res => { console.log(res) return getPromise(...) }).then(res => { console.log(res) return getPromise(...) }).then(res => { console.log(res) })
统一捕获 err:
function getPromise(url) { return new Promise((resolve, reject) => { ajax(url, res => { resolve(res) }) }) } getPromise(...) .then(res => { console.log(res) return getPromise(...) }).then(res => { console.log(res) return getPromise(...) }).then(res => { console.log(res) }).catch(err => { console.log(err) }) //上述任何一个出现错误都会调用
23.4 Promise 的静态方法
Promise.resolve('success') Promise.reject('fail')
function foo(flag) { if(flag) { return new Promise(resolve => { //异步操作 resolve('success') }) } else { return Promise.reject('fail') //如果写成 return 'fail',当条件为 false 的时候,会报错 } } foo(false).then(res => { console.log(res) //fail },err => { console.log(err) })
Promise.all([...])
所有对象都完成之后才会进入 res,只要有一个是失败的,都会进入 err 中
可应用于上传多张图片中
Promise.all([p1,p2,p3]).then(res => { console.log(res)}, err => { console.log(err) })
const imgArr = ['1.jpg', '2.jpg', '3.jpg'] let promiseArr = [] imgArr.forEach(item => { promiseArr.push(new Promise((resolve, reject) => { // 图片上传的操作 resolve() })) }) Promise.all(promiseArr).then(res => { // 插入数据库的操作 console.log('图片全部上传完成') })
Promise.race([...])
只要有一个成功,整个就会进入 res 中
可应用于请求图片超时
Promise.race([p1,p2,p3]).then(res => { console.log(res)}, err => { console.log(err) })
function getImg() { return new Promise((resolve, reject) => { let img = new Image() img.onload = function () { resolve(img) //返回图片 } // img.src = 'http://www.xxx.com/xx.jpg' img.src = 'https://www.imooc.com/static/img/index/logo.png' }) } function timeout() { return new Promise((resolve, reject) => { setTimeout(() => { reject('图片请求超时') }, 2000) }) } Promise.race([getImg(), timeout()]).then(res => { console.log(res) }).catch(err => { console.log(err) }
24. Generator
function* foo() { for (let i = 0; i < 3; i++) { yield i } } let f = foo() console.log(f.next()) console.log(f.next()) console.log(f.next()) console.log(f.next()) //yield 关键字只存在于 Generator,这里的的 yield 关键字是在 forEach 函数里的 // function* gen(args) { // args.forEach(item => { // yield item + 1 // }) // }
function* gen(x) { let y = 2 * (yield(x + 1)) let z = yield(y / 3) return x + y + z } //在 next 里可以传递参数 let g = gen(5) console.log(g.next()) // 6 console.log(g.next(12)) // y=24 8(对应的 x+1=12) console.log(g.next(13)) // z=13 x=5 42(对应的 y/3=13
使用 Generator 进行 ajax 请求:
function request(url) { ajax(url, res => { getData.next(res) }) } function* gen() { let res1 = yield request('static/a.json') console.log(res1) let res2 = yield request('static/b.json') console.log(res2) let res3 = yield request('static/c.json') console.log(res3) } let getData = gen() getData.next()
25. Module
- export default 默认,导入不需要知道命名(可以直接使用别名)
- import * from ‘../../xx.js’
把庞大的代码拆开。
将多个功能的代码按功能进行分开,以达到多个模块组合在一起形成一个功能复杂的功能。
好处
- 防止命名冲突
- 代码复用
- 高维护性
语法
<script type="module"> </script>
也可以使用
<script src="./src/js/app.js" type="module"></script>
将引用部分放到另一个 js 文件里
export 对外接口
导入的时候命名要完全一样,可以起别名,起了别名之后文件中使用只能使用别名,原名已经失效了
export 和 export default 可以一起使用 import add, {str} from '../../xxx.js'
分别暴露:在要暴露的语句前面+export。
统一暴露:在某个位置使用 export{},将要暴露的数据放在花括号里面。
在模块文件里,使用 export default
export default { ... }
这样就可以直接使用了。
默认暴露:export.default = { }
,这种方法在调用时需要添加default
导入不需要知道命名(可以直接使用别名)
- import 输入其他模块提供的功能
- 通用的导入方式:import * as m1 from “./src/js/m1.js”;
导入的是全部
- 解构赋值的形式:
- import{school,teach} from “./src/js/m1.js”;
- import{default as m1} from “./src/js/m1.js”;
重名时需要使用别名,不然会报错
- 简便形式(针对默认暴露):improt m3 from “./src/js/m3.js”
- 通用的导入方式:import * as m1 from “./src/js/m1.js”;
- 使用 babel
- 安装工具
npm i babel-cli babel-preset-env browerify -D
- 编译:
npx babel src/js -d dist/js --presets=babel-preset-env
先 [原文件目录] 后 [存放文件目录] - 打包 :
npx browserify dist/js/app.js -o dist/bundle.js
将存放文件目录下的文件打包生成 bundle.js 文件
- 安装工具
ES7
1. 数组拓展
Array.prototype.includes(searchElement[,fromIndex])
- includes VS indexOf
includes
返回布尔值,可以检测 NaNindexOf
返回 index / -1,不可以检测 NaN
- 幂运算符:**等同于
Math.pow()
ES8
1. 异步编程解决方案 Async Await
两者成对出现,代码可读性更强。
function timeout() { return new Promise(resolve => { setTimeout(() => { console.log(1) resolve() },1000) }) } async function foo() { await timeout() //等待 timeout()运行完毕后再继续往下运行 console.log(2) } foo()
之前的 ajax 请求代码:
async function getData() { const res1 = await request('static/a.json') console.log(res1) const res2 = await request('static/b.json') console.log(res2) const res3 = await request('static/c.json') console.log(res3) }
2. 对象拓展
Object.values()
获得值Object.entries()
获得数组(key 和 value)
const res = Object,keys(obj).map(key => obj[key]) console.log(res) //上面可以写成 console.log(Object.values(obj))
console.log(Object.entries(['a','b','c'])) //["0","a"],["1","b"],["2","c"]
3. 对象属性描述
Object.getOwnPropertyDescriptors()
- value 当前对象的默认值
- writable 是否可以修改
- enumerable 是否可以通过 for..in 方式循环
- configurable 是否可以删除
4. 字符串拓展
- String.prototype.padStart() 头部补全
- String.prototype.padEnd() 尾部补全第一个参数为长度,第二个参数为用于补全的字符串
'x'.padStart(5, 'ab') // 'ababx' 'x'.padStart(4, 'ab') // 'abax' 'x'.padEnd(5, 'ab') // 'xabab' 'x'.padEnd(4, 'ab') // 'xaba' //等于或大于最大长度,则字符串补全不生效,返回原字符串 'xxx'.padStart(2, 'ab') // 'xxx' 'xxx'.padEnd(2, 'ab') // 'xxx'
//应用于日期 yyyy-mm-dd const now = new Date() const year = now.getFullYear() //padStart 是 String 原型下面的方法,所以想要将其转换为 String //getMonth()返回的是 0-11 的数字,所以要加 1 const month = (now.getMonth() + 1).toString().padStart(2,'0') const day = (now.getDate()) + 1.toString().padStart(2,'0') console.log(`${year}-${month}-${day}`)
//加密手机号 const tel = '13011111111' const NewTel = tel.slice(-4).padStart(tel.length,'*') console.log(NewTel)
5. 尾逗号
允许数参数列表使用尾逗号。
ES9
1. 异步迭代 for await of
for-await-of
Symbol.asyncIterator
//同步迭代 const arr = ['es6','es7','es8','es9'] arr[Symbol.iterator] = function() { let nextIndex = 0 return { next() { return nextIndex < arr.length ? { value: arr[nextIndex++], done: false } : { value: undefined, done: true } } } } for(let item of arr) { console.log(item) }
//异步迭代 function getPromise(time) { return new Promise((resolve,reject) => { setTimeout(() => { resolve({ //写成对象的形式 value: time, done:false }) },time) }) } const arr = [getPromise(1000),getPromise(2000),getPromise(3000)] arr[Symbol.asyncIterator] = function() { let nextIndex = 0 return { next() { return nextIndex < arr.length ? arr[nextIndex++] : Promise.resolve({ value: undefined, done: true }) } } } async function test() { for await (let item of arr) { console.log(item) } } test()
2. 正则表达式拓展
- dotAlldot 不能匹配n r(包括两者的 Unicode)
const reg = /./s //匹配任意单个字符 console.log(reg.test('5')) //true console.log(reg.test('x')) //true console.log(reg.test('n')) //true console.log(reg.test('r')) //true console.log(reg.test('u{2028}')) //true console.log(reg.test('u{2029}')) //true
- 具名组匹配
const RE_DATE = /(d{4})-(d{2})-(d{2})/; //用圆括号分组 const matchObj = RE_DATE.exec('1999-12-31'); const year = matchObj[1]; // 1999 const month = matchObj[2]; // 12 const day = matchObj[3]; // 31
const reg = /(?d{4}-(?<month)d{2}-(?d{2})) const groups = reg.exec('2020-02-01').groups //使用解构赋值 const {year, month,day} = groups console.log(year, month, day)
- 后行断言 match
- 先行断言:
x
只有在y
前面才匹配,必须写成/x(?=y)/
- 先行否定断言:
x
只有不在y
前面才匹配,必须写成/x(?!y)/
- 后行断言:
x
只有在y
后面才匹配,必须写成/(?<=y)x/
- 后行否定断言:
x
只有不在y
后面才匹配,必须写成/(?<!y)x/
- 先行断言:
3. 对象拓展 Rest&Spread
//克隆对象 为深拷贝 const obj3 = {..obj1} //合并对象 为浅拷贝 const obj4 = {...obj1, ...obj2} //obj1 和 obj2 相同键名的会被后者覆盖 //...rest 获取剩余的属性 const {name, age, ...rest} = obj1 //...rest 必须放在最后,不然会报错
4. Promise 拓展 finally()
Promise.prototype.finally()
无论失败还是成功都会执行 finally 里面的语句【例如:成功失败相同的代码逻辑、关闭操作】
5. 字符串扩展
放松模板字符串文字限制,对一些错误不报错,返回 undefined。
ES10
1. 对象扩展
Object.fromEntries()
返回对象结构 【和Object.Entries()
相反(返回键对结构)】
// map => 对象 const map = new Map() map.set('name', 'n1') map.set('name', 'n2') console.log(map) const fromEntries = Object.fromEntries(map) console.log(map) //对象格式
2. 字符串扩展
- String.prototype.trimStart()【trimLeft()】 消除头部的空格,尾部会被保留
- String.prototype.trimEnd() 【trimRight()】消除尾部的空格,头部会被保留
- String.prototype.trim() 消除空格
3. 数组扩展
Array.prototype.flat(num)
对多维数组进行扁平化操作const arr = [1,2,3,[4,5,6,[7,8,9,10,11],12]] //三维数组 console.log(arr.flat().flat().flat()) console.log(arr.flat(3)) console.log(arr.flat(Infinity))
Array.prototype.flatMap()
const arr = [1,2,3,4,5] //const res = arr.map(x => [x + 1]).flat() 等价于↓ const res = arr.flatMap(x => [x + 1])
4. 修订 toString()
返回源代码中的实际文本片段【原样输出返回一模一样的原始代码,包括注释空格等等】。
5. 可选的 Catch Binding
省略 catch 绑定的参数和括号。
try { // ... } catch { // ... }
6. JSON 扩展
- JSON superset
- JSON.stringify() 增强能力
// JSON 超集 【少用】u2029 u2028 eval('var str = "youlan";u2029 function foo(){return str;}') console.log(foo())
//0xD800~0xDfff console.log(JSON.stringify('uD830uDE0E')) //emoji console.log(JSON.stringify('uD830')) //ud830 原样输出
7. Symbol 扩展
Symbol.prototype.description
只读属性,不可写【修改 description 也不会报错,但是不能起作用】.
const s = Symbol('yl') console.log(s) //Symbol(yl) console.log(s.description) //yl 如果没有值则返回 undefined
ES11
1. 全局模式捕获 matchAll()
String.prototype.matchAll()
和正则一起使用
const str = ` <html> <body> <div>第一个 div</div> <p>这是 p</p> <div>第二个 div</div> <span>这是 span</span> <div>第三个 div</div> </body> </html> ` //exec g function selectDiv1(regExp, str) { let matches = [] while(true) { const match = regExp.exec(str) if(match == null) { break } matches.push(match[1]) //完整匹配 } return matches } const regExp = /<div>(.*)</div>/g const res1 = selectDiv1(regExp, str) console.log(res1) //["第一个 div","第二个 div","第三个 div"] //match //console.log(str.match(regExp)) //["<div>第一个 div</div>","<div>第二个 div</div>","<div>第三个 div</div>"] //replace function selectDiv2(regExp, str) { let matches = [] str.replace(regExp, (all, first) => { matches.push(first) //完整匹配 }) return matches } const res2 = selectDiv2(regExp, str) console.log(res2) //["第一个 div","第二个 div","第三个 div"] //matchAll function selectDiv3(regExp, st){ let matches = [] for(let match of str.matchAll(regExp)){ matches.push(match[1]) //完整匹配 } return matches } const res3 = selectDiv3(regExp, str) console.log(res3) //["第一个 div","第二个 div","第三个 div"]
matchAll
方法的正则表达式需要有 g(全局匹配)
2. 动态导入 Dynamic import()
按需引入,使得页面渲染更快
懒加载
eg. 点击按钮才导入某个模块、才开始渲染这一部分的东西
3. 新的原始数据类型 BigInt
console.log(1n == 1) //true console.log(1n === 1) //false //创建 const bigInt = BigInt(900719925474740993n) bigInt.toSring()
4. Promise 扩展 allSettled()
- Promise.allSettled()
- allSettled() Vs all()
Promise.allSettled([ Promise.resolve({ code: 200, data: [1, 2, 3] }), Promise.reject({ code: 500, data: [] }), Promise.resolve({ code: 200, data: [7, 8, 9] }), ]).then(res => { //console.log(res,"成功") const data = res.filter(item => item.status === "fulfilled") console.log(data) }).catch(err => { console.log(err,"失败") })
如果使用all()
,则其中有一个 reject 都会导致整个进程进入“失败”;而allSettled()
,成功的会返回status: "fulfilled" value:{...}
,失败的返回reson: {...}
,使用 filter 进行过滤获得请求成功的数据
5. 全局对象 globalThis
提供一个标准的方式去获取不同环境下的全局对象
// node: global // web: window self const getGlobal = () => { if(typeof selt !== 'undefined'){ return self } if(typeof window !== 'undefined'){ return window } if(typeof global !== 'undefined'){ return global } throw new Error("无法找到全局变量") } const global = getGlobal() console.log(global) //在 es11 中 //console.log(globalThis)
6. 可选链 Optional chaining
先判断这个方法属性是否存在,如果存在再往下取
const street = user && user.address && user.address.street console.log(street) const num = user && user.address && user.address.getNum && user.address.getNum() console.log(num) //es11 中,代码更加简洁 const street = user?.address?.street console.log(street) const num = user?.address?.getNum?.() console.log(num)
?.
中间不能有空格
7. 空值合并运算符 Nullish coalescing Operator
const b = null const a = b ?? 6 //当 b 为 undefined 或 null 时,取默认值 console.log(a)
??
中间不能有空格
ES12
String.prototype.replaceAll()
在此之前只能使用正则替换,现在可以直接使用一个快捷方式;replaceAll
。
//前 'jxvxscript'.replace(/x/g, 'a'); //后 // jxvxscript becomes javascript 'jxvxscript'.replaceAll('x', 'a');
Promise.any
Promise.any()
接收一个Promise
可迭代对象,只要其中的一个 promise 成功,就返回那个已经成功的 promise 。 如果可迭代对象中没有一个 promise 成功(即所有的 promises 都失败/拒绝),就返回一个失败的 promise。
const promise1 = new Promise((resolve, reject) => reject('我是失败的 Promise_1')); const promise2 = new Promise((resolve, reject) => reject('我是失败的 Promise_2')); const promiseList = [promise1, promise2]; Promise.any(promiseList).then(values=>{ console.log(values); }) .catch(e=>{ console.log(e); });
WeakRefs
使用 WeakRefs 的 Class 类创建对对象的弱引用(对对象的弱引用是指当该对象应该被 GC 回收时不会阻止 GC 的回收行为)
Logical Assignment Operators
包括这些运算符:&&=
, ||=
,??=
;
a = 1; b = 2; a&&=b // a=2 /* 以上代码相当于 a && a = b ??= 作用相当于 a ?? a = b */
Numeric Separators —— 数字分隔符
数字增加分隔符,可以使用 _ 分割数字,方便阅读较大的数字 对于跟数字打交道比较多的同学来说,可能会更加舒服
// previous syntax before ES12 const number = 92145723; // new syntax coming with ES12 const number = 92_145_723; console.log(number) // 92145723 //对国人来说可以这样,万,亿为单位 const number = 1_0000; console.log(number) // 10000
结语
呼哈,终于整理完了,新鲜出炉的最全 ES6-ES12 新特性总结,希望对大家有用,整理不易,希望对大家有帮助。