JavaScript创新:Google I / O 2019成绩。第2部分

今天,我们将发布JavaScript创新的第二部分。 在这里,我们谈论数字的分隔符,关于globalThis数字,关于使用数组和对象,关于globalThis ,关于排序,关于国际化API以及关于promises的问题。



第一部分

数字分隔符


程序中发现的长数字很难阅读。 例如, 1000000000是十进制的十亿。 但乍一看很难理解。 因此,如果程序的读者遇到类似的情况-为了正确地理解它,他将必须仔细考虑零。

在现代JavaScript中,您可以使用数字的分隔符-下划线( _ ),使用下划线可以提高长数字的可读性。 这是使用定界符编写的数字在代码中的显示方式:

 var billion = 1_000_000_000; console.log( billion ); // 1000000000 

分隔符可用于将数字任意划分为多个片段。 JavaScript在处理数字时,只会忽略分隔符。 在写任何数字时可以使用它们:整数,浮点数,二进制,十六进制,八进制。

 console.log( 1_000_000_000.11 ); // 1000000000.11 console.log( 1_000_000_000.1_012 ); // 1000000000.1012 console.log( 0xFF_00_FF ); // 16711935 console.log( 0b1001_0011 ); // 147 console.log( 0o11_17 ); // 591 

→支持


  • TC39: 阶段3
  • 铬:75+
  • 节点:12.5+

Bigint数据类型


JavaScript中的数字是使用Number构造函数创建的。

使用Number数据类型可以安全表示的最大值是(2⁵³-1),即9007199254740991。您可以使用Number.MAX_SAFE_INTEGER构造查看此数字。

请注意,当在JS代码中使用数字文字时,JavaScript将对其进行处理,并使用Number构造函数基于该文字创建对象。 该对象的原型包含使用数字的方法。 所有原始数据类型都会发生这种情况。

如果我们尝试在数字9007199254740991中添加一些内容,将会怎样?

 console.log( Number.MAX_SAFE_INTEGER ); // 9007199254740991 console.log( Number.MAX_SAFE_INTEGER + 10 ); // 9007199254741000 

Number.MAX_SAFE_INTEGERconsole.log()的第二个输出10相加的结果不正确。 这是由于JS无法正确执行大于Number.MAX_SAFE_INTEGER数字的计算。 您可以使用bigint数据bigint来解决此问题。

bigint类型允许bigint表示大于Number.MAX_SAFE_INTEGER整数。 使用BigInt值类似于使用Number类型的Number 。 尤其是,该语言具有BigInt()函数,您可以使用该函数创建相应的值,以及内置的原始bigint数据类型用于表示大整数。

 var large = BigInt( 9007199254740991 ); console.log( large ); // 9007199254740991n console.log( typeof large ); // bigint 

JavaScript在BigInt文字的末尾添加n 。 对我们来说,这意味着可以通过在整数的末尾加上n来编写此类文字。

现在我们有了BigInt数,可以安全地对大量bigint类型执行数学运算。

 var large = 9007199254740991n; console.log( large + 10n ); // 9007199254741001n 

类型number的数字与类型bigint的数字不同。 特别是,我们谈论的是BigInt-numbers只能是整数的事实。 结果,事实证明您无法执行使用bigintnumber类型的算术运算。

应当注意, BigInt()函数可以采用各种数字:十进制,二进制,十六进制,八进制。 在此函数内部,它们将转换为数字,使用十进制数字系统表示。

bigint类型还支持位分隔符:

 var large = 9_007_199_254_741_001n; console.log( large ); // 9007199254741001n 

→支持


  • TC39: 阶段3
  • 铬: 67+
  • 节点:10.4+
  • Firefox:68+

新的数组方法:.flat()和.flatMap()


在这里,我们将讨论Array对象的新原型方法.flat().flatMap()方法。

flat .flat()方法


现在, Array类型的对象有了一个新方法.flat(n) 。 它返回一个新数组,以递归方式将数组的元素提升到指定的级别n 。 默认情况下, n为1。此方法可以传递等于Infinity n ,这使您可以将具有嵌套数组的数组转换为一维数组。

 var nums = [1, [2, [3, [4, 5]]]]; console.log( nums.flat() ); // [1, 2, [3, [4,5]]] console.log( nums.flat(2) ); // [1, 2, 3, [4,5]] console.log( nums.flat(Infinity) ); // [1, 2, 3, 4, 5] 

