正式リリースされたES8の主な新機能 🔥

EcmaScript仕様第8版の新機能


EcmaScript 8もしくはEcmaScript 2017が、6月末にTC39から正式にリリースされました。私たちはこの1年、EcmaScriptについて色々と議論しているようですが、それは無駄なことではありません。現在、ES標準は新しい仕様のバージョンが年1回公開されています。ES6は2015年、ES7は2016年に公開されましたが、ES5のリリース時期をご記憶でしょうか。JavaScriptが魔法のように普及する以前の、2009年のことでした。

つまり私たちは、安定した言語としてJavaScriptの開発上の変化をたどっており、今や自分の語彙にES8を加える必要があるのです。

ES2017(このJavaScript仕様の第8版)が昨日、正式にリリース&公開! https://t.co/1ITn5bzaqj 👏
 — @kentcdodds

自信がある方であれば、深呼吸して、WebあるいはPDF版の仕様をお読みください。そうでない方のために、この記事ではES8の主な新機能をコード例を使ってご紹介します。

本記事はJason Cheng氏によって中国語に翻訳されました。


文字列パディング

このセクションは、Stringオブジェクトに2つの関数、padStartとpadEndが追加されたことについてです。
名前にあるように、これらの目的は文字列の先頭または末尾にパディングし、文字列が指定の長さになるようにすることです。パディングで追加できるのは特定の文字、文字列、またはデフォルトのスペースです。以下が関数宣言です。

str.padStart(targetLength [, padString])
str.padEnd(targetLength [, padString])

ご覧のように、関数の1つ目のパラメータはtargetLengthで、これは返される文字列の合計長です。2つ目のパラメータpadStringはオプションで、ソース文字列のパディングに使う文字列です。デフォルト値はスペースです。

'es8'.padStart(2);          // 'es8'
'es8'.padStart(5);          // '  es8'
'es8'.padStart(6, 'woof');  // 'wooes8'
'es8'.padStart(14, 'wow');  // 'wowwowwowwoes8'
'es8'.padStart(7, '0');     // '0000es8'
'es8'.padEnd(2);          // 'es8'
'es8'.padEnd(5);          // 'es8  '
'es8'.padEnd(6, 'woof');  // 'es8woo'
'es8'.padEnd(14, 'wow');  // 'es8wowwowwowwo'
'es8'.padEnd(7, '6');     // 'es86666'


ブラウザサポート(MDN)


Object.valuesとObject.entries

Object.valuesメソッドは、与えられたオブジェクト自身の列挙可能なプロパティ値の配列をfor inループの場合と同様の順序で返します。関数宣言は単純です。

Object.values(obj)

objパラメータはこの操作のソースオブジェクトです。ソースオブジェクトにできるのは、オブジェクトまたは配列([10, 20, 30] -> { 0: 10, 1: 20, 2: 30 }のようなインデックスを持つオブジェクト)です。

const obj = { x: 'xxx', y: 1 };
Object.values(obj); // ['xxx', 1]

const obj = ['e', 's', '8']; // { 0: 'e', 1: 's', 2: '8' };と同じ
Object.values(obj); // ['e', 's', '8']

// 数値キーを使うと、キーの数値順で値が返される
const obj = { 10: 'xxx', 1: 'yyy', 3: 'zzz' };
Object.values(obj); // ['yyy', 'zzz', 'xxx']
Object.values('es8'); // ['e', 's', '8']


Object.valuesのブラウザサポート(MDN)

Object.entriesメソッドは、与えられたオブジェクト自身の列挙可能なプロパティ[key, value]ペアの配列をObject.valuesと同じ順序で返します。関数宣言は単純です。

const obj = { x: 'xxx', y: 1 };
Object.entries(obj); // [['x', 'xxx'], ['y', 1]]

const obj = ['e', 's', '8'];
Object.entries(obj); // [['0', 'e'], ['1', 's'], ['2', '8']]

const obj = { 10: 'xxx', 1: 'yyy', 3: 'zzz' };
Object.entries(obj); // [['1', 'yyy'], [’3’, 'zzz’], [’10’, 'xxx’]]
Object.entries('es8'); // [['0', 'e'], ['1', 's'], ['2', '8']]


Object.entriesのブラウザサポート(MDN)


Object.getOwnPropertyDescriptors

getOwnPropertyDescriptorsメソッドは、指定オブジェクト自身の全てのプロパティ記述子を返します。自身のプロパティ記述子はオブジェクト上で直接定義され、オブジェクトのプロトタイプからは継承されません。以下が関数宣言です。

