ちょっと話題の記事

[2020年版] JavaScriptの便利な書き方まとめ

2020.05.01

先月、Node.jsバージョン14がリリースされたこともあり、改めて最新のJavaScriptの書き方を調べてみました。その中でも特に便利だと感じたJavaScriptの書き方や普段の開発でよく利用している記法をまとめています。

アロー関数式

アロー関数式は関数を定義するための構文です。function式よりもアロー関数式の方が記述が短いので読みやすくなります。また、function式で度々問題になるthisが固定されるので混乱を避けることができます。メソッドでない関数はアロー関数式で定義するのがよいと思います。

function式

function name(arg) {
  return 'foo';
}

アロー関数式

const name = (arg) => {
  return 'foo';
};

async/await

async/awaitは非同期処理の構文です。また、asyncは非同期関数を定義する関数定義になります。async/awaitを利用すると非同期処理を同期的に扱えるので、可読性が向上してコードが読みやすくなります。

const resolveAfter2Seconds = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('resolved');
    }, 2000);
  });
};

const asyncCall = async () => {
  const result = await resolveAfter2Seconds();
  console.log(result);
};

asyncCall();

Promise.all

Promise.allは引数に指定した全てのPromiseを実行します。Promiseが1つでも失敗した場合は、その時点で処理を終了してエラーを返します。

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise(resolve => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then(values => {
  console.log(values); // [3, 42, 'foo']
});

配列操作のmapメソッドと組み合わせて使用することも多いです。

const promise = val => Promise.resolve(val);

const promises = [1, 2, 3].map(val => promise(val));

Promise.all(promises).then(values => {
  console.log(values); // [1, 2, 3]
});

Promiseで失敗が発生しても処理を継続させる場合は、Promise.allの代わりにPromise.allSettledを使用します。一部のブラウザでは非対応でNode.jsはバージョン12以降から対応になりますので、外部ライブラリの導入も検討することになります。

配列操作

ES5以降に使えるようになった便利な配列操作のメソッドを紹介します。配列の組み込みメソッド一覧は次のページに記載されています。

forEach

forEachは配列の各値に対して1度だけ処理を実行します。ただ、forEachはコールバックを持たないため、非同期関数で使用するとforEachの処理を待たずに次の処理が実行される点に注意が必要です。

['a', 'b', 'c'].forEach(val => {
  console.log(val); // a, b, c
});

filter

filterは配列から条件に合う値のみを取り出して、新しい配列を作成します。

const result = ['spray', 'elite', 'destruction', 'present'].filter(
  word => word.length > 6,
);

console.log(result); // ['destruction', 'present']

map

mapは配列の値に変更を加えて、新しい配列を作成します。

const array = [1, 4, 9, 16].map(x => x * 2);

console.log(array); // [2, 8, 18, 32]

reduce

reduceは配列を処理して、1つの値を取得します。第2引数に初期値を渡すことができます。

const val = [1, 2, 3, 4].reduce(
  // 10 + 1 + 2 + 3 + 4
  (accumulator, currentValue) => accumulator + currentValue,
  10,
);

console.log(val); // 20

flat

flatは全てのサブ配列の要素を、指定した深さで再帰的に結合した新しい配列を作成します。IEは非対応でNode.jsはバージョン11から利用可能です。

const flat = [[1, 2], [3, 4]].flat();

console.log(flat); // [1, 2, 3, 4]

以前まではreduceconcatを組み合わせて実装していました。

const flat = [[1, 2], [3, 4]].reduce((acc, val) => acc.concat(val), []);

console.log(flat); // [1, 2, 3, 4]

変数宣言

JavaScriptの変数宣言ではvar,let,constが使えます。constで変数を宣言した場合、変数に対して値の再代入ができなくなります。これにより、値の変更を意識する必要がなくなるので、コードが読みやすくなります。可能な限り変数宣言ではconstを利用するのがよいと思います。

条件分岐で値を変更したい場合にletを使いたくなりますが、三項演算子や関数で書くとconstで宣言することができます。

let name;

if (1 === 1) {
  name = 'orange';
} else {
  name = 'apple';
}

console.log(name); // orange

三項演算子

const name = 1 === 1 ? 'orange' : 'apple';

console.log(name); // orange

即時関数

const name = (() => {
  if (1 === 1) {
    return 'orange';
  } else {
    return 'apple';
  }
})();

console.log(name); // orange

テンプレート文字列

テンプレート文字列(テンプレートリテラル)は文字列を扱う構文です。バッククォートで文字列を囲み、変数を代入することもできます。

const fruit = 'りんご';

const name = `美味しい${fruit}`;

console.log(name); // 美味しいりんご

ヒアドキュメントのように使うこともできます。

const text = `1行目
2行目
3行目`;

スプレッド構文

スプレッド構文は配列の中で配列を展開します。

const array = ['apple', 'orange'];
const array2 = ['banana', ...array];

console.log(array2); // ['banana', 'apple', 'orange']

数を指定して配列を作成したい場合、次のような書き方もできます。

const promise = Promise.resolve('foo');

const promises = [...Array(3)].map(() => promise);

Promise.all(promises).then(values => {
  console.log(values); // ['foo', 'foo', 'foo']
});

分割代入構文

分割代入構文は、配列やオブジェクトからプロパティを取り出して、変数に代入します。

const people = ['高橋雄大', 26, 174, 63];

const [name, age, height, weight] = people;

Null合体演算子

Null合体演算子は、左辺がnullまたはundefinedの場合に右の値を返し、それ以外の場合に左の値を返します。Node.jsではバージョン14から対応になります。

const foo = null ?? 'default string';

console.log(foo); // default string

クロージャ

クロージャは関数を作るための環境を持つ関数です。変数を関数に閉じ込めることで、変数のスコープを制限します。これにより、変数がどこからでも参照できるわけではなくなるので、変数を安全に扱うことができます。また、変数の安全性を確認するために、全てのコードを見る必要もなくなるので、コードの可読性も向上します。

const makeCounter = () => {
  let cnt = 1;

  const counter = num => {
    cnt += num;

    return cnt;
  };

  return counter;
};

const counter = makeCounter();

console.log(counter(1)); // 2

まとめ

JavaScriptは次々に新しい機能が実装されて使いやすくなってきています。Node.jsについても可能であれば最新バージョンを使用して、JavaScriptの新機能を活用していきたいと思います。

今更ですがTwitterアカウント作りました!@_takahashiyudai

他にも便利な記法がありましたら、教えていただけると嬉しいです。

参考資料