详解ECMAScript2019/ES10新属性


Posted in Javascript onDecember 06, 2019

每年都有一些新的属性进入ECMA262标准,今年发布的ECMAScript2019/ES10同样也有很多新的特性,本文将会挑选一些普通开发者会用到的新属性进行深入的解读。

Array.prototype.flat()

The flat() method creates a new array with all sub-array elements concatenated into it recursively up to the specified depth. -- MDN

简单来说flat这个函数就是按照一定的深度depth将一个深层次嵌套的数组拍扁, 例子:

const nestedArr = [1, 2, [3, 4, [5, 6, [7, [8], 9]]], 10]
console.log(nestedArr.flat())
// [1, 2, 3, 4, [5, 6, [7, [8], 9]], 10]
console.log(nestedArr.flat(2))
// [1, 2, 3, 4, 5, 6, [7, [8], 9], 10]
console.log(nestedArr.flat(3))
// [1, 2, 3, 4, 5, 6, 7, [8], 9, 10]
console.log(nestedArr.flat(4))
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log(nestedArr.flat(Infinity))
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

由上面的例子可以看出flat会按照指定的深度depth将一个数组扁平化,如果需要将数组完全拍扁变成一维数组,则指定depth为无限大,即是Infinity,相反如果不指定深度,其默认值是1。

Array.prototype.flatMap()

The flatMap() method first maps each element using a mapping function, then flattens the result into a new array. It is identical to a map() followed by a flat() of depth 1, but flatMap() is often quite useful, as merging both into one method is slightly more efficient. -- MDN

简单来说flatMap等于一个数组先调用完map函数再调用flat函数将其扁平化,扁平化的深度固定为1,先通过一个简单的例子感受一下:

const myArr = [1, 2, 3]
myArr
 .map(n => [n * n]) // [[1], [4], [9]]
 .flat() // [1, 4, 9]

// 用flatMap可以一步到位
myArr.flatMap(n => [n * n]) // [1, 4, 9]

从上面的例子来看flatMap如果只是将flat和map做了一个简单的组合好像可有可无,其实不然,flatMap有个强大的功能是可以在map的时候添加和删除元素,这个无论是map还是filter都没有这个功能。

要想删除某一个元素只需要在mapper函数里面返回一个空的数组[], 而增加元素只需在mapper函数里面返回一个长度大于1的数组,具体可以看下面的例子:

// 假如我们想要删除掉原数组里面所有的负数,同时将单数转换为一个复数和1
const a = [5, 4, -3, 20, 17, -33, -4, 18]
//    |\ \ x  |  | \  x  x  |
//    [4,1, 4,  20, 16,1,     18]
a.flatMap(n =>
 (n < 0) ? []: // 删除负数
 (n % 2 == 0) ? [n] : // 保留复数
         [n - 1, 1] // 单数变为一个复数和1
)
// [4, 1, 4, 20, 20, 16, 1, 18]

Object.fromEntries()

The Object.fromEntries() method transforms a list of key-value pairs into an object. --MDN

fromEntries方法将一个iterable对象返回的一系列键值对(key-value pairs)转换为一个object。先看一个简单的例子理解一下:

// key-value pairs数组
const entriesArr = [['k1', 1], ['k2', 2]]
console.log(Object.fromEntries(entriesArr)
// {k1: 1, k2: 2}

const entriesMap = new Map([
 ['k1', 1],
 ['k2', 2]
]) // {"k1" => 1, "k2" => 2}
console.log(Object.fromEntries(entriesMap))
// {k1: 1, k2: 2}

再来看一个自定义的iterable对象例子深入理解一下:

const iteratorObj = {
 [Symbol.iterator]: function () {
  const entries = [['k1', 1], ['k2', 2]]
  let cursor = 0

  return {
   next() {
    const done = entries.length === cursor
    
    return {
     value: done ? undefined : entries[cursor++],
     done
    }
   }
  }
 }
}
Object.fromEntries(iteratorObj) // {k1: 1, k2: 2}

这个方法有一个用途就是对object的key进行filter,举个例子:

const studentMap = {
 student1: {grade: 80},
 student2: {grade: 50},
 student3: {grade: 100}
}
const goodStudentMap = Object.fromEntries(
 Object
  .entries(studentMap)
  .filter(([_, meta]) => meta.grade >= 60)
)
console.log(goodStudentMap)
// {student1: {grade: 80}, student3: {grade: 100}}

String.prototype.trimStart

这个方法很简单,就是返回一个将原字符串开头的空格字符去掉的新的字符串,例子:

const greeting = '  Hello world! '
console.log(greeting.trimStart())
// 'Hello world! '

这个方法还有一个别名函数,叫做trimLeft,它们具有一样的功能。

String.prototype.trimEnd

这个方法和trimStart类似,只不过是将原字符串结尾的空格字符去掉,例子:

const greeting = ' Hello world! '
console.log(greeting.trimEnd())
// ' Hello world!'

这个方法也有一个别名函数,叫做trimRight, 它们也具有一样的功能。

Symbol.prototype.description

The read-only description property is a string returning the optional description of Symbol objects. -- MDN

ECMAScript2019给Symbol对象添加了一个可选的description属性,这个属性是个只读属性,看看例子:

console.log(Symbol('desc').description)
// desc
console.log(Symbol.for('desc').description)
// desc

// 一些内置的Symbol也有这个属性
console.log(Symbol.iterator.description)
// Symbol.iterator

// 如果初始化时没有带description,这个属性会返回一个undefined,因为这样才说这个属性是可选的
console.log(Symbol().description)
// undefined

// 这个属性是只读的,不能被设置
Symbol.iterator.description = 'mess it'
console.log(Symbol.iterator.description)
// Symbol.iterator

这个新的属性只要是为了方便开发者调试,不能通过比较两个Symbol对象的description来确定这两个Symbol是不是同一个Symbol:

var s1 = Symbol("desc")
var s2 = Symbol("desc")
console.log(s1.description === s2.description)
// true
console.log(s1 === s2)
// false

try catch optional binding

ECMAScript2019之后,你写try...catch时如果没必要时可以不用声明error:

// ECMAScript2019之前,你一定要在catch里面声明error,否则会报错
try {
 ...
} catch (error) {

}
// 可是有时候,你确实用不到这个error对象,于是你会写这样的代码
try {
 ...
} catch (_) {
 ...
}

// ECMAScript2019后,你可以直接这样写了
try {
 ...
} catch {
 ...
}

虽然这个新属性可以让你省略掉error,可是我觉得开发者应该避免使用这个属性,因为在我看来所有的错误都应该被处理,至少应该被console.error出来,否则可能会有一些潜在的bug,举个例子:

let testJSONObj
try {
 testJSONObj = JSON.prase(testStr)
} catch {
 testJSONObj = {}
}
console.log(testJSONObj)

以上代码中无论testStr是不是一个合法的JSON字符串,testJSONObj永远都是一个空对象,因为JSON.parse函数名写错了,而你又忽略了错误处理,所以你永远不会知道这个typo。

稳定的排序 Array.prototype.sort

ECMAScript2019后Array.sort一定是个稳定的排序。什么是稳定排序?所谓的稳定排序就是:假如没排序之前有两个相同数值的元素a[i]和a[j],而且i在j前面,即i < j,经过排序后元素a[i]依然排在a[j]元素的前面,也就是说稳定的排序不会改变原来数组里面相同数值的元素的先后关系。看个例子:

var users = [
 {name: 'Sean', rating: 14},
 {name: 'Ken', rating: 14},
 {name: 'Jeremy', rating: 13}
]
users.sort((a, b) => a.rating - b.rating)
// 非稳定的排序结果可能是
// [
//  {name: 'Jeremy', rating: 13}, 
//  {name: 'Ken', rating: 14}, 
//  {name: 'Sean', rating: 14}
// ]
// 虽然Sean和Ken具有同样的rating,可是非稳定的排序不能保证他们两个的顺序在排序后保持不变

// ECMAScript2019后,Array.sort将是一个稳定的排序,也就是说它可以保证Sean和Ken两个人的顺序在排序后不变
// [
//  {name: 'Jeremy', rating: 13}, 
//  {name: 'Sean', rating: 14}, 
//  {name: 'Ken', rating: 14}
// ]

改进Function.prototype.toString()

ECMAScript2019之前,调用function的toString方法会将方法体里面的空格字符省略掉,例如:

function hello() {
 console.log('hello word')
}

console.log(hello.toString())
//'function hello() {\nconsole.log('hello word')\n}'

ECMAScript2019之后,要求一定要返回函数源代码(保留空格字符)或者一个标准的占位符例如native code,所以ECMAScript2019之后,以上的输出会变为:

console.log(hello.toString())
//"function hello() {
// console.log('hello word')
//}"

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript 硬盘序列号+其它硬件信息
Dec 23 Javascript
给Function做的OOP扩展
May 07 Javascript
from表单多个按钮提交用onclick跳转不同action
Apr 24 Javascript
javascript实现画不相交的圆
Apr 07 Javascript
javascript判断图片是否加载完成的方法推荐
May 13 Javascript
js+html5实现canvas绘制网页时钟的方法
May 21 Javascript
JavaScript对象创建模式实例汇总
Oct 03 Javascript
JS+HTML5实现的前端购物车功能插件实例【附demo源码下载】
Oct 17 Javascript
jQuery实现鼠标跟随效果
Feb 20 Javascript
手把手教你 CKEDITOR 4 扩展插件制作
Jun 18 Javascript
js实现视图和数据双向绑定的方法分析
Feb 05 Javascript
JavaScript禁止右击保存图片,禁止拖拽图片的实现代码
Apr 28 Javascript
ES6的异步操作之promise用法和async函数的具体使用
Dec 06 #Javascript
原生JavaScript实现滑动拖动验证的示例代码
Dec 06 #Javascript
微信小程序 自定义弹窗实现过程(附代码)
Dec 05 #Javascript
Nuxt v-bind绑定img src不显示的解决
Dec 05 #Javascript
微信小程序swiper左右扩展各显示一半代码实例
Dec 05 #Javascript
微信小程序顶部导航栏可滑动并选中放大
Dec 05 #Javascript
微信小程序实现点击按钮后修改颜色
Dec 05 #Javascript
You might like
php文字水印和php图片水印实现代码(二种加水印方法)
2013/12/25 PHP
php中$美元符号与Zen Coding冲突问题解决方法分享
2014/05/28 PHP
PHP实现支持GET,POST,Multipart/form-data的HTTP请求类
2014/09/24 PHP
php+laravel依赖注入知识点总结
2019/11/04 PHP
imagettftext() 失效,不起作用
2021/03/09 PHP
拖动一个HTML元素
2006/12/22 Javascript
idTabs基于JQuery的根据URL参数选择Tab插件
2012/04/11 Javascript
javascript中的onkeyup和onkeydown区别介绍
2013/04/28 Javascript
JS 两日期相减,获得天数的小例子(兼容IE,FF)
2013/07/01 Javascript
jquery 实现窗口的最大化不论什么情况
2013/09/03 Javascript
JavaScript通过正则表达式实现表单验证电话号码
2014/03/07 Javascript
JSON.stringify转换JSON时日期时间不准确的解决方法
2014/08/08 Javascript
jQuery子属性过滤选择器用法分析
2015/02/10 Javascript
require.js的用法详解
2015/10/20 Javascript
javascript中checkbox使用方法实例演示
2015/11/19 Javascript
Bootstrap学习笔记 轮播(Carousel)插件
2017/03/21 Javascript
jQuery EasyUI结合zTree树形结构制作web页面
2017/09/01 jQuery
使用pkg打包Node.js应用的方法步骤
2018/10/19 Javascript
[13:25]VP vs VICI (BO3)
2018/06/07 DOTA
python中的函数用法入门教程
2014/09/02 Python
用Python实现一个简单的能够上传下载的HTTP服务器
2015/05/05 Python
Python聚类算法之凝聚层次聚类实例分析
2015/11/20 Python
python3 拼接字符串的7种方法
2018/09/12 Python
Python装饰器简单用法实例小结
2018/12/03 Python
python判断元素是否存在的实例方法
2020/09/24 Python
关于python scrapy中添加cookie踩坑记录
2020/11/17 Python
python3.9实现pyinstaller打包python文件成exe
2020/12/13 Python
以色列的身体护理及家居香薰品牌:Sabon NYC
2018/02/23 全球购物
美国最大的电子宠物训练产品制造商:PetSafe
2018/10/12 全球购物
娇韵诗Clarins意大利官方网站:法国天然护肤品牌
2020/03/11 全球购物
大学本科毕业生求职信范文
2013/12/18 职场文书
《我为你骄傲》教学反思
2014/02/20 职场文书
班级安全教育实施方案
2014/02/23 职场文书
银行客户经理岗位职责
2015/04/09 职场文书
详解Spring Security中的HttpBasic登录验证模式
2022/03/17 Java/Android
Python尝试实现蒙特卡罗模拟期权定价
2022/04/21 Python