|
TC39是 Ecma International标准化组织旗下的技术委员会的一员,它负责管理着ECMAScript语言和标准化API。ECMAScript语言和标准化API又可以分为两个标准:# f: \* q O: f* P1 E" s* G* _4 Q+ ^
- 第一个是ECMA-262标准,它包含了语言的语法和核心的API。
- 另一个标准ECMA-402则包含了一些国际化的API,提供给ECMAScript核心API选择性支持。
) p; u' v, W$ L7 q 一、.at()4 M# r" T, W/ \5 [4 }3 i
这是个挺不错的新语法。其他有些语言是可以用 arr[-1] 来获取数组末尾的元素,但是对于 JS 来说这是实现不了的事情。因为 [key] 对于对象来说就是在获取 key 对应的值。数组也是对象,对于数组使用 arr[-1] 就是在获取 key 为 -1 的值。$ M4 C' b: h' p, T8 Y6 b
由于以上原因,我们想获取末尾元素就得这样写 arr[arr.length - 1],以后有了 at 这个方法,我们就可以通过 arr.at(-1) 来拿末尾的元素了,另外同样适用类数组、字符串。) X% @0 E. S- a6 H! ~& ?& G* w+ ~
- // Polyfill
- function at(n) {
- // ToInteger() abstract op
- n = Math.trunc(n) || 0;
- // Allow negative indexing from the end
- if(n < 0) n += this.length;
- // OOB access is guaranteed to return undefined
- if(n < 0 || n >= this.length) return undefined;
- // Otherwise, this is just normal property access
- return this[n];
- }
二、顶层 await
& C7 E4 r; E/ r/ E( K await 都得用 async 函数包裹大家肯定都知道,这个限制导致我们不能在全局作用域下直接使用 await,必须得包装一下。有了这个提案以后,大家就可以直接在顶层写 await 了,算是一个便利性的提案。目前该提案已经进入阶段 4,板上钉钉会发布。另外其实 Chrome 近期的更新已经支持了该功能。 0 W* B: s6 Z% x" O: I' b6 J- k) b
+ N* {6 v( x* O" Z) D2 E/ f
三、Error Cause5 g9 @+ V$ _% V4 Y1 {% G% @3 y. S. \
这个语法主要帮助我们便捷地传递Error。一旦可能出错的地方一多,实际就不清楚错误到底是哪里产生的。如果希望外部清楚的知道上下文信息的话,需要封装以下error。/ i2 ~' L+ g) ~6 S
- async function getSolution() {
- const rawResource = await fetch('//domain/resource-a')
- .catch(err => {
- // How to wrap the error properly?
- // 1. throw new Error('Download raw resource failed: ' + err.message);
- // 2. const wrapErr = new Error('Download raw resource failed');
- // wrapErr.cause = err;
- // throw wrapErr;
- // 3. class CustomError extends Error {
- // constructor(msg, cause) {
- // super(msg);
- // this.cause = cause;
- // }
- // }
- // throw new CustomError('Download raw resource failed', err);
- })
- const jobResult = doComputationalHeavyJob(rawResource);
- await fetch('//domain/upload', { method: 'POST', body: jobResult });
- }
- await doJob(); // => TypeError: Failed to fetch
那么有了这个语法以后,就可以这样来简化代码:
3 c0 ?- j. ^; j. }( @# M$ L' c- E' y- async function doJob() {
- const rawResource = await fetch('//domain/resource-a')
- .catch(err => {
- throw new Error('Download raw resource failed', { cause: err });
- });
- const jobResult = doComputationalHeavyJob(rawResource);
- await fetch('//domain/upload', { method: 'POST', body: jobResult })
- .catch(err => {
- throw new Error('Upload job result failed', { cause: err });
- });
- }
- try {
- await doJob();
- } catch (e) {
- console.log(e);
- console.log('Caused by', e.cause);
- }
- // Error: Upload job result failed
- // Caused by TypeError: Failed to fetch
四、管道运算符/ {' j4 \0 P4 J4 \
这个语法的Star特别多,有5k多个,侧面也能说明是个受欢迎的语法,但是距离发布应该还有好久,毕竟这个提案三四年前就有了,目前还只到阶段 1。这个语法其实在其他函数式编程语言上很常见,主要是为了函数调用方便: N+ G8 P: p3 g2 M( B9 Q
- let result = exclaim(capitalize(doubleSay("hello")));
- result //=> "Hello, hello!"
- let result = "hello"
- |> doubleSay
- |> capitalize
- |> exclaim;
- result //=> "Hello, hello!"
这只是对于单个参数的用法,其它的用法有兴趣的读者可以自行阅读提案,其中涉及到了特别多的内容,这大概也是导致推进阶段慢的原因吧。 # N$ c8 @1 }! `1 V# z2 |
五、新的数据结构:Records & Tuples
3 `5 H9 z3 @/ F7 U8 [6 \ 这个数据结构笔者觉得发布以后会特别有用,总共新增了两种数据结构,可以通过#来声明: 8 K# y0 l6 ]8 ?
#{ x: 1, y: 2 }
( D* L$ c5 E7 R: O% `4 v0 Y: I/ K* V#[1, 2, 3, 4]
% Q: ]. V# G+ {( Y, M9 n 这种数据结构是不可变的,类似 React 中为了做性能优化会引入的 immer 或者 immutable.js,其中的值只接受基本类型或者同是不可变的数据类型。
- I7 M7 L/ a+ V8 n( {/ p' h0 p8 w- const proposal = #{
- id: 1234,
- title: "Record & Tuple proposal",
- contents: `...`,
- // tuples are primitive types so you can put them in records:
- keywords: #["ecma", "tc39", "proposal", "record", "tuple"],
- };
- // Accessing keys like you would with objects!
- console.log(proposal.title); // Record & Tuple proposal
- console.log(proposal.keywords[1]); // tc39
- // Spread like objects!
- const proposal2 = #{
- ...proposal,
- title: "Stage 2: Record & Tuple",
- };
- console.log(proposal2.title); // Stage 2: Record & Tuple
- console.log(proposal2.keywords[1]); // tc39
- // Object functions work on Records:
- console.log(Object.keys(proposal)); // ["contents", "id", "keywords", "title"]
|
|