Object.getOwnPropertyDescriptors(obj)

objはソースオブジェクトです。返される記述子オブジェクトのキーとなり得るのは、configurable、enumerable、writable、get、set、valueです。

const obj = { 
  get es7() { return 777; },
  get es8() { return 888; }
};
Object.getOwnPropertyDescriptors(obj);
// {
//   es7: {
//     configurable: true,
//     enumerable: true,
//     get: function es7(){}, //getter関数
//     set: undefined
//   },
//   es8: {
//     configurable: true,
//     enumerable: true,
//     get: function es8(){}, //getter関数
//     set: undefined
//   }
// }

記述子データは、デコレータのような高度な機能にとって非常に重要です。


ブラウザサポート(MDN)


関数パラメータリストと関数呼び出しにおける末尾のコンマ

関数パラメータの末尾のコンマとは、パラメータリストの末尾に不必要なコンマを付けても、コンパイラがエラー(SyntaxError)を起こさない仕様のことです。

function es8(var1, var2, var3,) {
  // ...
}

関数宣言と同様、これは関数呼び出しにも以下の形で適用されます。

es8(10, 20, 30,);

この仕様は、オブジェクトリテラルやArrayリテラルの末尾のコンマ、[10, 20, 30,]{ x: 1, }を参考にしたものです。


非同期関数

async function宣言は非同期関数を定義しますが、これはAsyncFunctionオブジェクトを返します。内部的には、非同期関数はジェネレータによく似た働きをしますが、ジェネレータ関数に変換されるわけではありません。

function fetchTextByPromise() {
  return new Promise(resolve => { 
    setTimeout(() => { 
      resolve("es8");
    }, 2000);
  });
}
async function sayHello() { 
  const externalFetchedText = await fetchTextByPromise();
  console.log(`Hello, ${externalFetchedText}`); // Hello, es8
}
sayHello();

sayHelloを呼び出すと、Hello, es8が2秒後にログに記録されます。

console.log(1);
sayHello();
console.log(2);

出力は以下のようになります。

1 // 即時
2 // 即時
Hello, es8 // 2秒後

こうなるのは、関数呼び出しがフローを妨げないからです。

async functionが常にpromiseを返し、awaitキーワードがasyncキーワードの付いた関数でしか使えないことに注意してください。


ブラウザサポート(MDN)


共有メモリとアトミック操作

メモリが共有されている場合、複数のスレッドがメモリ内の同じデータの読み取りと書き込みを行うことができます。アトミック操作では、予測可能な値が読み書きされること、操作は次の操作の始まる前に終わること、そして操作が割り込まれないことが保証されます。これに関して、新しいコンストラクタSharedArrayBufferと、静的メソッドの名前空間オブジェクトAtomicsが導入されました。

Atomicオブジェクトは、Mathのような静的メソッドのオブジェクトなので、コンストラクタとして使うことはできません。このオブジェクトにおける静的メソッドの例を以下に挙げます。

  • add / sub:特定位置の値に対して、値を加算または減算する
  • and / or / xor:ビット単位のand、ビット単位のor、ビット単位のxor
  • load:特定位置の値を取得する


ブラウザサポート(MDN)


来年のES9 に関して:テンプレートリテラルの制限撤廃

タグ付きテンプレートリテラル(ES6)を使うと、テンプレートをパースする関数を宣言し、ロジックに応じた値を返すといったことができます。

const esth = 8;
helper`ES ${esth} is `;
function helper(strs, ...keys) {
  const str1 = strs[0]; // ES
  const str2 = strs[1]; // is
  let additionalPart = '';
  if (keys[0] == 8) { // 8
    additionalPart = 'awesome';
  }
  else {
    additionalPart = 'good';
  }

  return `${str1} ${keys[0]} ${str2} ${additionalPart}.`;
}

戻り値は、「ES 8 is awesome.」となります。
esthを7にした場合の戻り値は、「ES 7 is good.」となります。

ただし、例えば\uや\xの部分文字列を含むテンプレートに対しては制限があります。このエスケープの問題は、ES9で対処されるでしょう。詳細はMDNのサイトTC39のドキュメントをご参照ください。


ブラウザサポート(MDN)


まとめ

JavaScriptは稼働中の言語ですが、常に更新されています。仕様に新機能を採用する過程は、手順も体制も非常に整っています。これらの機能は最後の段階で、TC39委員会が承認し、コア開発者が実装します。大部分はすでにTypeScript言語やブラウザ、ポリフィルの一部となっていますので、皆さんも今すぐ試してみることができます。