→支持


  • TC39: 第4阶段
  • 铬: 69+
  • 节点:11岁以上
  • Firefox:62岁以上

flat .flatMap()方法


在解决日常任务时,程序员有时可能需要使用.map()方法处理数组,然后将其转换为平面结构。 例如,创建一个包含这些数字和这些数字的平方的数组:

 var nums = [1, 2, 3]; var squares = nums.map( n => [ n, n*n ] ) console.log( squares ); // [[1,1],[2,4],[3,9]] console.log( squares.flat() ); // [1, 1, 2, 4, 3, 9] 

通过使用.flatMap()方法,可以简化此问题的解决方案。 它将转换传递给它的回调函数返回的数组,就像转换其参数n等于1的.flat()方法一样。

 var nums = [1, 2, 3]; var makeSquare = n => [ n, n*n ]; console.log( nums.flatMap( makeSquare ) ); // [1, 1, 2, 4, 3, 9] 

→支持


  • TC39: 第4阶段
  • 铬: 69+
  • 节点:11岁以上
  • Firefox:62岁以上

▍Object.fromEntries()方法


可以从一个对象中提取:类型对:可以使用静态的Method Object来使用: ,该方法返回一个数组,该数组的每个元素都是一个数组,其中包含一个键(第一个元素),第二个元素包含一个值。

 var obj = { x: 1, y: 2, z: 3 }; var objEntries = Object.entries( obj ); console.log( objEntries ); // [["x", 1],["y", 2],["z", 3]] 

现在我们可以使用一个静态方法Object.fromEntries() ,它允许我们将类似的结构转换回一个对象。

 var entries = [["x", 1],["y", 2],["z", 3]]; var obj = Object.fromEntries( entries ); console.log( obj ); // {x: 1, y: 2, z: 3} 

entries()方法用于促进对存储在对象中的数据进行过滤和映射。 结果是一个数组。 但是到目前为止,将这样的数组转换为对象的任务还没有很好的解决方案。 可以使用Object.fromEntries()方法来解决此问题。

 var obj = { x: 1, y: 2, z: 3 }; // [["x", 1],["y", 2],["z", 3]] var objEntries = Object.entries( obj ); // [["x", 1],["z", 3]] var filtered = objEntries.filter( ( [key, value] ) => value % 2 !== 0 //  ,     ); console.log( Object.fromEntries( filtered ) ); // {x: 1, z: 3} 

如果Map :数据结构用于存储对: ,那么其中的数据将按照它们添加到其中的顺序进行存储。 同时,数据的存储方式类似于Object.entries()方法返回的数组。 Object.fromEntries()方法Object.fromEntries()很容易用于将Map数据结构转换为对象。

 var m = new Map([["x", 1],["y", 2],["z", 3]]); console.log( m ); // {"x" => 1, "y" => 2, "z" => 3} console.log( Object.fromEntries( m ) ); // {x: 1, y: 2, z: 3} 

→支持



▍全球房地产globalThis


我们熟悉JavaScript中使用的this 。 它没有固定值。 而是,其含义取决于对其进行访问的上下文。 在任何环境中,从最高级别的上下文访问this时,它都指向一个全局对象。 这就是这个的全球意义。

例如,在基于浏览器的JavaScript中,其全局值是window对象。 您可以使用JavaScript文件的顶级(在最外部的上下文中)或在浏览器JS控制台中使用console.log(this)构造来验证这一点。


在浏览器控制台中访问它

Node.js中this的全局值指向一个global对象。 在网络工作者内部,它指向工作者本人。 但是,要获得这一全球价值并非易事。 事实是,您无法在任何地方引用this 。 例如,如果您尝试在类的构造函数中执行此操作,那么事实证明this指向相应类的实例。

在某些环境中, self this可用于访问this的全局值。 该关键字与在浏览器,Node.js和Web Worker中访问此值的机制相同。 使用关于如何在不同环境中调用this方法的全局值的知识,可以创建一个返回此值的函数:

 const getGlobalThis = () => { if (typeof self !== 'undefined') return self; if (typeof window !== 'undefined') return window; if (typeof global !== 'undefined') return global; if (typeof this !== 'undefined') return this; throw new Error('Unable to locate global `this`'); }; var globalThis = getGlobalThis(); 

