in medias res

console.log([] == ![]); // true

意味不明

/* この頭痛がする式`[] == ![]`には順番に何が起こっているのか紐解いていく */
 
/* まず、`[]`はtruthy(条件式のときtrue)である */
console.log([] ? "true" : "false"); // true
 
/* 論理否定演算子`!`はオペランドをbooleanに変換し、それを反転させる */
console.log(![]); // false
 
/* そのため右辺の`![]`は`false`となる */
// `[] == false`
 
/* ここで、`==`演算子は型を強制する */
/* 一方のオペランドがbooleanならば、それを数値に変換する。`false`ならば`0`に変換される */
// `[] == 0`
 
/* さらに、一方のオペランドがobject(配列も含む)で、かつもう一方がプリミティブ値の場合、objectはプリミティブ値に変換される */
/* 変換は内部的にToPrimitive操作によって行われる。配列を含む多くの場合`toString()`が呼び出される */
/* よって`[]`は`toString()`を呼び出し、`""`(空文字列)となる */
// `"" == 0`
 
/* 最後に、一方のオペランドがstringで、かつもう一方がnumberの場合、stringはnumberに変換される */
/* `""`(空文字列)は`0`に変換される */
// `0 == 0`
 
/* すなわち */
console.log(0 == 0); // true

すべての元凶は曖昧な等価演算子

もちろん、厳密等価演算子===を使用すれば期待した通りの結果になるので、等価演算子==は二度と使わないでください。1

console.log([] === ![]); // false

さらにひどい例

JavaScriptでは空配列と空配列を足すと空文字列になる。空配列と空オブジェクトを足すと混沌が訪れる

おなじくひどい例

JavaScript baNaNa

Footnotes

  1. さすがに言い過ぎました。等価演算子==nullもしくはundefinedのいずれかにマッチさせたい場合は有用です。nullundefinedの場合はこのおかしな型変換は行われません