JavaScriptの奇異なSyntax

 
Web Tips.
Booskanium's
Booskanium's Web Tips.

一見して、奇異なコーディングもJavaScriptたる所以です。

JavaScriptの柔軟すぎる構文を理解しておかないと記号のお化けにしか見えないケースがあります。
この記号のお化け的書き方を好む人もいますので、リバースエンジニアリングの為に知っておいた方が良いメモです。
プログラミングに限らず妙な新語や方言が好まれるのは世の常なのかもしれません。ただ過ぎたる方言は人に伝わりません。

セミコロンを書く、書かない

自分はセミコロンを書く派(習慣として染み付いている)ですが、書かないほうが読みやすい様な気もします。しかし後述の様に生半可にセミコロン無しで書くとミスを誘発します。
セミコロン無しで書くなら変なところで改行しない。改行した時のセミコロン自動挿入の有無を理解しとく。
それと重要なのは、JavaScriptの圧縮ツールを利用する場合です。圧縮ツールでセミコロン自動挿入に対応していない物があり、改行が失われることよる誤動作や構文エラーが頻発する場合があります。

関数の閉じかっこにはセミコロンを書かない

この理由はJavaScript構文で関数の閉じカッコに後ろにはセミコロンなしを推奨しています。この理由を何かの文献で読んで納得したのですが、その所在と理由は失念しました。

function func() {
	a,
	b,
};
    ↑関数の場合はこの閉じセミコロンを書かない

ただし、関数定義の後に“(”で始まる即時実行関数定義がある場合は思わぬ結果を招きますので、無駄でも関数の終わりにセミコロンを書く癖をつけた方が良いと思われます。

var func = function() {
	//...
}
(function() {
	//...
})());
これ、1つ目の関数が即時実行関数と解釈されます。 下記の様に書けば問題有りません。
var func = function() {
	//...
}
(function() {
	//...
})();

returnでオブジェクトを戻したい

returnでオブジェクトを戻したいときに

return
{
	a,
	b,
}	
							
駄目ですね、これは以下と同義です。
return;
{
	a,
	b,
}
							
正しくは
return {
	a,
	b,
}
							
と書かねばなりません。

あれれ、即時実行関数でクロージャーを書きたい

これ即時実行にならない

a = b + c
(function {
	処理
})()
							
無名関数のクロージャーにしたいのでしょうが、cの次の行の(が結合されて「c()」で関数呼び出しになります。
正しくは
a = b + c
!function {
	処理
}()
							
と書けば無名関数のクロージャーになります。
クロージャーと書きましたが、クロージャーが何故必要か?
それはプレイベート変数で処理したい場合に用います。JavaScriptの理解が難しい所以です。

詳しくはhttps://blog.tai2.net/automatic_semilocon_insertion.htmlを参照。

左かっこは改行前、それとも改行後

これは前述のセミコロンを書く・書かないの項で答えがでています。

問題がになるケースです

改行前に書く場合はなんの問題もありません。

return {
	a,
	b,
}
							
改行後に左かっこを書く場合と問題が発生するケースです。
return
{
	a,
	b,
}
							
この様な凡ミスに繋がりますので、左かっこは改行前に書く癖をつけて、目を慣らしといた方が良いです。

びっくりびっくり(!!)っ何?

リバースエンジニアリングしていると、時々目にする二重否定って何なんだろう。調べたら未定義変数にundefinedが戻らなかった初期の頃に活躍した名残みたいです。

比較演算子で活躍した名残

varなどで未定義項目にboolean型のfalseを戻してエラーにならない様にする

if (!!conditions) {
}
							
否定演算子は渡されたオブジェクトをboolean型の値で戻します。もし未定義のオブジェクトが渡されるとboolean型のfalseが戻ります。
今のJavaScriptエンジンは未定義項目にundefinedを返し、条件式としてはfalseになる仕様なので、この様な書き方は不要です。

昔のシーケンス処理的(Goto)な処理

JavaScriptにはGoto文がありません。Goto乱用でとんでもなく遠方にかっ飛ぶ奇っ怪なロジックが書かれてしまう事は防がれています。しかし単純なシーケンス処理を表現したい場合は不便です。
そこで単純なシーケンス処理的な事を行いたい場合は、labeled文にcontinueとbreakを組み合わせる方言記述が行われます。この方言で閉じられた階層内や親階層への遷移ができます。

参考になる文献

JavaScriptでgoto文的な処理ができるlabeled文の使い方とコード例
[JavaScript] goto 文の実装例

変数の巻き上げ

var variable  = "global";
function func() {
    console.log(variable);    // undefined
    var variable = "local";
    console.log(variable);    // local
}
func();
							
上記のコードの巻き上げって、なんというムフフな構文なんでしょう。
最初のconsol.logでvar定義前だからグローバル変数が参照されると思っていると痛い目にあいます。
なお、巻き上げはアロー関数と関数リテラルでは起きません。これもなんともムフフです。

このムフフな構文の落とし穴にはまらない様にするために、
・関数内のクロージャ変数は最初にまとめて書く
場当たり的な変数乱用の前に変数を考える癖もつきます。

オブジェクトの複製方法

これ、知らないと思わぬ不具合を招きます。

これ、複製じゃなくて参照です

「obj2 = obj1;」

オブジェクトの複製方法は

「obj2 = JSON.parse(JSON.stringify(obj1));」

これ、表層のオブジェクトのみの複製

「obj2 = Object.assign({}, obj1);」
これ、階層を持つオブジェクト複製には使えない。