「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战」。
ES2016(ES7)
1. Array.prototype.includes()
判断数组里是否有特定的值,传回true/false
语法
arr.includes(searchElement[, fromIndex])
fromIndex:可选参数,默认是0
let arr = ['es7','es8','es9','es10','a']
console.log(arr.includes("es7")); //true
console.log(arr.includes("es12")); //false
console.log(arr.includes("es7",2)); //false
注意点
- 区分大小写
let arr = ['es7','es8','es9','es10','a']
console.log(arr.includes("A")) //false
只能判断简单类型的数据,对于复杂类型的数据,比如对象,二维数组,这些都无法判断
let arr = ['es6', ['es7', 'es8'], 'es9',{name:"syl"}]
console.log(arr.includes(["es7", "es8"])); // false
console.log(arr.includes({name:"syl"})); // false
- 和indexOf的区别 indexOf不能识别NaN
let arr = ['es7','es8','es9','es10',NaN]
console.log(arr.indexOf(NaN)) //-1
console.log(arr.includes(NaN)) //true
总结
如果只想知道数组里包不包含一个值,使用includes,如果想知道具体数值缩在的位置,使用indexOf
2. 幂运算符
函数实现
function pow(x,y){
let result = 1
for(let i = 0;i<y;i++){
result *= x
}
return result
}
console.log( pow(2,10)) //1024
Math实现
console.log(Math.pow(2,10))
使用幂运算符
console.log(2**10)
注意点
- NaN不可求幂
console.log(NaN ** 1) //NaN
- 幂运算符的两个*之间不能出现空格,否则语法会报错
ES2017(ES8)
1. Object.values()
Object.values()方法返回一个数组,成员是参数对象(不包含继承的)所有可遍历的键值。
let obj= {
name:liHua,
age:18,
weight:40,
}
console.log(Object.values(obj)) //['liHua', 18, 40]
let obj= {
name:"liHua",
age:18,
weight:40,
hobby:{
piano:true,
Calligraphy:true
}
}
console.log(Object.values(obj)) //['liHua', 18, 40,{piano: true, Calligraphy: true}]
2. Object.entries()
Object.entries() 方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历属性的键值对数组。
let obj2 = {
name: "liHua",
age: 18
}
console.log(Object.entries(obj2)) //[["name","liHua"],["age",18]]
let obj2 = {
name: "liHua",
age: 18,
information: {
weight: 40,
piano: true
}
}
console.log(Object.entries(obj2))
//打印结果
[["name","liHua"],["age",18],["information",{weight: 40,panio: true}]]
3. Object.getOwnPropertyDescriptors()
Object.getOwnPropertyDescriptors() 方法用来获取一个对象的所有自身属性的描述符。
- value:当前对象的默认值
- writable:表示当前对象是否可以修改
- enumerable:表示当前这个属性是否可以出现在对象的枚举属性中
- configurable:表示当前这个对象的属性是否能用delete删除
let obj3 = {
name: "liHua",
age: 18,
};
let desc = Object.getOwnPropertyDescriptors(obj3);
console.log(desc);
//打印结果
{
name: {
value: 'liHua',
writable: true,
enumerable: true,
configurable: true
},
age: {
value: 18,
writable: true,
enumerable: true,
configurable: true
}
}
对象的属性如何设置和修改呢,可以使用ES5提供的Object.defineProperty()
Object.defineProperty(obj3, "name", {
value: "hanMeiMei",
writable: true,
enumerable: true,
configurable: true,
})
console.log(obj3)
//打印结果
{name: 'hanMeiMei', age: 18}
当我们将writable设置为false,configurable设置为false时,对象的值不能被修改和删除。 当enumerable设置为false,对象的属性不可被枚举,所以遍历对象取不到name的键,只能取到age
Object.defineProperty(obj3, "name", {
value: "liHua",
writable: false,
enumerable: false,
configurable: false,
})
console.log(obj3.name) //打印结果:liHua
obj3.name = "hanMeiMei"
console.log(obj3.name) //打印结果:liHua
delete obj3.name
console.log(obj3.name) //打印结果:liHua
for(let key in obj3){
console.log(key) //打印结果:age
}
4. String.prototype.padStart()
语法:str.padStart(targetLength [, padString])
- targetLength:当前字符串需要填充到的目标长度,如果这个数值小于字符串的长度,则返回当前字符串本身
- padString:可选,选择填充的字符串,默认值是空字符串。如果字符串太长,填充后长度超过了目标值,则只保留左侧的长度,剩下部分被截断。
console.log("liHua".padStart(10)) //" syl"
console.log("liHua".padStart(10,"123456789")) //"12345liHua"
应用场景
- 日期格式化:yyyy-mm-dd格式
var month = date.getMonth() + 1
var strDate = date.getDate()
if (month >= 1 && month <= 9) {
month = '0' + month
}
if (strDate >= 0 && strDate <= 9) {
strDate = '0' + strDate
}
or
let month = format_date.getMonth() + 1 < 10 ? `0${format_date.getMonth() + 1}` : format_date.getMonth() + 1;
let day = format_date.getDate() < 10 ? `0${format_date.getDate()}` : format_date.getDate();
可以换成
let year = ((new Date().getMonth()) + 1).toString().padStart(2,"0")
隐藏手机号/银行卡等
let tel = "18600967266"
console.log(tel.slice(-4).padStart(tel.length,"*")) //*******7266
5. String.prototype.padEnd()
把指定字符串填充到字符串尾部,返回新字符串。
console.log("liHua".padEnd(10)) //"liHua "
console.log("liHua".padEnd(1)) //liHua
应用场景
js处理时间戳单位是毫秒ms,后端返回的时间如果不是毫秒ms。所以我们在处理这个时间戳的时候,保险起见,要先做一个13位的补全。
console.log(new Date().getTime().toString().padEnd(13,"0"))
6. async/await
我们都知道使用 Promise 能很好地解决回调地狱的问题,但如果处理流程比较复杂的话,那么整段代码将充斥着 then,语义化不明显,代码不能很好地表示执行流程,那有没有比 Promise 更优雅的异步方式呢?那就是async/await!
function foo() {
return "liHua"
}
console.log(foo()) //liHua
添加async后,返回的是一个Promise对象
async function foo() {
return "liHua"
}
console.log(foo())
// 打印结果
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: "liHua"
async函数中使用await,那么await这里的代码就会变成同步的了,意思就是说只有等await后面的Promise执行完成得到结果才会继续下去,await就是等待。请看下面的示例
function timeout() {
return new Promise(resolve => {
setTimeout(() => {
console.log(1)
resolve()
}, 1000)
})
}
// 不加async和await是2、1 加了是1、2
async function foo() {
await timeout()
console.log(2)
}
foo()
假如有这样一个使用场景:需要先请求 a 链接,等返回信息之后,再请求 b 链接的另外一个资源。下面代码展示的是使用 fetch 来实现这样的需求,fetch 被定义在 window 对象中,它返回的是一个 Promise 对象。
fetch("https://www.csdn.net/")
.then(response => {
console.log("response")
return fetch("https://juejin.cn/")
})
.then(response => {
console.log(response)
})
.catch(error => {
console.log(error)
})
虽然上述代码可以实现这个需求,但语义化不明显,代码不能很好地表示执行流程。基于这个原因,ES8 引入了 async/await,这是 JavaScript 异步编程的一个重大改进,提供了在不阻塞主线程的情况下使用同步代码实现异步访问资源的能力,并且使得代码逻辑更加清晰。
async function foo(){
try{
let response1 = await fetch("https://www.csdn.net/")
console.log("response1")
let response2 = await fetch("https://juejin.cn/")
console.log(response2)
}catch (error){
console.log(error)
}
}
foo()
注意点
- await只能子安async标记的函数内部使用,单独使用会触发Syntax error
- await后面需要跟异步操作,不然就没有意义。且await后面的Promise对象不必写then,因为await的作用之一就是获取后面Promise对象成功状态传递出来的参数。
缺陷
Async/await 让你的代码看起来是同步的,在某种程度上,也使得它的行为更加地同步。 await 关键字会阻塞其后的代码,直到promise完成,就像执行同步操作一样。它确实可以允许其他任务在此期间继续运行,但您自己的代码被阻塞。
这意味着您的代码可能会因为大量await的promises相继发生而变慢。每个await都会等待前一个完成,而你实际想要的是所有的这些promises同时开始处理(就像我们没有使用async/await时那样)。
ES2018(ES9)
1. Object.Rest & Object.Spread
let input = {
a: 1,
b: 2,
c: 3,
}
let output = {...input}
console.log(output) //{a: 1, b: 2, c: 3}
注意点
- 如果存在相同的属性名,只有最后一个会生效
let input = {
a: 1,
b: 2,
c: 3,
}
let output = { ...input, c: 4 }
console.log(output) //{a: 1, b: 2, c: 4}
- 如果属性的值是一个对象的话,该对象的引用会被拷贝,而不是生成一个新的对象。
let obj4 = {
x: { y: 10 }
}
let copy1 = {...obj4}
let copy2 = {...obj4}
obj4.x.y = "liHua"
console.log(copy1,copy2) //x: {y: 'liHua'} , x: {y: 'liHua'}
console.log(copy1.x === copy2.x) //true
- 当对象 key-value 不确定的时候,把必选的 key 赋值给变量,用一个变量收敛其他可选的 key 数据,这在之前是做不到的。注意,rest 属性必须始终出现在对象的末尾,否则将抛出错误。
let input = {
a: 1,
b: 2,
c: 3,
}
let { a, ...rest } = input
let output = { a, rest }
console.log(output) //{a:1,rest:{b: 2,,c: 3}}
2. for await of 异步迭代器
function TimeOut(time) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(time)
}, time)
})
}
async function test() {
let arr = [TimeOut(2000), TimeOut(1000), TimeOut(3000)]
for (let item of arr) {
console.log(Date.now(), item.then(console.log))
}
}
test()
// 打印结果
//1640830034005 Promise {<pending>}
//1640830034005 Promise {<pending>}
//1640830034005 Promise {<pending>}
//1000
//2000
//3000
上述代码证实了for of方法不能遍历异步迭代器
function TimeOut(time) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(time)
}, time)
})
}
async function test() {
let arr = [TimeOut(2000), TimeOut(1000), TimeOut(3000)]
for await (let item of arr) {
console.log(Date.now(), item)
}
}
test()
//打印结果
// 1640830494750 2000
// 1640830494750 1000
// 1640830495738 3000
for await of 等待每一个Promise对象变为fulfilled状态才进入下一步。
3. Promise.prototype.finally()
Promise.prototype.finally()方法会返回一个Promise对象,在Promise执行结束之后,无论结果是fulfilled或者rejected,在执行then()和catch()后,都会执行finally指定的回调函数。
new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("resolve")
},1000)
}).then(res=>{
console.log(res)
}).catch(error=>{
console.log(error)
}).finally(()=>{
console.log("finally")
})
//打印结果
// resolve
// finally
应用场景
- loading关闭 需要每次发送请求,都会有loading提示,请求发送完毕,就需要关闭loading提示框,也就是说不管成功或者失败,这个loading都需要关掉,这时吧关闭loading的代码写在finally里再合适不过了。
ES2019(ES10)
1. Object.fromEntries()
将键值对列表转换为一个对象
let obj5 = Object.fromEntries([
["foo", 1],
["bar", 2]
])
console.log(obj5) //{foo: 1, bar: 2}
案例1:Object转换操作
let obj6 = {
name:"liHua",
age:18
}
let entries = Object.entries(obj6)
console.log(entries) //[['name', 'liHua'],['age', 18]]
let fromEntries = Object.fromEntries(entries)
console.log(fromEntries) //{name: 'liHua', age: 18}
案例2:Map转Object
let map = new Map()
map.set("name","liHua")
map.set("age",18)
console.log(map) //{'name' => 'liHua', 'age' => 18}
let obj7 = Object.fromEntries(map)
console.log(obj7) //{name: 'liHua', age: 18}
案例3:过滤
let course = {
math: 80,
english: 85,
chinese: 90
}
let res = Object.entries(course).filter(([key, val]) => val > 80)
console.log(res) //[ [ 'english', 85 ], [ 'chinese', 90 ] ]
let res1 = Object.fromEntries(res)
console.log(res1) //{english: 85, chinese: 90}
案例4:url的serch参数转换
let url = "https://www.baidu.com?name=jimmy&age=18&height=1.88"
let queryString = url.slice(url.indexOf("?"))
const queryParams = new URLSearchParams(queryString);
const paramObj = Object.fromEntries(queryParams);
console.log(paramObj); // { name: 'jimmy', age: '18', height: '1.88' }
2.Array.prototype.flat()
flat方法会按照一个可指定的深度递归遍历数组,并将所有元素钰遍历的字数组的元素合并为一个新数组返回。
语法
let newArray = arr.flat([depth])
指定要提取嵌套数组的结构深度,默认值为 1。
示例
- 指定参数
let arr1 = [0, 1, 2, [[3, 4]]]
console.log(arr1.flat()) //[0, 1, 2, [3, 4]]
console.log(arr1.flat(2)) //[0, 1, 2, 3, 4]
- 展开全部
var arr2 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
console.log(arr2.flat(Infinity)) //[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
- 移出数组中的空项
var arr3 = [1,2,,4,5]
console.log(arr3.flat()) //[1, 2, 4, 5]
3. Array.prototype.flatMap()
flatMap() 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。从方法的名字上也可以看出来它包含两部分功能一个是 map,一个是 flat(深度为1)。
语法
var new_array = arr.flatMap(function callback(currentValue[, index[, array]]) {
// 返回新数组的元素
}[, thisArg])
-
callback:
可以生成一个新数组中的元素的函数,可以传入三个参数
-
currentValue
当前正在数组中处理的元素
-
index
可选,数组中当前正在处理元素的索引值
-
array
可选,被调用的map数组
-
thisArg
指定callbback函数时使用的this值
示例
- 简单使用
let num1 = [1, 2, 3]
console.log(num1.map(item => [item * 2])) //[[2],[4],[6]]
console.log(num1.flatMap(item => [item * 2])) //[2,4,6]
- map和flatMap的区别对比
let arr4 = ["早上你吃的什么", "", "吃的包子"]
console.log(arr4.map(item=>item.split("")));
打印结果
let arr4 = ["早上你吃的什么", "", "吃的包子"]
console.log(arr4.flatMap(item=>item.split("")))
//打印结果
//['早', '上', '你', '吃', '的', '什', '么', '吃', '的', '包', '子']
4. String.prototype.trimStart
trimStart() 方法从字符串的开头删除空格,trimLeft()是此方法的别名。
let str = ' foo '
console.log(str.length) // 8
str = str.trimStart() // 或str.trimLeft()
console.log(str.length) // 5
5. String.prototype.trimEnd
trimEnd() 方法从一个字符串的右端移除空白字符,trimRight 是 trimEnd 的别名。
let str = ' foo '
console.log(str.length) // 8
str = str.trimEnd() // 或str.trimRight()
console.log(str.length) // 6
6. Symbol.prototype.description
我们知道,Symbol 的描述只被存储在内部的 Description ,没有直接对外暴露,我们只有调用 Symbol 的 toString() 时才可以读取这个属性.
let name2 = Symbol("xiaobai")
console.log(name2.toString()) //Symbol(xiaobai)
console.log(name2) //Symbol(xiaobai)
console.log(name2 === "Symbol(xiaobai)") //false
console.log(name2.toString() === "Symbol(xiaobai)") //true
ES2020(ES12)
1.空值合并运算符
是一个逻辑操作符,当左侧的操作数为 null或者undefined时,返回其右侧操作数,否则返回左侧操作数。
let str1 = undefined ?? "str1"
let str2 = null ?? "str2"
console.log(str1) //str1
console.log(str2) //str2
与逻辑或的区别
逻辑或会在左侧造作数为false的时候,返回右侧操作数。
console.log(undefined || "xiaobai") //xiaobai
console.log(undefined ?? "xiaobai") //xiaobai
console.log(null || "xiaobai") //xiaobai
console.log(null ?? "xiaobai") //xiaobai
console.log(0 || "xiaobai") //xiaobai
console.log(0 ?? "xiaobai") //0
console.log(false || "xiaobai") //xiaobai
console.log(false ?? "xiaobai") /false
console.log("" || "xiaobai") //xiaobai
console.log("" ?? "xiaobai") //""(空字符串)
console.log(NaN || "xiaobai") //xiaobai
console.log(NaN ?? "xiaobai") //NaN