JavaScript配列+配列をするとjoin()される
Arrayに+演算子を適用したらどうなるのかという話です。
これにハマった人が嘆いていたので気になって調べました
論よりコード
a=[1,2];
b=[3,4];
c=a+b;
console.log(c) // => "1,23,4"
JavaScript「配列と配列の+演算?できますできます join()処方しておきますね^^」
配列+配列をしたつもりが面白いことに変数cは文字列になって妙な結合をしていますね
この程度のことではTypeErrorにならないクールなところが個人的には好きです
正しくは
a=[1,2];
b=[3,4];
c=a.concat(b);
console.log(c) // => [1, 2, 3, 4]
やりたいのはこういうことだと思う
何が起きているのか
簡単に言うと
・配列に+演算はできないので暗黙の型変換がおきる
↓
・変換が行われて内部的に配列に対してjoin()メソッドが適用される
↓
・文字列同士であれば+演算子は連結を行う
↓
・よってcは「"1,2"+"3,4"」の結果となる
もう少し詳しく
JavaScriptは、必要とする値の型について、非常に柔軟な対応をします。
型とは
JavaScriptでは
数値でも、文字列でも、論理値でも、nullでもundefinedでもない値はすべてオブジェクトです
今回の配列もオブジェクトということですね
型変換とは
オブジェクトはすべて変換メソッドを2つ持ちます
toString()
メソッドと
valueOf()
メソッドです
valueOf()
メソッドについては今回は割愛します。
toString()
はオブジェクトを表す文字列を返します。
通常あまり意味を持ちません
({x:1, y:2}).toString() // => "[object Object]"
しかし多くのクラスはそのクラス用にtoString()
メソッドを定義しています。
今回の配列Array クラスであれば
toString()
メソッドは、配列の各要素を文字列に変換し、カンマで区切って結合した文字列を返します。
join()
と全く同じ動作です。(ECMAScript公式ドキュメントにjoin()
を行うと明記されていました)
[1,2,3].toString() // => "1,2,3"
[1,2,3].join() // => "1,2,3"
つまりいつ何時も配列は上記の動作で文字列として変換可能で必要に応じて変換されることになります
+演算子について
+演算は数値型か文字列型でしか評価しません。必要とする値の型は数値か文字列です。
数値であれば加算を行い、文字列の場合は連結を行います。
①オペランドの値のどちらかがオブジェクトの場合、オブジェクトから基本型値への変換アルゴリズムを使って、オブジェクトを基本型値に変換します。
ここでtoString()
メソッドが適用されます。
(正確にはDate以外のオブジェクトはまずvalueOf()
が適用されますが多くのオブジェクトは意味のあるvalueOf()
メソッドを持たないので結局toString()
を使って型変換を行われます。)
②オブジェクトから基本型への型変換の後、オペランドの一方が文字列の場合、もう一方のオペランドも文字列に変換し連結処理を行います。
③それ以外の場合は、両方のオペランドを数値(または NaN)に変換し、加算処理が行われます。
1 + 2 // => 3: 加算。
"1" + "2" // => "12": 連結。
"1" + 2 // => "12": 数値から文字列への変換の後、連結。
1 + {} // => "1[object Object]": オブジェクトから文字列への変換の後、連結。
true + true // => 2: 論理値から数値への変換の後、加算。
2 + null // => 2: null を 0 に変換した後、加算。
2 + undefined // => NaN: undefined を NaN に変換した後、加算。
要するに+演算するために勝手に配列は文字列に変換されるしそれはカンマ区切りですよってことです
ちなみにpythonだと
a = [1,2]
b = [3,4]
c= a+b
print(c) # => [1, 2, 3, 4]
あっ・・・
まとめ
JavaScriptで配列の型変換はjoin()されるので注意って話でした
参考文献
ECMA-262 - Ecma International
https://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf