ECMAScript 2017(ES8)の新機能

Netologiyaのプログラミング部門の上級大学院生および方法論者であるAlena Batitskayaは、ECMAScript 2017のリリースでJavaScriptに登場した革新をレビューしました。私たちは皆、これを長い間待っていました!



JavaScriptの歴史には停滞期と急速な成長期がありました。 言語が登場した瞬間(1995年)から2015年まで、更新された仕様は定期的にリリースされませんでした。

3年目は、更新をいつ待つかを正確に把握できてうれしいです。 2017年6月に、更新された仕様がリリースされました:ES8、またはより正確には、ES2017。 このバージョンの標準で言語でどのような更新が行われたかを一緒に見てみましょう。

非同期関数


おそらく、JavaScriptで最も期待されている革新の1つです。 これですべてが公式になりました。

構文


asyncキーワードは、非同期関数を作成するために使用されます。


async演算子


仕組みを見てみましょう。 単純な非同期関数を作成します。

 async function mainQuestion() { return 42; } 

mainQuestion関数は、 mainQuestionを返しますが、promiseを返します。

 const result = mainQuestion(); console.log(result instanceof Promise); // true 

ES2015のジェネレーターを既に使用している場合は、ジェネレーター関数がイテレーターを自動的に作成して返すことを覚えておいてください。 非同期関数では、まったく同じことが起こります。

そして、返された42番はどこにありますか? 彼らは私たちが返した約束を非常に明確に許可します:

 console.log(''); mainQuestion() .then(result => console.log(`: ${result}`)); console.log(''); 

Promisは非同期に解決するため、この出力をコンソールに取得します。

   : 42 

しかし、非同期関数が何も返さない場合はどうなりますか?

 async function dumbFunction() {} console.log(''); dumbFunction() .then(result => console.log(`: ${result}`)); console.log(''); 

約束は「なし」で解決されます。これは、JavaScriptではundefined型に対応します。

   : undefined 

名前にもかかわらず、非同期関数自体は同期的に呼び出され、実行されます。

 async function asyncLog(message) { console.log(message); } console.log(''); asyncLog(' '); console.log(''); 

コンソールへの出力は次のようになりますが、そうでなければ多くの人が期待するかもしれません:

     

非同期関数はプロミスを返します。 約束が何であるかをすでに理解していることを願っています。 それ以外の場合は、最初に対処することをお勧めします。

そして、関数本体でもpromiseを返すとどうなりますか?

 async function timeout(message, time = 0) { return new Promise(done => { setTimeout(() => done(message), time * 1000); }); } console.log(''); timeout(' 5 ', 5) .then(message => console.log(message)); console.log(''); 

thenメソッドに渡されるコールバック内でpromiseを返したかのように、自動的に作成されるそのpromiseにチェーンします。

    5  (_ 5 _) 

しかし、非同期関数ではなく通常の関数を作成した場合、すべてが上記の例とまったく同じように機能します。

 function timeout(message, time = 0) { return new Promise(done => { setTimeout(() => done(message), time * 1000); }); } 

次に、非同期関数は何のためにありますか? 非同期関数の最も優れた機能は、そのような関数の本体で、別の非同期関数の結果(promiseが解決されたとき)を待機する機能です。

 function rand(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } async function randomMessage() { const message = [ '', ' ?', '  ' ][rand(0, 2)]; return timeout(message, 5); } async function chat() { const message = await randomMessage(); console.log(message); } console.log(''); chat(); console.log(''); 

chat関数の本体は同期関数の本体のように見えることに注意してください。コールバック関数は1つもありません。 ただし、 await randomMessage()はpromiseを返しませんが、5秒待ってからメッセージ自体を返すため、promiseが許可されます。 これが彼の役割です:「正しいオペランドの結果を待つ」。

    ? 

メッセージchat機能の本体にメッセージが表示されるのを待たずに、 chat機能を呼び出した後がすぐに表示されます。 したがって、この部分を次のように書き換えることは論理的です。

 console.log(''); chat() .then(() => console.log('')); console.log('   '); 

ステートメントをawait
awaitは、コールバックなしでpromiseを美しく使用できる便利なものです。 ただし、非同期関数の本体でのみ機能します。 そのようなコードは構文エラーを生成します:

 console.log(''); await chat(); console.log(''); // SyntaxError: Unexpected token, expected ; 

非同期機能を「停止」できるという事実は、ジェネレーターとの別の類似点です。 非同期関数の本体でawaitキーワードを使用すると、 yieldと同様に、 next反復子メソッドへのnext呼び出しを「待機」するように、別の非同期関数の結果を待機( 期待どおりに変換)できます。

しかし、promiseを返す同期関数を「待機」するとどうなりますか? はい、できます:

 <source lang="javascript">function mainQuestion() { return new Promise(done => done(42)); } async function dumbAwait() { const number = await mainQuestion(); console.log(number); } dumbAwait(); // 42 

