書籍「メンテナブルJavaScript」と Google JavaScript Style Guide 和訳 を参考に自分なりのJavaScriptスタイルガイドを用意してみた。適時アップデートする。
本家Google JavaScript Style Guide(英語)ではES6に対応したスタイルガイドに更新されているが、まだぼくのスキルでは難解のため、和訳も更新されるのを待ちたい(汗)。
インデントの各レベルは、2個の空白とする。タブは使わない。
// Good
if (true) {
doSomrthing();
}
// Bad: 空白が4個
if (true) {
doSomrthing();
}
常にセミコロンを使う。
// Good
let name = 'Taketake';
// Bad: セミコロンがない
let name = 'Taketake'
1行100文字とする。
100文字を超える場合は、読みやすい形で複数行にする。
// Good: 2レベル分(空白4つ)をインデントする
callAFunction(document, element,
navigator);
// Good: 長い関数名の場合
foo.bar.doThingThatIsVeryDifficultToExplain(
document, element);
// Good: 引数を強調したい場合
foo.bar.doThingThatIsVeryDifficultToExplain(
veryDescriptiveArgumentNumberOne,
veryDescriptiveArgumentTwo,
tableModelEventHandlerProxy,
artichokeDescriptorAdapterIterator);
// Good: if文の場合、本体は1インデントレベルであることがポイント
if (isYear && isMonth && isDay &&
isYourBirthday) {
//...
}
// Bad: 演算子の前で改行されている
if (isYear && isMonth && isDay
&& isYourBirthday) {
//...
}
// Good: 例外 変数を代入するとき
let result = somthing + anything +
somthingElse;
// Bad: 変数を代入するときに通常ルール
let result = somthing + anything +
somthingElse;
以下の箇所で空行を追加する。
キャメルケース(小文字で始まり、その後に頭文字が大文字で単語が続く)を使う。
変数は名詞、関数は動詞を使う。
// Good
let count = 10;
let myName = 'Taketake';
let found = true;
// Bad: 関数と間違いやすい
let getCount = 10;
let isFound = true;
// Good
function getName() {
return myName;
}
// Bad: 変数と間違いやすい
function theName() {
return myName;
}
can, has, is はブーリアンを返す関数、
get は非ブーリアンを返す関数、
set は値を保存するために使われる関数、
として使う。
MEMO: 変数名である程度、型がわかるようにした方がいいかも。isFoundは名詞として使ってもいいし、numCountとすることでnumber型と分かるようにするのもいい。命名はもう一度熟考する必要あり。
すべて大文字、単語の間はアンダースコアとする。
// Good
const MAX_COUNT = 10;
const URL = 'https://www.simplesimplesdesign.com/';
Pascalケース(先頭文字が大文字である以外はキャメルケースと同じ)を使う。
文字列にはダブルクオートよりもシングルクオートを使う。
常に1行内に収める。スラッシュを使って文字列内で改行してはいけない。
// Good
let name = 'Hi, I am Taketake.';
let name = "Hi, I'm Taketake.";
// Bad: シングルクオートのなかにシングルクオート
let name = 'Hi, I\'m Taketake.';
// Bad: 次行に折り返している
let longString = 'アイウエオ\
かきくけこ';
数値は10進数の整数、e表記の整数、16進数の整数、小数点の前後に少なくとも1桁ずつある小数にする。8進数リテラルリテラルは使わない。
// Good
let count = 10; // Integer
let price = 10.0; // Decimal
let price = 10.00; // Decimal
let num = 0xA2; // 16進数
// Bad: 小数点で終わっている
let price = 10.;
// Bad: 小数点で始まっている
let price = .1;
// Bad: 8進数は非推奨
let num = 010;
undifinedと混同されがち。nullは、下記のケースで使う。
null を使うべきではないケース
// Good
let person = null;
// Good
function getPerson() {
return (condition)? new Person('Taketake'): null;
}
// Good
let person = getPerson();
if (person !== null) {
doSomething();
}
// Bad: 初期化されていない変数とテストしている
let person;
if (person != null) {
doSomething();
}
// Bad: 引数が渡されたかをテストしている
function doSomething(arg1, arg2) {
if (arg2 != null) {
doSomethingElse();
}
}
nullと混同されがち。
undefined は使わない。変数が宣言されているかどうかを利用するときにのみ、typeof演算子を使って undefined を使う。
それ以外、つまり後でオブジェクトの値が代入されるかもしれないし、されないかもしれない変数を使うときは、null で初期化しておく。
// Good
if (typeof variable === 'undefined') {
doSomething();
}
// Bad: undefinedリテラルを使用
if (variable === undefined) {
doSomething();
}
// Good
let object = {
key1: value1,
key2: value2,
func: function () {
doSomething();
}
key3: value3
};
// Bad: インデントが正しくない
let object = {
key1: value1,
key2: value2
};
// Bad: 関数の前後に空行がない
let object = {
key1: value1,
key2: value2,
func: function () {
doSomething();
}
key3: value3
};
// Good
doSomething({
key1: value1,
key2: value2
});
// Bad
doSomething({ key1: value1, key2: value2 });
// Good
let book = {
title: 'ノルウェーの森',
author: '村上春樹'
};
// Bad: 滅多に使われない
let book = new Object();
book.title = 'ノルウェーの森';
book.author = '村上春樹';
// Good
let colors = ['red', 'green', 'blue'];
let numbers = [1, 2, 3, 4];
// Bad: 問題視される
let colors = new Array('red', 'green', 'blue');
let numbers = new Array(1, 2, 3, 4);
コードの内容がはっきりしないときにはコメントすべきであり、内容がはっきりしているときはコメントすべきではない。
2つのスラッシュの後に空白を入れてコメントする
// 1行コメント
// Good
if (condition) {
// ここに通ればセキュリティチェックは合格
allowed();
}
// Bad: コメントの前に空行がない
if (condition) {
// ここに通ればセキュリティチェックは合格
allowed();
}
// Bad: インデントが正しくない
if (condition) {
// ここに通ればセキュリティチェックは合格
allowed();
}
// Good
let result = something + somethingElse; // コメントコメントコメント
// Bad: コードとコメントの間に余白がない
let result = something + somethingElse;// コメントコメントコメント
// Good
// if (condition) {
// doSomething();
// }
// Bad: これは複数行コメントにすべき
// 次のコードの説明を補足
// 条件がtrueかどうかで実行内容が決定される
// こんな感じで1行コメントで
// 説明書きを足していくのはBadケース
// Good
if (condition) {
/*
* 複数行コメントを書くときのサンプル
* テキストテキストテキスト
*/
doSomething();
}
// Bad: コメントの前に空行がない
if (condition) {
/*
* 複数行コメントを書くときのサンプル
* テキストテキストテキスト
*/
doSomething();
}
// Bad: *(アスタリスク)が揃っていない
if (condition) {
/*
* 複数行コメントを書くときのサンプル
* テキストテキストテキスト
*/
doSomething();
}
// Bad: *(アスタリスク)の後に空白がない
if (condition) {
/*
*複数行コメントを書くときのサンプル
*テキストテキストテキスト
*/
doSomething();
}
// Bad: インデントが正しくない
if (condition) {
/*
*複数行コメントを書くときのサンプル
*テキストテキストテキスト
*/
doSomething();
}
// Bad: 行末のコメントとして複数行コメントを使わない
let result = something + somethingElse; /* テキストテキスト */
1語の後にコロンが続く形式を取る。1行コメントでも複数コメントでも、どちらでも使える。一般的なコメントと同じフォーマットのルールに従う。可能なアノテーションは以下の通り。
TODO
このコードの実装が未完であることを示す。次のステップに関する情報を盛り込むべき。
HACK
このコードが応急措置的ハックで書かれていることを示す。なぜハックが使われているのか、その理由についても書くべき。これは問題を解決するより良い方法で置き換えた方が良いことも示す。
XXX
コードが問題含みであり、できるだけ早く解決すべきであることを示す。
FIXME
コードが問題含みであり、早期に解決すべきであることを示す。XXXよりも重要度は低い。
REVIEW
コード改変のためにレビューする必要があることを示す。
@namespace
オブジェクトを包含するグローバル参照。
@class
オブジェクトあるいはコンストラクタ関数の意味で使う。
@constructor
この「クラス」が実際はコンストラクタ関数であることを示す。
@property と @type
オブジェクトのプロパティを説明する。
@param
関数が取る引数のリスト。パラメータの型は波括弧の中に書き、その後にパラメータの名前と説明を続ける。
@return
メソッドの戻り値を説明する。名前の指定はなし。
/**
* 説明テキストテキストテキスト
* テキストテキストテキスト
*
* @method merge
* @param {object} objects* マージする1個以上のオブジェクト
* @return {object} マージされたオブジェクト
*/
/**
* 数学ユーティリティ
* @namespace MYAPP
* @class math_stuff
*/
MYAPP.math_stuff = {
/**
* 和を計算
*
* @method sum
* @param {number} a 数値1
* @param {number} b 数値2
* @return {number} 2つの数の和
*/
sum: function (a, b) {
return a + b;
}
}
/**
* Person オブジェクトを作成
* @class Person
* @constructor
* @namespace MYAPP
* @param {string} first フィーストネーム
* @param {string} last ラストネーム
*/
MYAPP.Person = function (first, last) {
/**
* ファーストネーム
* @property firstName
* @type string
*/
this.firstName = first;
/**
* ラストネーム
* @property lastName
* @type string
*/
this.lastName = last;
}
/**
* その人の名前を返却する
*
* @method getName
* @return {string} 名前
*/
MYAPP.Person.prototype.getName = function () {
return this.firstName + ' ' + this.lastName;
}
// Good
if (condition) {
doSomething();
}
// Bad: {} がない
if (condition)
doSomething();
// Bad: 1行に省略している
if (condition) doSomething();
// Bad: 1行に省略している
if (condition) { doSomething(); }
// Good
if (condition) {
doSomething();
} else {
doSomethingElse();
}
// Bad: C#, Visual Studioスタイル
if (condition)
{
doSomething();
}
else
{
doSomethingElse();
}
空行は、論理的に関連するコードのセクションを区切ることでコードの可読性を向上させる。
次の状況では2行の空行を必ず使う。
次の状況では1行の空行を必ず使う。
空白は次の状況で使用する。
// Good
if (condition) {
doSomething();
}
// Bad: 空白で区切らない
if(condition){
doSomething();
}
// Bad: 括弧内の前後に空白を置く
if ( condition ) {
doSomething();
}
意図的な素通りであれば、それは許容される
switch (condition) {
case 'first':
case 'second':
doSomethingA();
break;
case 'third':
doSomethingB();
/* 下に落ちる */
default:
doSomethingC();
}
// Good
switch (condition) {
case 'first':
doSomethingA();
break;
// default なし
}
// Bad: デフォルトのアクションで何も実行しないときでもdefaultを含める
switch (condition) {
case 'first':
doSomethingA();
break;
default:
// 何も実行しない
}
with文は使用しない。
// Good
let values = [1, 2, 3, 4, 5],
i,
len;
for (i=0, len=values.length; i < len; i++) {
process(values[i]);
}
// Good
let values = [1, 2, 3, 4, 5],
i,
len;
for (i=0, len=values.length; i < len; i++) {
if (i == 2) {
break; // 以後イテレーションしない
}
process(values[i]);
}
// Good
let values = [1, 2, 3, 4, 5],
i,
len;
for (i=0, len=values.length; i < len; i++) {
if (i != 2) {
process(values[i]);
}
}
// Case by case
let values = [1, 2, 3, 4, 5],
i,
len;
for (i=0, len=values.length; i < len; i++) {
if (i == 2) {
continue; // このイテレーションをスキップするだけ
}
}
// Good
let prop;
for (prop in object) {
if (object.hasOwnProperty(prop)) {
console.log('name is ' + prop);
console.log('value is ' + object[prop]);
}
}
// Bad: インスタンスプロパティだけが得られるようになっていない
let prop;
for (prop in object) {
console.log('name is ' + prop);
console.log('value is ' + object[prop]);
}
// Bad: エラーが起きる可能性がある
let values = [1, 2, 3, 4, 5],
i;
for (in in values) {
process(items[i]);
}
ECMAScript 5までは、var
ECMAScript 6 からは、let, const
それぞれ挙動が異なる。
var で変数宣言した場合、その変数はJavaScriptエンジンによって巻き上げられる。つまり関数の中のどこで変数を定義したとしても、関数の冒頭で宣言したのと同じになる。
関数宣言はJavaScript宣言によって巻き上げられる。
// Good
doSomething(item);
// Bad: ブロック文のように見える
doSomething (item);
即時関数呼び出しが発生することが明確にするために、関数を括弧でくくる。
// Good
let value = (function() {
return 'Hi';
})();
// Bad: 最後の行までみないと即時関数かわからない
let value = function () {
return 'Hi';
}();
グローバルスコープに "use strict" を指定するのは避ける
// Good
function doSomething() {
'use strict';
// コード
}
// Bad: グローバルstrictモード
'use strict';
なるべく、== と != ではなく、 === と !== を利用する
// 数値の5と文字列の5
console.log(5 == '5'); // true
console.log(5 === '5'); // false
// 数値の25と16進数の25
console.log(25 == '0x19'); // true
console.log(25 === '0x19'); // false
// 数値の1とtrue
console.log(1 == true); // true
console.log(1 === true); // false
// 数値の0とfalse
console.log(0 == false); // true
console.log(0 === false); // false
// null と undefined
console.log(null == undefined); // true
console.log(null === undefined); // false
eval()は、受け取ったJavaScriptコードの文字列を実行する。タスクを実現できる手段が他に有る限り、eval()を避ける。
String、Bookean、Numberのプリミティブラッパー型は使用しない。
// Good
let s = 'string text';
let n = 123;
let b = true;
// Bad: プリミティブラッパー型を使用している
let s = new String('string text');
let n = new Number(123);
let b = new Boolean(true);
この書籍の中で、ライティングのユーザビリティについて触れている項目があり、激しく共感する部分だったので、ここで備忘録としてピックアップする。 ・・・
この書籍は、I部 リサーチ、II部 デザイン、III部 インプリメンテーションと三部構成になっている。この記事では、その中から、I部 リサーチ、・・・
これを知ったときはマジか!と飛び跳ねた。あらためて思い返してみると、確かに公式チュートリアルでも触れていたことをうっすら思い出す。そしてそのときとやり方がなん・・・
試したことはまだないけど、Macで編集時と書き出し後で色味が変わって困ったときのために備忘録。 プロジェクト設定 > 「カラーマネジメント・・・
プロジェクト設定と環境設定について詳しく解説されている情報がなかなか見つからないので、要所要所で知り得た情報を更新していきます。 プロジェクト設定 ・・・
Clipyが超絶便利そうだったので、macOS Big Sur にインストール&再起動して使ってみた。ところが、command + c を複数の箇所で行い、c・・・
requestAnimationFrame をはじめて見たので調べていたら、setTimeout や setInterval は requestAnimati・・・
6年ぶりに読み返したが、今なおハッとさせられることが多く見つかる。 この本で忘れないようにしたい項目をピックアップするだけでも役に立ちそ・・・
この記事では、以前に読んだ際に付箋を付けていたが、その部分だけを備忘録としてピックアップするため、本の要約ではない。実際は、何倍も濃い内容で、練・・・
もう一回、全部読み返したいところだが、書籍がありすぎるので、当時付箋紙をつけていたところだけをピックアップ。書籍内ではより具体的な説明があるので・・・
正しいCSSを記述しているにもかかわらず、表示が崩れることがある。ブラウザによる解釈の違い(バグ)が原因であるが、IE5や古いブラウザにバグが見られる。・・・
iBook G4(OS10.3.x)がある。Safariのバージョンは、1.xだ。2は10.4にしないと使えない。もっと詳しく言えば、10.4.10以下でないと・・・
ブラウザ、モバイルファースト、メディアクエリー、マルチ画面、タブレット・・・ 想定すべき画面サイズ、利用シーンに適した情報のコントロールが崩壊しつつある。 とい・・・
たとえば、白文字が混じった画像を透明GIFにする場合、背景だけでなく白文字までが透明化されてしまう。 ずっと悩んでいたがようやく解決できたので覚え書き。 形・・・
jQurey Mobile。まもなくβ版がリリースされるそうですが、現状のα版3を見てみました。 最低限必要なソースまで削り落として、ちょっとjQuery Mo・・・
変数bnにphpファイルのファイル名を拡張子なしで取得するサンプル $bn = basename($_SERVER['PHP_SELF'], ".php");・・・
sassファイルを保存すると、cssファイルが自動生成されるという症状でしばらくの間、ストレスだったがようやく解決。 例えば、var.scssを修正して保存す・・・
記述方法は間違いないのに、文字化けしてしまう。 xhtmlはutf-8で宣言していたのだが、Javascriptで記述された日本語がブラウザで確認すると文字化け・・・
変数bnにhtmlファイルのファイル名を拡張子なしで取得するサンプル var bn = location.href.split("/"); bn = bn[b・・・
ローカル環境はMAMPを使いました。 データベースを作成する MAMPを起動し、「サーバを起動」後、「オープンWebStartの」をクリックします。 「ツ・・・
「test」
「>ころころさん コメントありがとうございます! 確かに、APIドキュメント見ましたが、ライブに関する情報は今のところ取得できないようですね。 インスタライ・・・」
「SIGMAから超軽量で明るい単焦点レンズが2本発売になりましたので、リストにレンズ情報追加しました!」
「>名無しさん ご指摘、ありがとうございます! 記事冒頭の「まずはサンプル」のサンプルが動いていませんでしたので修正しました。」
「>前田さん コメントありがとうございます。 環境は分かりかねますが、修正したいファイルのパーミッションを604や644に変更すると書き込みできるようになります(・・・」
「アバターを取得する「get_avatar」についても追記しました!」
「「値をクリアする」を追加しました。チェックボックスやラジオボタンの値を何も選択していない状態に戻すときについて触れています。」
「>匿名さん コメントありがとうございます。 サンプルでは、beforeは何も処理していないので期待する表示にならない、で正解です。 クリックした後が、対応・・・」
「(匿名)さん コメントありがとうございます。何も設定変更していないのに、それまで使用できていたサーバーが突然使えなくなるのは辛いですよね、、。 ここで紹介したや・・・」
「コメントありがとうございます! そもそもできるかはわかりませんが、ソースを書き換える必要はあります。 下記記事などが参考になるかもしれません。 illustra・・・」
WEB制作マークアップJavaScriptJavaScriptスタイルガイド | シンプルシンプルデザイン