JavaScript ベストプラクティス
グローバル変数の回避、new の使用制限、== の回避、eval() の禁止など、コードの品質を高めるためのルールを確認しましょう。
1. グローバル変数の回避
グローバル変数の使用は最小限に抑えてください。
これには、すべてのデータ型、オブジェクト、関数が含まれます。
グローバル変数や関数は、他のスクリプトによって上書きされるリスクがあります。
代わりにローカル変数(Local variables)を使用し、クロージャ(Closures)の活用方法を学びましょう。
2. 常にローカル変数を宣言する
関数内で使用するすべての変数は、ローカル変数として宣言する必要があります。
ローカル変数は、var、let、または 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;一方で、let や const で宣言された変数を再宣言することはできません。
例(エラーになります):
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; // false11. パラメータのデフォルト値を使用する
引数(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() 関数は、テキストをコードとして実行するために使用されます。ほとんどすべての場合において、これを使用する必要はありません。
任意のコードを実行できてしまうため、セキュリティ上の問題も伴います。