在我们面前的是一个原始的polyfill,用于获取this对象的全局信息。 在此处阅读有关此内容的更多信息。 JavaScript现在具有globalThis关键字。 它提供了一种访问不同环境的全局值的通用方法,并且不依赖于从中访问该程序的程序的位置。

 var obj = { fn: function() {  console.log( 'this', this === obj ); // true  console.log( 'globalThis', globalThis === window ); // true } }; obj.fn(); 

→支持


  • TC39: 阶段3
  • 铬: 71+
  • 节点:12岁以上
  • Firefox:65岁以上

排序稳定


ECMAScript标准未提供JavaScript引擎应实现的特定数组排序算法。 它仅描述用于排序的API。 结果,使用不同的JS引擎,可能会遇到排序操作的性能和排序算法的稳定性(稳定性)方面的差异。

现在,该标准要求排序数组必须稳定。 有关分类稳定性的详细信息,请参见此处 。 排序算法的这一特征的实质如下。 如果排序结果是一个经过修改的数组,则该算法是稳定的,该排序结果包含的元素具有相同的值,这些元素的值不受排序的影响,排序的顺序与它们在原始数组中的放置顺序相同。 考虑一个例子:

 var list = [  { name: 'Anna', age: 21 },  { name: 'Barbra', age: 25 },  { name: 'Zoe', age: 18 },  { name: 'Natasha', age: 25 } ]; //      age [  { name: 'Natasha', age: 25 }  { name: 'Barbra', age: 25 },  { name: 'Anna', age: 21 },  { name: 'Zoe', age: 18 }, ] 

在这里,包含对象的list数组按这些对象的age字段排序。 在list数组中, name属性等于Barbra的对象位于name属性等于Natasha的对象之前。 由于这些对象的age值相等,因此我们可以期望在排序后的数组中这些元素将相对于彼此保留以前的排列顺序。 但是,实际上这是无法预期的。 排序数组的精确形成方式完全取决于所使用的JS引擎。

现在,所有现代浏览器和Node.js都使用一种稳定的排序算法,该算法在访问.sort()数组方法时调用。 这样一来,对于相同的数据,您总是可以得到相同的结果:

 //    [  { name: 'Barbra', age: 25 },  { name: 'Natasha', age: 25 }  { name: 'Anna', age: 21 },  { name: 'Zoe', age: 18 }, ] 

过去,某些JS引擎支持稳定排序,但仅适用于小型数组。 为了提高处理大型阵列时的性能,它们可以使用更快的算法并牺牲排序稳定性。

→支持


  • 铬: 70+
  • 节点:12岁以上
  • Firefox:62岁以上

国际化API


国际化API旨在组织字符串比较,以格式化数字,日期和时间,这是各种区域标准(区域设置)的惯例。 通过Intl 对象可以组织对此API的访问。 该对象提供了用于创建排序器对象和格式化数据的对象的构造函数。 可在此处找到Intl对象支持的语言环境列表。

tlIntl.RelativeTimeFormat()


在许多应用中,通常需要以相对格式输出时间。 它可能看起来像是“ 5分钟前”,“昨天”,“ 1分钟前”等等。 如果将网站资料翻译成不同的语言,则必须在网站组合中包括描述时间的所有可能的相对结构组合。

JS现在具有Intl.RelativeTimeFormat(locale, config) 构造函数 ,该构造函数使您可以为不同的语言环境创建日期和时间格式设置系统。 特别是,我们谈论的对象具有.format(value, unit) ,该方法使您可以生成各种相对时间戳。 看起来像这样:

 // español ( ) var rtfEspanol= new Intl.RelativeTimeFormat('es', {  numeric: 'auto' }); console.log( rtfEspanol.format( 5, 'day' ) ); // dentro de 5 días console.log( rtfEspanol.format( -5, 'day' ) ); // hace 5 días console.log( rtfEspanol.format( 15, 'minute' ) ); // dentro de 15 minutos 

→支持


  • TC39: 阶段3
  • 铬: 71+
  • 节点:12岁以上
  • Firefox:65岁以上

tlIntl.ListFormat()


Intl.ListFormat构造函数使Intl.ListFormat可以使用单词and)和or)组合列表项。 创建相应的对象时,构造函数将被传递给语言环境和带有参数的对象。 其type参数可以是conjunctiondisjunctionunit 。 例如,如果要使用连接对象来合并 [apples, mangoes, bananas]的元素,我们将得到apples, mangoes and bananas形式的字符串。 如果使用析取对象,则会得到一串apples, mangoes or bananas