しかし、数値(文字列など)を返す同期関数を「期待」するとどうなりますか? はい、それも可能です。

 function mainQuestion() { return 42; } async function dumbAwait() { const number = await mainQuestion(); console.log(number); } dumbAwait(); // 42 

これにはあまり意味がありませんが、数字を「待つ」こともできます。

 async function dumbAwait() { const number = await 42; console.log(number); } dumbAwait(); // 42 

awaitステートメントは、何を期待しても違いはありません。 thenメソッドがコールバックする方法と同様に機能します。

  1. 約束が戻った場合:約束を待って、結果を返します。
  2. プロミスが返されない場合: Promise.resolveでラップし、同様にラップします。

awaitは、非同期関数を非同期floatに送信します。

 async function longTask() { console.log(''); await null; console.log(''); for (const i of Array (10E6)) {} return 42; } console.log(''); longTask() .then(() => console.log('')); console.log('   '); 

この例を、「便利な」トリックとしてではなく、 awaitデモとして取り上げてください。 以下の作業の結果:

         

エラー処理


しかし、 await 「期待する」約束await解決されない場合はどうでしょうか。 その後、 awaitは例外をスローします。

 async function failPromise() { return Promise.reject(''); } async function catchMe() { try { const result = await failPromise(); console.log(`: ${result}`); } catch (error) { console.error(error); } } catchMe(); //  

try-catchを使用するtry-catch 、他の例外と同様にこの例外をtry-catchして、何かを実行できます。

申込み


非同期関数の内部構造は、プロミスとジェネレーターの混合のようなものです。 実際、非同期関数は、言語のこれら2つのクールな機能を組み合わせるための構文糖衣です。 リンクされたコールバックの論理的な代替品です。

非同期関数の本体では、連続する非同期呼び出しをフラットな同期コードとして記録できます。これが私たちが待ち望んでいたものです。

 async function fetchAsync(url) { const response = await fetch(url); const data = await response.json(); return data; } async function getUserPublicMessages(login) { const profile = await fetchAsync(`/user/${login}`); const messages = await fetchAsync(`/user/${profile.id}/last`); return messages.filter(message => message.isPublic); } getUserPublicMessages('spiderman') .then(messages => show(messages)); 

promiseでこのコードを書き直してみて、読みやすさの違いを理解してください。

Nicholas Bevacuaの記事「 JavaScriptの非同期待ちについて 」では、非同期関数の原理と機能について非常に詳細に説明しています。 この記事には、コード例とユーザーケースが豊富に含まれています。

サポート


現在、非同期機能はすべての主要なブラウザをサポートしています 。 したがって、言語のこの機能をまだ適用していない場合は、安全に適用を開始できます。



Object.valuesおよびObject.entries


これらの新しい機能は、主にオブジェクトの操作を容易にするために設計されています。

Object.entries()


この関数は、オブジェクトの独自の列挙プロパティの配列を[key、value]の形式で返します。

オブジェクト構造にキーと値が含まれる場合、出力レコードは、2つの要素を持つ配列を含む配列に記録されます。最初の要素がキーになり、2番目の要素が値になります。 ペア[キー、値]は、オブジェクトのプロパティと同じ順序で配置されます。

 Object.entries({ : 1, : 2 }); 

コードの結果は次のようになります。

 [ [ '', 1 ], [ '', 2 ] ] 

Object.entries()渡されたデータ構造にキーが含まれていない場合、配列要素のインデックスはその場所に配置されます。

 Object.entries(['n', 'e', 't', 'o', 'l', 'o', 'g', 'y']); 

出力では次のようになります。

 [ [ '0', 'n' ], [ '1', 'e' ], [ '2', 't' ], [ '3', 'o' ], [ '4', 'l' ], [ '5', 'o' ], [ '6', 'g' ], [ '7', 'y' ] ] 

文字は無視されます


キーが文字であるプロパティは無視されることに注意してください。

 Object.entries({ [Symbol()]: 123, foo: 'bar' }); 

結果:

 [ [ 'foo', 'bar' ] ] 

プロパティの反復


Object.entries()関数の外観は、 for-ofループを使用しfor-ofオブジェクトのプロパティを反復処理する方法を最終的に提供します。

 let obj = { : 1, : 2 }; for (let [x,y] of Object.entries(obj)) { console.log(`${JSON.stringify(x)}: ${JSON.stringify(y)}`); } 

結論:

 "": 1 "": 2 

Object.values()


この関数はObject.entries()近いです。 出力では、キーなしで、独自のプロパティの値のみで構成される配列を取得します。 これは、原則として、名前から理解できます。

サポート





Object.entries()およびObject.values()現在、主要なブラウザーでサポートされています。

関数パラメーターの「ハング」コンマ


