Table of Contents
- Overview
- glossary (强行科普)
- tc39
- ecma-262
- stage
- Fun Facts
- ES7 (EcmaScript 2016)
- Array.prototype.includes
- Exponentiation Operator
- ES8 (EcmaScript 2017)
- Object.values
- Object.entries
- String padding
- 有了ES2017,麻麻再也不用担心Leftpad作者生气了
- String.prototype.padStart
- String.prototype.padEnd
- Object.getOwnPropertyDescriptors
- 现在继承可以这么简单的写
- shallow clone
- Trailing commas in function parameter lists and calls
- Async Functions
-
- Promise
-
- generator
-
- 但是promise只会把callback hell,改成 then hell
-
- 虽然这种情况可以用 Promise.all 来解决
-
-
- coroutine
-
- 最重要的是,还可以命令式的 try catch
-
- 现在有了 async function,不再需要第三方库的支持
-
- 但是不用太激动
- 而spawn的实现也很简单
- 返回一个 Promise
-
- call the generator function
genF
- call the generator function
-
- 异步的递归step
-
- resolve or reject promise
- Refs
Overview
大部分浏览器都已经实现 90%+ 的 ES6 features 了,如果现在还在看 ES6入门 我呵呵了。若是想快速回顾,不妨看看 Essential EcmaScript 6.
下面我们来看看 2017 草稿中到底有些什么新黑科技:
- Object.values/Object.entries
- String padding
- Object.getOwnPropertyDescriptors
- Trailing commas in function parameter lists and calls
- Async Functions
如果要问这些 proposals 都是哪来的,其实都可以在 tc39 的 这个 页面找到
能到达这个页面的都是 stage 4 的 proposals
而到达 stage 4 的,就会出现在 draft 上 https://tc39.github.io/ecma262/
glossary (强行科普)
tc39
Technical Committees 39
ecma-262
ecma 262 号规范
stage
- 0 strawman
- 1 proposal
- 2 draft
- 3 candidate
- 4 finished
Fun Facts
有人知道 ECMA-334 和 408 分别是什么语言的规范吗?
ES7 (EcmaScript 2016)
年份和版本号不要搞混了,7是指第七个版本,2016是release的年份,就像 ES6 也叫 ES2015 一样
ES7 很少被提及,是因为它的 feature 太少了,而且 没什么卵用
Array.prototype.includes
这个没什么好说的,跟lodash的 _.includes
一样一样的
终于从语言层面上让 indexOf > -1
更语义化了些。
ES8 (EcmaScript 2017)
下面来看看激动人心的ES8,先来看前面几个 没什么卵用 的小改动
Object.values
var obj = { foo: "bar", baz: 42 }; var array = [1,2,3] var symbol = Symbol('abc') var fn = function(){ return {foo: 'bar'} } fn.baz = 42; var string = 'foobar' var number = 123 console.log(Object.values(obj)); console.log(Object.values(array)); console.log(Object.values(symbol)); console.log(Object.values(string)); console.log(Object.values(number)); console.log(Object.values(fn)); console.log(Object.values(true));
[ 'bar', 42 ] [ 1, 2, 3 ] [] [ 'f', 'o', 'o', 'b', 'a', 'r' ] [] [ 42 ] []
Object.entries
var obj = { foo: "bar", baz: 42 }; var array = [1,2,3] var symbol = Symbol('abc') var fn = function(){ return {foo: 'bar'} } fn.baz = 42; var string = 'foobar' var number = 123 console.log(Object.entries(obj)); console.log(Object.entries(array)); console.log(Object.entries(symbol)); console.log(Object.entries(string)); console.log(Object.entries(number)); console.log(Object.entries(fn)); console.log(Object.entries(true));
[ [ 'foo', 'bar' ], [ 'baz', 42 ] ] [ [ '0', 1 ], [ '1', 2 ], [ '2', 3 ] ] [] [ [ '0', 'f' ], [ '1', 'o' ], [ '2', 'o' ], [ '3', 'b' ], [ '4', 'a' ], [ '5', 'r' ] ] [] [ [ 'baz', 42 ] ] []
String padding
还记得 leftpad 吗?
有了ES2017,麻麻再也不用担心Leftpad作者生气了
String.prototype.padStart
'abc'.padStart(10); // " abc" 'abc'.padStart(10, "foo"); // "foofoofabc"
String.prototype.padEnd
'abc'.padEnd(10); // "abc " 'abc'.padEnd(10, "foo"); // "abcfoofoof"
Object.getOwnPropertyDescriptors
Object.getOwnPropertyDescriptor
的复数形式
现在继承可以这么简单的写
function superclass() {} function subclass() {} subclass.prototype = Object.create(superclass.prototype, Object.getOwnPropertyDescriptors({ // define your methods and properties here }));
shallow clone
const shallowClone = (object) => Object.create( Object.getPrototypeOf(object), Object.getOwnPropertyDescriptors(object) );
Trailing commas in function parameter lists and calls
这个东西没什么用,跟数组一样,只有code diff的时候
1: function clownPuppiesEverywhere( 2: param1, 3: param2, + 4: param3, // updated to add new parameter 5: ) { /* ... */ }
才有那么一丢丢用
Async Functions
终于到 async function
了,但是在开始之前,我们来回顾一下 ES6 的 Promise 和 generator
Promise
new Promise((resolve, reject) => { console.log('first') setTimeout(resolve, 1000); }).then(() => { console.log('next 1s') throw new Error("hmm"); }).catch(err => { console.log('error:'+err) })
first next 1s error:Error: hmm
generator
现代浏览器都已经支持 generator 了, 写一个fibonacci数列生成器
function* fibonacci() { var pre = 0, cur = 1; for (;;) { var temp = pre; pre = cur; cur += temp; yield cur; } } let fib = fibonacci() console.log(fib.next()) console.log(fib.next()) console.log(fib.next()) console.log(fib.next()) console.log(fib.next())
{ value: 1, done: false } { value: 2, done: false } { value: 3, done: false } { value: 5, done: false } { value: 8, done: false }
但是promise只会把callback hell,改成 then hell
var asyncVal1 = Promise.resolve(1) var asyncVal2 = Promise.resolve(2) var asyncVal3 = Promise.resolve(3) asyncVal1.then(val1=>( asyncVal2.then(val2=>( asyncVal3.then(val3=>val1+val2+val3) )) )) .then(log('sum of val 1 2 3'))
虽然这种情况可以用 Promise.all 来解决
Promise.all([asyncVal1, asyncVal2, asyncVal3]) .then(([val1,val2,val3])=>val1+val2+val3)
但是并不是所有then hell都可以用promise的combinator就能解决的, 而generator的支持,彻底让我们离开了 then hell
最重要的是,还可以命令式的 try catch
spawn(function*(asyncVal1, asyncVal2, asyncVal3) { try { let val1 = yield asyncVal1; let val2 = yield asyncVal2; let val3 = yield asyncVal3; return val1 + val2 + val3 } catch(e) { return NaN } });
现在有了 async function,不再需要第三方库的支持
async function asyncSum(asyncVal1, asyncVal2, asyncVal3) { let val1 = await asyncVal1; let val2 = await asyncVal2; let val3 = await asyncVal3; return val1 + val2 + val3 };
但是不用太激动
async function <name>?<argumentlist><body> // => function <name>?<argumentlist>{ return spawn(function*() <body>, this); }
而spawn的实现也很简单
返回一个 Promise
function spawn(genF, self) { return new Promise(function(resolve, reject) { ... }); }
call the generator function genF
function spawn(genF, self) { return new Promise(function(resolve, reject) { var gen = genF.callself; // <-- ... }); }
异步的递归step
function spawn(genF, self) { return new Promise(function(resolve, reject) { var gen = genF.call(self); function step(nextF) { next = nextF(); // <-- 2 Promise.resolve(next.value).then(function(v) { step(function() { return gen.next(v); }); // <-- 3 }); } step(function() { return gen.next(undefined); }); // <-- 1 }); }
resolve or reject promise
function spawn(genF, self) { return new Promise(function(resolve, reject) { var gen = genF.call(self); function step(nextF) { var next; try { next = nextF(); } catch(e) { // finished with failure, reject the promise reject(e); // <-- return; } if(next.done) { // finished with success, resolve the promise resolve(next.value); // <-- return; } // not finished, chain off the yielded promise and `step` again Promise.resolve(next.value).then(function(v) { step(function() { return gen.next(v); }); }, function(e) { step(function() { return gen.throw(e); }); // <-- }); } step(function() { return gen.next(undefined); }); }); }
Refs
- https://github.com/tc39/proposals/blob/master/finished-proposals.md
- https://tc39.github.io/ecma262/
- https://tc39.github.io/ecmascript-asyncawait/
- https://github.com/jcouyang/clojure-flavored-javascript/blob/master/book/zh/%E7%AC%AC%E5%85%AB%E7%AB%A0.org
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptors
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects
- https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Object/values
- http://blog.oyanglul.us/javascript/essential-ecmascript6.html
- http://kangax.github.io/compat-table/es6/
/
Essential EcmaScript 2017 - 欧阳继超