POSTD PRODUCED BY NIJIBOX

POSTD PRODUCED BY NIJIBOX

ニジボックスが運営する
エンジニアに向けた
キュレーションメディア

POSTD PRODUCED BY NIJIBOX

POSTD PRODUCED BY NIJIBOX

ニジボックスが運営する
エンジニアに向けた
キュレーションメディア

FeedlyRSSTwitterFacebook
Dor Moshe

本記事は、原著者の許諾のもとに翻訳・掲載しております。

EcmaScript仕様第8版の新機能


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

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

ES2017 (the 8th edition of the JavaScript Spec) was officially released and published yesterday! https://t.co/1ITn5bzaqj ????

— Kent C. Dodds (@kentcdodds) June 28, 2017

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言語やブラウザ、ポリフィルの一部となっていますので、皆さんも今すぐ試してみることができます。

監修者
監修者_古川陽介
古川陽介
株式会社リクルート プロダクト統括本部 プロダクト開発統括室 グループマネジャー 株式会社ニジボックス デベロップメント室 室長 Node.js 日本ユーザーグループ代表
複合機メーカー、ゲーム会社を経て、2016年に株式会社リクルートテクノロジーズ(現リクルート)入社。 現在はAPソリューショングループのマネジャーとしてアプリ基盤の改善や運用、各種開発支援ツールの開発、またテックリードとしてエンジニアチームの支援や育成までを担う。 2019年より株式会社ニジボックスを兼務し、室長としてエンジニア育成基盤の設計、技術指南も遂行。 Node.js 日本ユーザーグループの代表を務め、Node学園祭などを主宰。