JavaScript 速習チュートリアル

JavaScript ベストプラクティス

グローバル変数の回避、new の使用制限、== の回避、eval() の禁止など、コードの品質を高めるためのルールを確認しましょう。

1. グローバル変数の回避

グローバル変数の使用は最小限に抑えてください。
これには、すべてのデータ型、オブジェクト、関数が含まれます。

グローバル変数や関数は、他のスクリプトによって上書きされるリスクがあります。
代わりにローカル変数(Local variables)を使用し、クロージャ(Closures)の活用方法を学びましょう。

2. 常にローカル変数を宣言する

関数内で使用するすべての変数は、ローカル変数として宣言する必要があります。

ローカル変数は、varlet、または const キーワードを使用して宣言しなければなりません。そうしない場合、それらはグローバル変数になってしまいます。
なお、ストリクトモード(Strict mode)では、未宣言の変数は許可されません。

3. 宣言を先頭に配置する

すべての宣言を各スクリプトまたは関数の先頭に置くことは、優れたコーディング慣行です。
これにより、以下のメリットが得られます。

  • コードがクリーンになる
  • ローカル変数を確認する場所が1箇所にまとまる
  • 意図しない(暗黙的な)グローバル変数の発生を避けやすくなる
  • 不要な再宣言の可能性を減らす
// 先頭で宣言する
let firstName, lastName, price, discount, fullPrice;

// 後で使用する
firstName = "太郎";
lastName = "田中";

price = 19.90;
discount = 0.10;

fullPrice = price - discount;

これはループ(Loop)変数についても同様です。

for (let i = 0; i < 5; i++) {
  // 処理
}

4. 変数の初期化

変数を宣言するときに初期化することは、良い慣行です。
これにより、以下のメリットが得られます。

  • コードがよりクリーンになる
  • 変数を初期化する場所が1箇所にまとまる
  • undefined(未定義)な値を避けることができる
// 先頭で宣言し、初期化する
let firstName = "";
let lastName = "";
let price = 0;
let discount = 0;
let fullPrice = 0;
const myArray = [];
const myObject = {};

変数を初期化することで、その変数の用途(および意図されたデータ型)を明示することができます。

5. JavaScript変数の再宣言

var で宣言された変数を再宣言しても、その値は失われません。
以下のステートメントを実行した後も、変数 carName の値は "Volvo" のままです。

例(非推奨):

var carName = "Volvo";
var carName;

一方で、letconst で宣言された変数を再宣言することはできません。

例(エラーになります):

let carName = "Volvo";
let carName; // 構文エラー

const carName = "Volvo";
const carName; // 構文エラー

6. オブジェクトを const で宣言する

オブジェクトを const で宣言することで、誤って型(Type)が変更されるのを防ぐことができます。

例:

let car = {type:"Fiat", model:"500", color:"white"};
car = "Fiat";      // オブジェクトが文字列に変更されてしまう

const car = {type:"Fiat", model:"500", color:"white"};
car = "Fiat";      // 不可能(エラーになる)

7. 配列を const で宣言する

配列を const で宣言することで、誤って型が変更されるのを防ぐことができます。

例:

let cars = ["Saab", "Volvo", "BMW"];
cars = 3;    // 配列が数値に変更されてしまう

const cars = ["Saab", "Volvo", "BMW"];
cars = 3;    // 不可能(エラーになる)

8. new Object() を使用しない

ラッパーオブジェクトの代わりにプリミティブな記法を使用してください。

  • new String() の代わりに "" を使用
  • new Number() の代わりに 0 を使用
  • new Boolean() の代わりに false を使用
  • new Object() の代わりに {} を使用
  • new Array() の代わりに [] を使用
  • new RegExp() の代わりに /()/ を使用
  • new Function() の代わりに function (){} を使用

例:

let x1 = "";              // 新しいプリミティブ文字列
let x2 = 0;               // 新しいプリミティブ数値
let x3 = false;           // 新しいプリミティブ論理値
const x4 = {};            // 新しいオブジェクト
const x5 = [];            // 新しい配列オブジェクト
const x6 = /()/;          // 新しい正規表現オブジェクト
const x7 = function(){};  // 新しい関数オブジェクト

9. 自動型変換への注意

JavaScriptは動的型付け(Loosely typed)言語です。
変数はすべてのデータ型を保持でき、またそのデータ型を変更することも可能です。

例:

let x = "こんにちは";     // x の typeof は string
x = 5;               // x の typeof は number に変更される

数値が意図せず文字列や NaN (Not a Number) に変換される可能性があることに注意してください。
数学的な演算を行う際、JavaScriptは数値を文字列に変換することがあります。

例:

let x = 5 + 7;       // x は 12、typeof は number
let x = 5 + "7";     // x は "57"、typeof は string
let x = "5" + 7;     // x は "57"、typeof は string
let x = 5 - 7;       // x は -2、typeof は number
let x = 5 - "7";     // x は -2、typeof は number
let x = "5" - 7;     // x は -2、typeof は number
let x = 5 - "x";     // x は NaN、typeof は number

文字列から文字列を引いてもエラーは発生せず、NaN が返されます。

例:

"Hello" - "Dolly"    // NaN を返す

10. === 比較を使用する (Use === Comparison)

== 比較演算子は、比較の前に常に(一致する型に)変換を行います。
一方、=== 演算子は値と型の両方の比較を強制します。

例:

0 == "";        // true
1 == "1";       // true
1 == true;      // true

0 === "";       // false
1 === "1";      // false
1 === true;     // false

11. パラメータのデフォルト値を使用する

引数(Argument)を渡さずに関数を呼び出すと、不足している引数の値は undefined に設定されます。
undefined な値はコードを破壊する可能性があります。引数にデフォルト値を割り当てることは良い習慣です。

例:

function myFunction(x, y) {
  if (y === undefined) {
    y = 0;
  }
}

ECMAScript 2015 では、関数定義の中でデフォルトパラメータ(Default parameters)を使用できるようになりました。

function (a = 1, b = 1) { /* 関数コード */ }

12. Switch文は必ず default で終える

必要ないと思っても、常に switch 文の最後には default を付けてください。

例:

switch (new Date().getDay()) {
  case 0:
    day = "日曜日";
    break;
  case 1:
    day = "月曜日";
    break;
  case 2:
    day = "火曜日";
    break;
  case 3:
    day = "水曜日";
    break;
  case 4:
    day = "木曜日";
    break;
  case 5:
    day = "金曜日";
    break;
  case 6:
    day = "土曜日";
    break;
  default:
    day = "不明";
}

13. プリミティブ値をオブジェクトとして扱わない

数値、文字列、論理値は常にプリミティブ値(Primitive values)として扱い、オブジェクトとして扱わないでください。
これらの型をオブジェクトとして宣言すると、実行速度が低下し、好ましくない副作用(Side effects)が発生します。

例:

let x = "John";             
let y = new String("John");
(x === y) // false です。x は文字列、y はオブジェクトであるため。

さらに悪い例:

let x = new String("John");             
let y = new String("John");
(x == y) // false です。オブジェクト同士を比較することはできないため。

14. eval() の使用を避ける

eval() 関数は、テキストをコードとして実行するために使用されます。ほとんどすべての場合において、これを使用する必要はありません。
任意のコードを実行できてしまうため、セキュリティ上の問題も伴います。