indexOfを使う際は配列の要素に注意

2つの配列の差分を取るコードをindexOfを使って書いた。

function get_diff(older, newer){
    function callback_filter(element, index, array){
        return (this.indexOf(element) === -1); // 要素が含まれていなければtrue
    }

    return newer.filter(callback_filter, older);
}

文字列onlyな配列だとうまく動く。

get_diff(["a", "b"], ["a", "b", "c"])
>> ["c"]

でも配列の中に配列とか連想配列を含むとおかしくなる。

get_diff([{a: "A"}, {b: "B"}], [{a: "A"}, {b: "B"}, {c: "C"}]);
>> [{"a":"A"},{"b":"B"},{"c":"C"}] 

これはindexOfが原因である。

indexOfは要素を比較する際、JSON.stringfyを使わずに比較しているようである。

[["a"], "b"].indexOf(["a"])
>> -1

JSON.stringfyを使わずに配列や連想配列を比較するとfalseとなってしまう。

{a: "A"} == {a: "A"}
>> false
{a: "A"} === {a: "A"}
>> false

というわけでindexOfを使わないコードを書いた。

function get_diff2(older, newer){
    function callback_filter(element, index, array) {
    	for (var i = 0; i < this.length; i++) {
    		if (JSON.stringify(this[i]) === JSON.stringify(element)) {
                return false;
            }
        }
        return true;
    }
    return newer.filter(callback_filter, older);
}

Array.prototype.indexOfを使う際は配列の中の要素に注意しましょう。