関数の引数リストの最後にカンマを残すことは現在有効です。 関数が呼び出されると、最後のコンマも犯罪の範囲外になります。

 function randomFunc( param1, param2, ) {} randomFunc( 'foo', 'bar', ); 

ぶら下げコンマも配列とオブジェクトで許可されています。 それらは単に無視され、作業には影響しません。

このような小さいながらも確かに有用な革新!

 let obj = { : '', : '', }; let arr = [ '', '', '', ]; 

サポート





パラメータリストの最後にカンマを残す前に、少し待つ必要があります。

文字列の「スタブ」:希望の長さに達する


ES8では、文字列を操作するための2つの新しいメソッドpadStart()padEnd()導入されました。 padStart()メソッドは、行の先頭の左側の追加文字を置き換えます。 そしてpadEnd()は、行の終わりの右側にあります。

 str.padStart(, []); str.padEnd(, []); 

最初のパラメーターで指定する長さに元の文字列が含まれることに注意してください。

2番目のパラメーターはオプションです。 指定しない場合、文字列にはスペースが埋め込まれます(デフォルト値)。

元の文字列が指定されたパラメータよりも長い場合、文字列は変更されません。

 ''.padStart(6, '~'); // '~~~~~' '  '.padStart(15, '-->'); // '-->  ' ''.padEnd(10); // ' ' ''.padEnd(10, '0123456789'); // '012345678' 

サポート





素晴らしい写真!

関数Object.getOwnPropertyDescriptors()


この関数は、オブジェクトのすべてのプロパティの記述子を含む配列を返します。

 const person = { first: '', last: '', get fullName() { return ` ,   ${first} ${last}`; }, }; console.log(Object.getOwnPropertyDescriptors(person)); 

結果:

 { first: { value: '', writable: true, enumerable: true, configurable: true }, last: { value: '', writable: true, enumerable: true, configurable: true }, fullName: { get: [Function: get fullName], set: undefined, enumerable: true, configurable: true } } 

応用分野


  1. ゲッター、セッター、書き換え不可能なプロパティなど、オブジェクトのプロパティをコピーするため。
  2. オブジェクトをコピーします。 .getOwnPropertyDescriptorは、 Object.create() 2番目のパラメーターとして使用できます。
  3. 特定のプロトタイプを使用したクロスプラットフォームオブジェクトリテラルの作成。

superを持つメソッドは、元のオブジェクトと密接に関連しているため、コピーできないことに注意してください。

サポート





IEでも問題ありません。

メモリ共有とAtomicsオブジェクト


この革新により、JavaScriptの共有メモリの概念が導入されました。 新しいSharedArrayBuffer設計と既存のTypedArrayおよびDataViewは、使用可能なメモリの割り当てに役立ちます。 これにより、複数のスレッド間で共有スレッドを使用しながら、必要な操作の順序が提供されます。

SharedArrayBufferオブジェクトは、高レベルの抽象化のためのプリミティブビルディングブロックです。 バッファを使用して、複数のワーカースレッド間でバイトを再分配できます。 これには2つの明確な利点があります。

  1. ワーカー間のデータ交換の速度が向上します。
  2. ワーカー間の調整がより速く簡単になります( postMessage()比べて)。

共有データへの安全なアクセス


新しいAtomicsオブジェクトはコンストラクターとして使用できませんが、型指定されたSharedArrayBuffer配列でさまざまな操作を実行する際のセキュリティ問題を解決するために設計された独自のメソッドが多数あります。

サポート





この「新しいこと」は、まだサポートが不十分です。 信じて、待ってください。
Alex Rauschmeierは、「 ESの提案:共有メモリとアトミック 」という記事で、この言語機能のメカニズムについて詳しく説明しました。

2017年にStackOverflowが実施した調査によると、JavaScriptは最も使用されているプログラミング言語です。 個人的に、私は現在の写真に非常に満足しています。


言語は生き、発達し、目の前でさらに便利で柔軟で強力なツールに変わります。

率直に言って、この急速な成長と研究に遅れずについていくことは常に可能ではなく、最も重要なことには、あなたの仕事で最新かつ最も関連性の高いものをすべて使用することです。 したがって、最も重要な情報を受け取り、労働市場に精通した最新の専門家を入力することは、初期開発中に非常に重要です。

Netologyの同僚と私は、オンライン教育の利点は、開発世界の絶えず変化する現実に適応する柔軟性と能力であることを理解しています。 このため、コースの資料の更新をやめることはせず、すべての新機能についてタイムリーに話します。 そのため、すべての学生がECMAScript 2017に登場したツールを使用する方法を知っており、知っているように、「 JavaScript:ゼロから約束まで 」コースを完成させています。

記事の作成では、次の資料が使用されました。

Source: https://habr.com/ru/post/J333604/


All Articles