- イマドキJavaScriptの機能や書き方とは?
- 最近のJavaScriptの使い方とは?
本記事ではこのような疑問を解決します。
Web開発になくてはならないプログラミング言語がJavaScriptです。
そんなJavaScriptは、2015年に発表されたECMAScript(JavaScriptの母体規格)の大幅なバージョンアップによって機能や書き方などが更なる進化を遂げました。
この2015年がJavaScriptの大きな転換期となり、今に至るまで毎年バージョンアップが重ねられています。
そして、現在のWeb開発で使われるJavaScriptの機能や書き方は、”イマドキJavaScript”や”モダンJavaScript”とよく呼ばれます。
そこで今回はイマドキJavaScriptの機能や書き方についてご紹介します。
変数宣言(letとconst)
JavaScriptの変数宣言にはvar、let、constの3つを使用することができます。
今まで使われていたvarに、letとconstが新たに登場したため、いわばvarは”旧式”、letとconstは”新式”であると言えるでしょう。
3つそれぞれの特徴は以下の通りです。
○var
・スコープ(コードの中でその変数が利用できる範囲)は関数ごと
・再宣言は可能
・再代入は可能
・ミュータブル(変数の型は変更可能)である
・変数代入前に読み込みor書き込みをしようとしてもエラーは発生しない
○let
・スコープはブロックごと
・再宣言は不可能
・再代入は可能
・ミュータブルである
・変数代入前に読み込みor書き込みをしようとするとエラーが発生する
○const
・スコープはブロックごと
・再宣言は不可能
・再代入は不可能
・ミュータブルである
・変数代入前に読み込みor書き込みをしようとするとエラーが発生する
なお、イマドキJavaScriptでは、”旧式”のvarを使用せず、”新式”のletとconstを使用します。
文字列の変数展開(テンプレートリテラル)
文字列の中で変数を展開する時は、テンプレートリテラルを使って変数や式などを展開できます。
このテンプレートリテラルとは文字列を“(バッククオート)で囲んだものです。
そして、そのテンプレートリテラルの中で「${変数}」といった書き方をして変数を展開します。
なお、テンプレートリテラルを用いると改行も反映させることができます。
従来の方法と比較しながら実際にコードを確認してみましょう。
// 従来の変数展開
name = "こうすけ"
console.log("私の名前は" + name + "です。");
// => 私の名前はこうすけです。
// テンプレートリテラル用いた変数展開(改行も反映)
name = "こうすけ"
console.log(`私の名前は
${name}です。`);
// => 私の名前は
こうすけです。
アロー関数
JavaScriptの関数定義では、ノーマル関数、無名関数、アロー関数の3つを使用することができます。
今ではノーマル関数と無名関数に代わって、メリットのあるアロー関数が多く使われています。
ノーマル関数、無名関数、アロー関数それぞれを比較して確認しましょう。
※アロー関数のメリットは後述
○引数なしパターン
// ノーマル関数
function myFunc() {
/* 処理 */
}
// 無名関数
const myFunc = function() {
/* 処理 */
}
// アロー関数
const myFunc = () => {
/* 処理 */
}
○引数ありパターン
// ノーマル関数
function myFunc(value) {
/* 処理 */
}
// 無名関数
const myFunc = function(value) {
/* 処理 */
}
// アロー関数
const myFunc = value => {
/* 処理 */
}
// 引数が2つの場合・・・(value1, value2)
最後にアロー関数のメリットを確認しましょう。
・コードの簡潔さ
→短く記述できる
・関数が定義されたスコープ内のthisを参照する
→実行環境に影響されない記述ができる
スプレッド構文
スプレッド構文(…)は反復可能オブジェクト(配列やリストなど)を展開してくれるものです。
言葉だと説明しづらいので、実際にコードを確認してみましょう。
// 配列のコピー
const arr1 = ["a", "b", "c"];
const arr2 = [...arr1];
console.log(arr2);
// => ['a', 'b', 'c']
// 配列の結合
const arr3 = ["a", "b", "c"];
const arr4 = [...arr3, "d", "e", "f"];
console.log(arr4);
// => ['a', 'b', 'c', 'd', 'e', 'f']
分割代入
分割代入は配列やオブジェクトを一部分だけ受け取るために使うものです。
メリットとしては、余計な変数を定義せずに済むという点が挙げられます。
こちらも実際にコードを確認してみましょう。
// 例①
const [a, b, c, d] = [1, 2, {num: 3}, 4];
console.log(a, b, c, d);
// => 1 2 {num: 3} 4
// 例②
const nums = {a: 1, b: 2, c: {num: 3}};
const {a, b, c, c: {num}} = nums;
console.log(a, b, c, num);
// => 1 2 {num: 3} 3
// 例③
const item = {
name: 'Banana',
color: 'Yellow'
};
const {name, color} = item;
console.log(name);
// => Banana
console.log(color);
// => Yellow
// 例④
const myCapital = ({country, capital}) => {
return country + ' : ' + capital;
}
console.log(myCapital({country: 'Japan', capital: 'Tokyo'}));
// => Japan : Tokyo
配列の処理(mapとfilter)
map、filter、reduceの2つのメソッドを使うことで配列の処理を簡潔に記述することができます。
今までは配列の処理にはforやforEachが使われていました。
しかし、map、filterの2つのメソッドを使うことでforやforEachを代替することができます。
それではmap、filterの2つのメソッドを簡単に説明していきます。
○mapメソッド
mapメソッドは配列を受け取り、各要素に対して何かしらの処理をして、変更された要素を持つ配列を返します。
例えば以下の通りです。(1~5の配列を2倍にして返す例)
const array1 = [1, 2, 3, 4, 5];
const array2 = array1.map(num => num * 2);
console.log(array2);
// 処理結果
// [2, 4, 6, 8, 10]
○filterメソッド
filterメソッドは配列を受け取り、要素ごとに保持するかどうかを決めて、保持する要素のみからなる配列を返します。
例えば以下の通りです。(メンバーリストから住所が「テキサス」の者を抽出する例)
const member_list = [
{ id: "001", name: "Allison", address: "Texas" },
{ id: "002", name: "Shelly", address: "New York" },
{ id: "003", name: "Jessica", address: "Okurahoma" },
{ id: "004", name: "Sonny", address: "Texas" },
];
const member_Texas = member_list.filter(data => data.address === "Texas");
console.log(member_Texas);
// 処理結果
// {id: '001', name: 'Allison', address: 'Texas'} {id: '004', name: 'Sonny', address: 'Texas'}
非同期処理の結果(Promise)
以前にも非同期処理の書き方はいくつかありましたが、Promiseの登場によって格段に便利になりました。
Promise自体の説明は後でするとして、
Promise登場以前の非同期処理では、
リクエストされたリソースが何らかの理由で利用不可の場合にレスポンスが返ってこない、
コードが複雑で可読性が下がる、などの問題点がありました。
しかし、Promiseの登場により、以下のようなメリットが生まれました。
・レスポンス状況が明確になった
・コードの可読性が上がった
・非同期処理に関するあらゆる操作が可能になった
それでは、Promise自体の説明に入っていきます。
そもそもPromiseとは何かというと、非同期処理の完了 (もしくは失敗)の結果や値を表すものです。
Promiseは以下のような3つの状態を持ちます。
・pending:非同期処理が成功も失敗もしていない状態を表す(初期状態)
・fulfilled:非同期処理が成功して完了した状態を表す
・rejected:非同期処理が失敗した状態を表す
この初期状態である「pending」から、
処理が成功して完了したら「fulfilled」、処理が失敗したら「rejected」になります。
わかりやすく例えると、Promiseは宝くじみたいなものです。
宝くじを買った時はそれがアタリなのかハズレなのかわかりません。
つまり、pendingの状態です。
そして、当選発表の時にアタリ(fulfilled)かハズレ(rejected)かの結果が明らかになり、買った宝くじを引換券として景品(処理結果)を受け取ります。
ではPromiseの基本構文を確認しましょう。
new Promise(function(resolve, reject) {
resolve()
})
Promiseの引数には関数を渡し、その関数の第一引数にresolveメソッド、第二引数にrejectメソッドを記述します。
※第二引数のrejectメソッドはなくてもOK
その処理の中でresolve()が実行されるとfulfilledになり、reject()が実行されるとrejectedになります。
つまり、”resolve”すると「処理が成功して完了したよ!」状態になり、
”reject”すると「処理が失敗したよ!」状態になるということです。
そして、Promiseでは結果(処理が成功したか失敗したか)が出た時に実行する処理(関数)を登録しておくことができます。
処理が成功したか失敗したかによって、以下のどちらかのメソッドが呼ばれます。
・then():非同期処理が成功して完了した際に呼ばれるメソッド
・catch():非同期処理が失敗した際に呼ばれるメソッド
new Promise(function(resolve, reject) {
console.log("promise!");
resolve("Hello!");
}).then(function(data) {
console.log("1回目の" + data);
return data;
}).then(function(data) {
console.log("2回目の" + data);
}).catch(function(data) {
console.log("fail!");
});
// 処理結果
promise!
1回目のHello!
2回目のHello!
thenメソッド内では直前で行われた処理の結果(値)が渡されます。
なお、thenメソッドが2つ以上連なっている(thenチェーン)場合、
エラーが起きたらその後のthenチェーンをすっ飛ばして、catchメソッドに処理が移ります。
非同期処理の記述簡略化(async await)
async awaitは非同期処理の記述を簡略化するために登場しました。
仕組み自体は上で説明したPromiseと同じです。
それでは実際にコードを確認してみましょう。
function sampleFunc1(value) {
return new Promise(resolve => {
setTimeout(() => {
resolve(value);
}, 2000);
})
}
// sampleFunc1()をawaitしているため、Promiseの結果が返されるまで処理が一時停止される
// 2秒後にresolve(10)が返ってきて、その後の処理(return result + 10;)が再開される
async function sampleFunc2() {
const result = await sampleFunc1(10);
return result + 10;
}
sampleFunc2().then(result => {
console.log(result);
});
// => 20
※async関数はPromiseを返し、awaitはPromiseの結果(resolve、reject)が返されるまで待機する。
まとめ
以上がイマドキJavaScriptの機能や書き方になります。
JavaScriptには、jQueryをはじめ様々なライブラリがありますが、それらを利用しなくても素のJavaScriptで十分簡潔に記述できる場面が増えました。
ぜひイマドキJavaScriptの機能や書き方を学んで活かしてみてください。