2020.12.06
ざっくり ECMAScript 2017
ざっくりと ES2017 のおさらいをしたい人向け。オカタい説明は mdn さんあたりにおまかせするとして、ゆるっとざっくり気楽にサクッとコードベースでおさらい。ES2017 は 待望の? Async / Await が追加されたよ。
環境構築
- MacOS High Sierra
- ふる〜い MBP 使ってます
- nvm, ndenv, nodebrew のどれでもいいので node が動く環境を用意
- VSCode 使ってます。拡張はお好みで。
- node.js のバージョンは v14.7.0
- 適当なディレクトリを掘って、index.js を用意しています (ファイル名はお好みで)
- 動作確認は $ node index.js って叩いてます
最小限で動かすだけならこれだけでおっけいです。ここらへんの準備も面倒ならば codepen だの JSFiddle だの REPL だのを使ってもおk
es2017
es2017 は以下のような機能が追加されている(参考 Wikipedia ECMAScript)
非同期関数 (async/await)、SharedArrayBufferとAtomics、String.padStart/padEnd、Object.values/entries、Object.getOwnPropertyDescriptors、関数の引数における末尾のカンマ許容
async / await
asyncは 非同期関数を定義する時に使用するキーワード。以下のような特徴・仕様がある
- async function 〜 で非同期関数を定義。
- async () => {} のようにアロー関数の形式も。
- async function には await を含める事ができる (mustでないと成立しないわけではない)
- async function の戻り値は 暗黙的に Promise ( resolve or reject ) で返す
- (引用 mdn ) 非同期関数の戻り値は 「Promise で、非同期関数から返される値で解決するか、または非同期関数内の捕捉されなかった例外で拒否します。」
- async/await は結局 Promise の糖衣構文
await は async function により Promise が返ってくるまで待ってくれる演算子。んー。なんかこの表現気持ち悪いな。
とりあえず Promise での簡単な例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
const fn = () => { return new Promise( resolve => { setTimeout( () => { console.log(2) resolve() }, 1000) }) } (() => { console.log(1) fn().then(()=>{ console.log(3) }) })() // 1 // 2 // 3 |
上記のコードを async / await で書き直すと以下のようになる
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
const fn = () => { return new Promise( resolve => { setTimeout(()=>{ console.log(2) resolve() }, 1000) }) } (async () => { console.log(1) await fn() console.log(3) })() // 1 // 2 // 3 |
async/await での例外処理
Promise での例外は「catch( ) ハンドラー」もしくは「onRjected」を探していました。async/await では、同期処理で実装していた try-catch 的な方法で例外を補足できるよ。下記は mdn 掲載の例です
1 2 3 4 5 6 7 8 9 10 |
async function foo() { try { const result = await doSomething(); const newResult = await doSomethingElse(result); const finalResult = await doThirdThing(newResult); console.log(`Got the final result: ${finalResult}`); } catch(error) { failureCallback(error); } } |
ってことで例。fnで例外を起こしてるよ。catch( ) で補足してる
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
const returnExeption = () => { throw new Error("hoge") } const fn = () => { return new Promise( (resolve, reject) => { console.log(2) returnExeption() }) } (async () => { try { console.log(1) await fn() console.log(3) }catch(error){ console.log(0) } })() // 1 // 2 // 0 |
setTimeout( ) と絡めた時の例外処理。今の所次のコードで済ませてる(setTimeout 内の try-catch のアレ感
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
const returnExeption = () => { throw new Error("例外起きてまっせ") } const fn = () => { return new Promise( (resolve, reject) => { setTimeout(()=>{ console.log(2) try { returnExeption() }catch(e){ reject() } }, 1000) }) } (async () => { try { console.log(1) await fn() console.log(3) }catch(error){ console.log(0) } })() // 1 // 2 // 0 |
String.padStart/padEnd
対象の文字列を、文字列を指定した桁数(文字数)分、指定した文字で埋める。
以下、mdn のサンプルをわかりやすく(醜く)したもの
1 2 3 4 5 6 7 8 9 10 11 |
const origin = '5' const filled = origin.padStart(4, '0') console.log(origin) // 5 console.log(filled) // 0005 const cardNumber = '4934345634326095' const sliceNumber = cardNumber.slice(-4) console.log(sliceNumber) // 6095 const filledNumber = sliceNumber.padStart(cardNumber.length, '*') console.log(filledNumber) // ************6095 |
Object.values/entries
Object.values はオブジェクトが持つプロパティの値を配列に、Object.entriesはオブジェクトを Key, Value を配列化した配列に( array in array )するよ
1 2 3 4 5 6 7 8 9 10 11 |
const obj = { name: 'taro', age: 20, address: 'Shinjuku Tokyo' } console.log(Object.values(obj)) console.log(Object.entries(obj)) // [ 'taro', 20, 'Shinjuku Tokyo' ] // [ [ 'name', 'taro' ], [ 'age', 20 ], [ 'address', 'Shinjuku Tokyo' ] ] |
関数の引数における末尾のカンマ許容
配列やオブジェクトの末尾のカンマは許容されていたけど、関数の引数も許容された。
1 2 3 4 5 6 7 8 |
const arr = [1, 2, 3,] const obj = { a: 1, b: 2, c:3, } const fn = (a, b, c,) => { console.log(a + b + c) } fn(1, 2, 3,) |