2015年6月にECMAScript 2015がリリースされて以降、JavaScriptの機能は大きく強化されました。const/let、アロー関数、クラス構文、Promiseなどが有名なところですが、ES2016、ES2017、ES2018、そして更にその先へJavaScriptの仕様は日々進化しています。筆者はここ数年JavaScript(主にTypeScript)の開発を進めていますが、これまで当たり前だと思っていた手法を新しい新機能で置き換えることが何度もありました。

本記事では、2017から2018年に向けて筆者が見直したJavaScriptのプログラミング手法について紹介します。記事の末尾にブラウザ対応の手法もまとめていますので、あわせてご覧ください。

☞︎配列要素の存在チェックにはincludes()メソッド

配列内に特定の要素があるかどうかを調べる場合、従来は次のようにindexOf()メソッドを使っていました。

// 対象の配列
var targetArray = ["鈴木", "田中", "高橋"];
 
// 田中が存在するかどうか
if (targetArray.indexOf("田中") >= 0) {
  console.log("田中が含まれています");
} else {
  console.log("田中は存在しません");
}

ES2017で追加された配列のためのincludes()メソッドを使うと、インデックスではなく真偽値を使って配列内の要素の存在チェックが可能になります。

// 対象の配列
const targetArray = ["鈴木", "田中", "高橋"];
 
// 田中が存在するかどうか
if (targetArray.includes("田中")) {
  console.log("田中が含まれています");
} else {
  console.log("田中は存在しません");
}

ちなみにES2015では文字列の存在チェックのためのincludes()メソッドが追加されており、こちらもindexOf()と代わって使用しています。

// 対象の文字列
const targetUserAgent = navigator.userAgent;
 
// ES 5以下
// if (targetUserAgent.indexOf("iOS") >= 0) {
//   console.log("iOSブラウザです");
// }
 
// ES2015以上
if (targetUserAgent.includes("iOS")) {
   console.log("iOSブラウザです");
}

筆者のQiita記事「配列内の要素の存在確認にはArray.includes()メソッドが便利」もあわせて参照ください。

☞︎ゼロパディングにはpadStart()メソッド

時計の秒数表示など、一桁の数字の頭に0をつけて文字列にしたい場合、従来は次のようなコードを書いていました。

// 現在時刻の秒数を取得
var second = new Date().getSeconds();
 
// 0パディングされた文字列
var paddedSecond = String(second);
 
// 10分未満なら、冒頭に0を付与する
if (second < 10) {
  paddedSecond = "0" + paddedSecond;
}
 
// 現時刻の秒数 01, 09, 12, ...
console.log(paddedSecond);

ES2017では、文字詰めのためのpadStart()メソッドが追加されました。次のように指定することで、「文字列」が指定の「長さ」になるように、「詰める文字」を文字列の前に配置します。

文字列.padStart(長さ, 詰める文字)

先ほどのコードは次のように短く書けます。

// 現在時刻の秒数を取得
const second = new Date().getMinutes();
 
// 2桁の文字列になるよう文字詰め
const paddedSecond = String(second).padStart(2, "0");
 
// 現時刻の秒数 01, 09, 12, ...
console.log(paddedSecond);

☞︎Promiseを使うならasync/awaitをセットに

ES2015で非同期処理のために導入されたPromiseですが、Promiseの処理を連結し、条件分岐を入れるなどすると見通しが悪くなりがちでした。

次に示すのは、リソース取得のためのFetch APIを用いてその結果responseに応じて処理を出し分ける例です(※)。

fetch("./myjson.json")
  .then(response => new Promise((resolve, onrejected) => {
      if (response.ok) {
        return response
          .json()
          .then(json => resolve(json));
      }
 
      return onrejected(response.status);
    })
  )
  .then(
    json => console.log(Reflect.get(json, "mytext")),
    error => console.log(`error status : ${error}`)
  );

※ 取得結果であるresponseデータには、取得成功・失敗を示すresponse.okが含まれます。成功ならばJSONの中身を、失敗ならばエラーコードを出力するコードです。
コード中のReflect.get()を使うとオブジェクトから指定のプロパティを取り出せます。

