JavaScriptは近年大きく変化しました。 本日から使用を開始できる12の新機能をご紹介します!
物語
この言語に新しく追加されたものは、ECMAScript 6と呼ばれます。ES6またはES2015 +のいずれかです。
1995年の導入以来、JavaScriptはゆっくりと進化しています。 新しい機能は数年ごとに追加されます。 ECMAScriptは1997年に登場し、その目標はJavaScriptの開発を正しい方向に導くことでした。 ES3、ES5、ES6などの新しいバージョンが登場しました。
ご覧のとおり、ES3、ES5、およびES6のバージョン間には10年と6年のギャップがあります。 新しいモデルは、毎年小さな変更を加えることです。 ES6の場合のように、大量の変更を蓄積して一度にすべてをリリースする代わりに。
ブラウザのサポート
最新のブラウザとランタイムはすべて、すでにES6をサポートしています!
Chrome、MS Edge、Firefox、Safari、Node、および他の多くのシステムには、ほとんどのJavaScript ES6機能のサポートが組み込まれています。 したがって、このマニュアルはすべて今すぐ使用できます。
行こう!
ES6の主な機能
すべてのスニペットをブラウザコンソールに挿入して実行できます。
ブロックスコープ変数
ES6では、 var
からlet
/ const
切り替えました。
var
何が問題になっていますか?
var
問題は、変数がfor
ループやif
ブロックなどの他のコードブロックに漏れることです。
ES5 var x = 'outer'; function test(inner) { if (inner) { var x = 'inner'; // scope whole function return x; } return x; // gets redefined on line 4 } test(false); // undefined test(true); // inner
ラインtest(false)
outer
が戻ることを期待できますが、いいえ、 undefined
ます。 なんで?
if
ブロックif
実行されていなくても、4行目でvar x
がundefined
として再定義されているためです。
ES6による救助:
ES6 let x = 'outer'; function test(inner) { if (inner) { let x = 'inner'; return x; } return x; // gets result from line 1 as expected } test(false); // outer test(true); // inner
var
を変更して、動作を調整できるようにしました。 if
ブロックif
呼び出されないif
、 x
変数はオーバーライドされません。
IIFE(すぐに呼び出される関数式)
最初に例を見てみましょう。
ES5 { var private = 1; } console.log(private); // 1
ご覧のとおり、 private
が漏れています。 IIFE(即時に呼び出される関数式)を使用する必要があります。
ES5 (function(){ var private2 = 1; })(); console.log(private2); // Uncaught ReferenceError
jQuery / lodashまたは他のオープンソースプロジェクトを見ると、IIFEがグローバル環境をクリーンに保つために使用されていることがわかります。 また、グローバルなものは、 _
、 $
、 jQuery
などの特殊文字で定義されます。
ES6では、IIFEを使用する必要はありません。ブロックを使用してlet
:
ES6 { let private3 = 1; } console.log(private3); // Uncaught ReferenceError
定数
変数を変更しない場合は、 const
使用することもできます。
結果:
-
var
忘れて、let
とconst
使用します。 - すべての参照に
const
を使用します。var
使用しないでください。 - 参照を再定義する必要がある場合は、
const
代わりにlet
を使用します。
テンプレートリテラル
ネストされた連結を行う必要がなくなり、テンプレートを使用できます。 ご覧ください:
ES5 var first = 'Adrian'; var last = 'Mejia'; console.log('Your name is ' + first + ' ' + last + '.');
バックティック( )
を使用して)
$ {} ` )
、これを行うことができます。
ES6 const first = 'Adrian'; const last = 'Mejia'; console.log(`Your name is ${first} ${last}.`);
複数行の文字列
文字列を+ \n
連結する必要はもうありません。
ES5 var template = '<li *ngFor="let todo of todos" [ngClass]="{completed: todo.isDone}" >\n' + ' <div class="view">\n' + ' <input class="toggle" type="checkbox" [checked]="todo.isDone">\n' + ' <label></label>\n' + ' <button class="destroy"></button>\n' + ' </div>\n' + ' <input class="edit" value="">\n' + '</li>'; console.log(template);
ES6では、backticsを再び使用できます。
ES6 const template = `<li *ngFor="let todo of todos" [ngClass]="{completed: todo.isDone}" > <div class="view"> <input class="toggle" type="checkbox" [checked]="todo.isDone"> <label></label> <button class="destroy"></button> </div> <input class="edit" value=""> </li>`; console.log(template);
コードの両方のブロックは同じ結果を生成します。
破壊の割り当て
ES6の破壊は便利で簡潔なものです。 例を見てください:
配列から要素を取得する
ES5 var array = [1, 2, 3, 4]; var first = array[0]; var third = array[2]; console.log(first, third); // 1 3
同じこと:
ES6 const array = [1, 2, 3, 4]; const [first, ,third] = array; console.log(first, third); // 1 3
価値の交換
ES5 var a = 1; var b = 2; var tmp = a; a = b; b = tmp; console.log(a, b); // 2 1
同じこと:
ES6 let a = 1; let b = 2; [a, b] = [b, a]; console.log(a, b); // 2 1
複数の戻り値の再構築
ES5 function margin() { var left=1, right=2, top=3, bottom=4; return { left: left, right: right, top: top, bottom: bottom }; } var data = margin(); var left = data.left; var bottom = data.bottom; console.log(left, bottom); // 1 4
3行目では、配列として返すことができます。
return [left, right, top, bottom];
ただし、呼び出し元のコードはデータの順序を知る必要があります。
var left = data[0]; var bottom = data[3];
ES6では、呼び出し元は必要なデータのみを選択します(6行目):
ES6 function margin() { const left=1, right=2, top=3, bottom=4; return { left, right, top, bottom }; } const { left, bottom } = margin(); console.log(left, bottom); // 1 4
注:行3には、他のES6機能が含まれています。 { left: left }
を{ left }
短縮できます。 ES5バージョンと比較した簡潔さをご覧ください。 かっこいい?
構造化とパラメーターのマッピング
ES5 var user = {firstName: 'Adrian', lastName: 'Mejia'}; function getFullName(user) { var firstName = user.firstName; var lastName = user.lastName; return firstName + ' ' + lastName; } console.log(getFullName(user)); // Adrian Mejia
同じこと(ただし短い):
ES6 const user = {firstName: 'Adrian', lastName: 'Mejia'}; function getFullName({ firstName, lastName }) { return `${firstName} ${lastName}`; } console.log(getFullName(user)); // Adrian Mejia
深いマッチング
ES5 function settings() { return { display: { color: 'red' }, keyboard: { layout: 'querty'} }; } var tmp = settings(); var displayColor = tmp.display.color; var keyboardLayout = tmp.keyboard.layout; console.log(displayColor, keyboardLayout); // red querty
同じこと(ただし短い):
ES6 function settings() { return { display: { color: 'red' }, keyboard: { layout: 'querty'} }; } const { display: { color: displayColor }, keyboard: { layout: keyboardLayout }} = settings(); console.log(displayColor, keyboardLayout); // red querty
これは、オブジェクトの破壊とも呼ばれます。
ご覧のとおり、再構築は非常に便利であり、コーディングスタイルの改善につながる可能性があります。
ヒント:
- 構造化を使用して、配列から要素を取得し、値を交換します。 一時的な参照を行う必要はありません-時間を節約します。
- 複数の戻り値に対して配列の破壊を使用せず、代わりにオブジェクトの破壊を使用してください。
クラスとオブジェクト
ECMAScript 6では、「コンストラクター関数」から「クラス」に移行しました。
JavaScriptの各オブジェクトには、異なるオブジェクトであるプロトタイプがあります。 JavaScriptのすべてのオブジェクトは、プロトタイプからメソッドとプロパティを継承します。
ES5では、コンストラクター関数を使用してオブジェクト指向プログラミングが実現されました。 彼らは次のようにオブジェクトを作成しました:
ES5 var Animal = (function () { function MyConstructor(name) { this.name = name; } MyConstructor.prototype.speak = function speak() { console.log(this.name + ' makes a noise.'); }; return MyConstructor; })(); var animal = new Animal('animal'); animal.speak(); // animal makes a noise.
ES6には新しい構文糖衣があります。 同じことを、より小さなコードで、 class
およびconstrutor
を使用して行うことができます。 また、メソッドが明確に定義されていることに注目してください: construtor.prototype.speak = function ()
vs speak()
:
ES6 class Animal { constructor(name) { this.name = name; } speak() { console.log(this.name + ' makes a noise.'); } } const animal = new Animal('animal'); animal.speak(); // animal makes a noise.
どちらのスタイル(ES5 / 6)も同じ結果になります。
ヒント:
- 常に
class
構文を使用し、prototype
直接変更しないでください。 コードはより簡潔で理解しやすくなります。 - 空のコンストラクターを作成しないでください。 独自のクラスを設定しない場合、クラスにはデフォルトのコンストラクタがあります。
継承
Animal
クラスで前の例を続けましょう。 新しいLion
クラスが必要だとしましょう。
ES5は、プロトタイプの継承で少し動作する必要があります。
ES5 var Lion = (function () { function MyConstructor(name){ Animal.call(this, name); } // prototypal inheritance MyConstructor.prototype = Object.create(Animal.prototype); MyConstructor.prototype.constructor = Animal; MyConstructor.prototype.speak = function speak() { Animal.prototype.speak.call(this); console.log(this.name + ' roars '); }; return MyConstructor; })(); var lion = new Lion('Simba'); lion.speak(); // Simba makes a noise. // Simba roars.
詳細には触れませんが、いくつかの詳細に注意してください。
- 3行目は、パラメーターを指定して
Animal
コンストラクターを直接呼び出します。 - 7〜8行目では、
Lion
プロトタイプをAnimal
クラスのプロトタイプに割り当てています。 - 行11、親クラス
Animal
からspeak
メソッドを呼び出します。
ES6には新しいextends
キーワードとsuper
キーワードがあります。
ES6 class Lion extends Animal { speak() { super.speak(); console.log(this.name + ' roars '); } } const lion = new Lion('Simba'); lion.speak(); // Simba makes a noise. // Simba roars.
ES5に比べてES6でのコードの見栄えを確認してください。 そして、彼らは同じことをします! 勝つ!
ヒント:
- 組み込みの継承メソッド-extendsを使用し
extends
。
ネイティブの約束
コールバック地獄からプロミスへ
ES5 function printAfterTimeout(string, timeout, done){ setTimeout(function(){ done(string); }, timeout); } printAfterTimeout('Hello ', 2e3, function(result){ console.log(result); // nested callback printAfterTimeout(result + 'Reader', 2e3, function(result){ console.log(result); }); });
1つの関数はコールバックを受け入れて、完了時にコールバックを開始します。 次々に2回実行する必要があります。 したがって、コールバックでprintAfterTimeout
を呼び出す必要があります。
3番目または4番目のコールバックを追加する必要がある場合、すべてが非常に悪くなります。 約束で何ができるか見てみましょう:
ES6 function printAfterTimeout(string, timeout){ return new Promise((resolve, reject) => { setTimeout(function(){ resolve(string); }, timeout); }); } printAfterTimeout('Hello ', 2e3).then((result) => { console.log(result); return printAfterTimeout(result + 'Reader', 2e3); }).then((result) => { console.log(result); });
そうすれば、ネストされた関数なしthen
実行できます。
矢印関数
ES5では、通常の関数定義は消えませんでしたが、新しい形式が追加されました-矢印関数。
ES5にはthis
に関する問題があります。
ES5 var _this = this; // need to hold a reference $('.btn').click(function(event){ _this.sendData(); // reference outer this }); $('.input').on('change',function(event){ this.sendData(); // reference outer this }.bind(this)); // bind to outer this
関数内で一時的なthis
を参照するか、 bind
使用bind
必要があります。 ES6では、矢印機能を使用できます!
ES6 // this will reference the outer one $('.btn').click((event) => this.sendData()); // implicit returns const ids = [291, 288, 984]; const messages = ids.map(value => `ID is ${value}`);
〜の
for
からforEach
for
移動し、次にfor...of
移動for...of
。
ES5 // for var array = ['a', 'b', 'c', 'd']; for (var i = 0; i < array.length; i++) { var element = array[i]; console.log(element); } // forEach array.forEach(function (element) { console.log(element); });
ES6 for ...では、イテレータを使用できます
ES6 // for ...of const array = ['a', 'b', 'c', 'd']; for (const element of array) { console.log(element); }
デフォルトのオプション
パラメーターの確認から、デフォルト設定に進みます。 以前にこのようなことをしたことがありますか?
ES5 function point(x, y, isFlag){ x = x || 0; y = y || -1; isFlag = isFlag || true; console.log(x,y, isFlag); } point(0, 0) // 0 -1 true point(0, 0, false) // 0 -1 true point(1) // 1 -1 true point() // 0 -1 true
おそらくそうです。 これは、変数値の存在を確認するための一般的なパターンです。 しかし、いくつかの問題があります。
- 行8、パス
0, 0
取得0, -1
- 9行目は
false
渡しfalse
が、true
取得しtrue
。
デフォルトのパラメーターがブール変数の場合、または値を0に設定した場合、何も機能しません。 なんで? この例の後、ES6で説明します;)
ES6では、より少ないコードですべてがより良く機能します。
ES6 function point(x = 0, y = -1, isFlag = true){ console.log(x,y, isFlag); } point(0, 0) // 0 0 true point(0, 0, false) // 0 0 false point(1) // 1 -1 true point() // 0 -1 true
期待どおりの結果が得られます。 ES5の例は機能しませんでした。 false
、 null
、 undefined
および0
はすべて偽の値であるため、 undefined
をチェックする必要があります。 数字を使用すると、これを行うことができます。
ES5 function point(x, y, isFlag){ x = x || 0; y = typeof(y) === 'undefined' ? -1 : y; isFlag = typeof(isFlag) === 'undefined' ? true : isFlag; console.log(x,y, isFlag); } point(0, 0) // 0 0 true point(0, 0, false) // 0 0 false point(1) // 1 -1 true point() // 0 -1 true
undefined
チェックでは、すべてが正常に機能します。
残りのパラメーター
引数から残りのパラメーターおよびスプレッド操作まで。
ES5では、可変数の引数を扱うのは不便です。
ES5 function printf(format) { var params = [].slice.call(arguments, 1); console.log('params: ', params); console.log('format: ', format); } printf('%s %d %.2f', 'adrian', 321, Math.PI);
休むと...
すべてがはるかに簡単です。
ES6 function printf(format, ...params) { console.log('params: ', params); console.log('format: ', format); } printf('%s %d %.2f', 'adrian', 321, Math.PI);
操作の広がり
apply()
からspreadに渡されapply()
。 繰り返し...
が、救助に急いで:
要確認:apply()
を使用して、配列を引数のリストに変換します。 たとえば、Math.max()
はパラメーターのリストを受け取りますが、配列がある場合はapply
を使用apply
。
ES5 Math.max.apply(Math, [2,100,1,6,43]) // 100
ES6では、スプレッドを使用します。
ES6 Math.max(...[2,100,1,6,43]) // 100
また、 concat
からspreadに移行しました。
ES5 var array1 = [2,100,1,6,43]; var array2 = ['a', 'b', 'c', 'd']; var array3 = [false, true, null, undefined]; console.log(array1.concat(array2, array3));
ES6の場合:
ES6 const array1 = [2,100,1,6,43]; const array2 = ['a', 'b', 'c', 'd']; const array3 = [false, true, null, undefined]; console.log([...array1, ...array2, ...array3]);
おわりに
JavaScriptは大きく変わりました。 この記事では、すべての開発者が知っておくべき基本的な機能のみを扱います。