Intl.ListFormat 构造函数创建的对象具有组合列表 .format(list) 方法 。 考虑一个例子:

 // español ( ) var lfEspanol = new Intl.ListFormat('es', {  type: 'disjunction' }); var list = [ 'manzanas', 'mangos', 'plátanos' ]; console.log( lfEspanol.format( list ) ); // manzanas, mangos o plátanos 

→支持



Local国际语言环境()


通常,“区域标准”的概念不仅仅是一种语言的名称。 这可能包括日历的类型,有关使用的时间周期的信息以及语言名称。 Intl.Locale(localeId, config) 构造函数 Intl.Locale(localeId, config)用于基于传递给它的config对象创建格式化的Intl.Locale(localeId, config)字符串。

使用Intl.Locale创建Intl.Locale对象包含所有指定的区域设置。 其.toString()方法产生格式化的区域标准字符串。

 const krLocale = new Intl.Locale( 'ko', {  script: 'Kore', region: 'KR',  hourCycle: 'h12', calendar: 'gregory' } ); console.log( krLocale.baseName ); // ko-Kore-KR console.log( krLocale.toString() ); // ko-Kore-KR-u-ca-gregory-hc-h12 

在这里,您可以阅读有关Unicode中的标识符和语言环境标签的信息。

→支持


  • TC39: 阶段3
  • 铬:74+
  • 节点:12岁以上

承诺


到目前为止,JS具有静态方法Promise.all()Promise.race()Promise.all([...promises])方法返回一个promise,该promise将作为参数传递给该方法的所有promise解析成功。 如果转移给它的承诺中的至少一个被拒绝,则该承诺被拒绝。 Promise.race([...promises])方法返回一个promise,在任何传递给它的promise被解析后,该promise将被解析,如果其中至少一个promise被拒绝,则被拒绝。

JS开发人员社区迫切需要一个静态方法,返回的诺言将在传递给它的所有诺言完成(允许或拒绝)之后得到解决。 另外,我们需要一种类似于race()的方法,该方法将返回一个promise,等待传递给它的任何promise的解析。

m Promise.allSettled()方法


Promise.allSettled()方法接受一个promise数组。 在所有承诺都被拒绝或允许之后,才允许他返回的承诺。 结果是此方法返回的promise不需要catch

事实是,这一诺言总是能够成功解决。 then块按照它们出现的顺序从每个承诺中接收statusvalue

 var p1 = () => new Promise(  (resolve, reject) => setTimeout( () => resolve( 'val1' ), 2000 ) ); var p2 = () => new Promise(  (resolve, reject) => setTimeout( () => resolve( 'val2' ), 2000 ) ); var p3 = () => new Promise(  (resolve, reject) => setTimeout( () => reject( 'err3' ), 2000 ) ); var p = Promise.allSettled( [p1(), p2(), p3()] ).then(  ( values ) => console.log( values ) ); //  [ {status: "fulfilled", value: "val1"}  {status: "fulfilled", value: "val2"}  {status: "rejected", value: "err3"} ] 

→支持



▍方法Promise.any()


Promise.any()方法类似于Promise.race() ,但是当传递给此方法的一个承诺被拒绝时,它返回的承诺不会执行catch

相反,他等待所有诺言的解决。 如果没有允诺,那么catch块将被执行。 如果任何诺言都成功解决,则将执行。

总结


在本文中,我们研究了Google I / O 2019大会上讨论的一些JavaScript创新。 我们希望您在其中找到对您有用的东西。

亲爱的读者们! 您在JavaScript中特别想念什么?

Source: https://habr.com/ru/post/zh-CN464131/


All Articles