ES2017で導入されたawait/asyncを使えば、次のようにネストを深くせずにPromiseによる処理を記述可能です。

async function main() {
  const response = await fetch("./myjson.json");
 
  if (!response.ok) {
    console.log(`error status : ${error}`);
    return;
  }
 
  const json = await response.json();
  console.log(Reflect.get(json, "mytext"));
}
 
main();
  • await演算子: Promiseによる処理の結果が返るのを待つ
  • async: 関数内でawaitを使うための宣言

☞︎整数部分の取得にはMath.trunc()メソッド

小数を整数に丸める場合、Math.floor()を使うことが多かったのですが、負の値を丸める場合の挙動が分かりづらく、複数人開発での混乱の元になりがちでした。

Math.floor(6.5);  // 6
Math.floor(-6.5);  // -7 (-6ではない)

ES2015で導入された整数部分だけを取得するMath.trunc()メソッドを使えば、正の値、負の値が関係なく整数部分を取得でき、直感的な挙動となります。

Math.trunc(6.5);  // 6
Math.trunc(-6.5);  // -6

☞︎べき乗の計算にはべき乗演算子**

2の5乗などのべき乗計算には、従来はMath.pow()を使っていました。

Math.pow(2, 5); // 32
Math.sqrt(Math.pow(3, 2) + Math.pow(4, 2));
// (3の2乗 + 4の2乗)のルート。5

ES2016ではべき乗演算子**(Exponentiation Operator))を使って同じようにべき乗計算が可能になりました。タイプ量が少なくなるメリットがあります。

2 ** 5; // 32
(3 ** 2 + 4 ** 2) ** 0.5;
// (3の2乗 + 4の2乗)のルート。5

筆者のQiita記事「べき乗をするならMath.pow()よりもExponentiation Operatorが手軽」もあわせて参照ください。

☞︎文字数カウントには配列用のスプレッド演算子

文字数をJavaScriptでカウントする場合は、Stringlengthプロパティを用いてきました。しかし、このプロパティではサロゲートペア文字列(「𦥑(臼ではありません)」や、「𩸽(ホッケ)」などの漢字、「😀」「😺」といった絵文字)の文字数が2以上になります。

"𦥑".length; // 2
"今日は☀️です".length; // 7

ES2015で導入された...」で表現されるスプレッド演算子。文字列と配列を組み合わせると、文字数のカウントに使えます。

[..."𦥑"].length; // 1。(旧字体の「𦥑」)
[..."今日は☀️です"].length; // 6

なお、JavaScriptにおける文字数の数え方についてより詳しくは記事「JavaScript における文字コードと「文字数」の数え方 | blog.jxck.io」を参照ください。

☞︎オブジェクトのコピーにも…(スプレッド演算子)

ES2015では、オブジェクトのコピーのためのObject.assign()が導入され、オブジェクトのコピー(シャローコピー)が楽になりました。

const myObject = {
  result: true,
  members: [
    { id: 1, name: "鈴木" },
    { id: 2, name: "田中" },
    { id: 3, name: "高橋" }
  ]
};
 
// オブジェクトのコピー
const copiedObject = Object.assign({}, myObject);
 
console.log(copiedObject);
// オブジェクトがコピーされる
// {
//    result: true,
//    members: [
//      { id: 1, name: "鈴木" },
//      { id: 2, name: "田中" },
//      { id: 3, name: "高橋" }
//    ]
//  }

ES2018で導入予定のオブジェクト用のスプレッド演算子を用いれば、次のような短いコードでオブジェクトのコピーが可能です。

const myObject = {
  result: true,
  members: [
    { id: 1, name: "鈴木" },
    { id: 2, name: "田中" },
    { id: 3, name: "高橋" }
  ]
};
 
// オブジェクトのコピー
const copiedObject = {...myObject};
 
console.log(copiedObject);
// オブジェクトがコピーされる

次のページでは、非同期処理に使用しているObservable(RxJS)と、未対応ブラウザで最新機能を使う方法、そして未来のJavaScriptの機能について紹介します。