Edited at

Javascriptにおけるオブジェクトの順序

More than 3 years have passed since last update.

最初のころはObjectの順序は保証されていないと思っていたのでまとめました。


Javascriptエンジン

今回検証する3つのエンジン


v8


  • Node.js

  • Chrome


SpiderMonkey


  • FireFox


Nitoro


  • Safari


結論


v8: Node.js, Chrome


  • Objectの順序


    1. 数値順

    2. 挿入順



  • 1aなど数字から始まる文字は文字列扱い

  • 0は数値扱いで00は文字列扱い


SpiderMonkey: FireFox


  • Objectの基本的な順序


    1. 数値順

    2. 挿入順



  • 最初に挿入される数値が1000以上の場合、挿入順になる

  • 最初に挿入される数値が1000未満の場合、数値順・挿入順になる

  • 1aなど数字から始まる文字は文字列扱い

  • 0は数値扱いで00は文字列扱い


Nitoro: Safari


  • 挿入順



  • ブラウザ間で挙動が異なるので、実用的ではない

  • v8は結構記事書かれてるけど結論出てない感じ 調査中…


検証1


  • Node.js v0.10.33

  • Chrome バージョン 39.0.2171.71

  • FireFox 34.0

  • Safari バージョン 6.0.5...

空オブジェクトに順番に入れてみる

var obj = {};

obj.c = 'c';
obj.b = 'b';
obj.a = 'a';
obj['2'] = '2';
obj[1] = '1';


Node.js

console.log(Object.keys(obj));

// [ '1', '2', 'c', 'b', 'a' ]

console.log(JSON.stringify(obj));
// {"1":"1","2":"2","c":"c","b":"b","a":"a"}


Chrome

console.log(Object.keys(obj));

// ["1", "2", "c", "b", "a"]

console.log(JSON.stringify(obj));
// {"1":"1","2":"2","c":"c","b":"b","a":"a"}


FireFox

console.log(Object.keys(obj));

// Array [ "1", "2", "c", "b", "a" ]

console.log(JSON.stringify(obj));
// "{"1":"1","2":"2","c":"c","b":"b","a":"a"}"


Safari

console.log(Object.keys(obj));

// ["c", "b", "a", "2", "1"]

console.log(JSON.stringify(obj));
// {"c":"c","b":"b","a":"a","2":"2","1":"1"}


結果


  • safari以外は数値順・挿入順

  • safariは挿入順


検証2

初期値があるとどうなるか

var obj = {

c: 'c',
b: 'b',
a: 'a',
'3': '3',
2: 2
};
obj[1] = '1';


Node.js

console.log(Object.keys(obj));

// [ '1', '2', '3', 'c', 'b', 'a' ]

console.log(JSON.stringify(obj));
// {"1":"1","2":2,"3":"3","c":"c","b":"b","a":"a"}


Chrome

console.log(Object.keys(obj));

// ["1", "2", "3", "c", "b", "a"]

console.log(JSON.stringify(obj));
// {"1":"1","2":2,"3":"3","c":"c","b":"b","a":"a"}


FireFox

console.log(Object.keys(obj));

// Array [ "1", "2", "3", "c", "b", "a" ]

console.log(JSON.stringify(obj));
// "{"1":"1","2":2,"3":"3","c":"c","b":"b","a":"a"}"


Safari

console.log(Object.keys(obj));

// ["c", "b", "a", "3", "2", "1"]

console.log(JSON.stringify(obj));
// {"c":"c","b":"b","a":"a","3":"3","2":2,"1":"1"}


結果


  • safari以外は数値順・挿入順

  • safariは挿入順


検証3

数値が先頭だとどうなるか

var obj = {

'b': 'b',
'a': 'a',
'2c': '2c',
'1b': '1b',
'1a': '1a'
};
obj[3] = 3;


Node.js

console.log(Object.keys(obj));

// [ '3', 'b', 'a', '2c', '1b', '1a' ]

console.log(JSON.stringify(obj));
// {"3":3,"b":"b","a":"a","2c":"2c","1b":"1b","1a":"1a"}


Chrome

console.log(Object.keys(obj));

// ["3", "b", "a", "2c", "1b", "1a"]

console.log(JSON.stringify(obj));
// {"3":3,"b":"b","a":"a","2c":"2c","1b":"1b","1a":"1a"}


FireFox

console.log(Object.keys(obj));

// Array [ "3", "b", "a", "2c", "1b", "1a" ]

console.log(JSON.stringify(obj));
// "{"3":3,"b":"b","a":"a","2c":"2c","1b":"1b","1a":"1a"}"


Safari

console.log(Object.keys(obj));

// ["b", "a", "2c", "1b", "1a", "3"]

console.log(JSON.stringify(obj));
// {"b":"b","a":"a","2c":"2c","1b":"1b","1a":"1a","3":3}


結果


  • safari以外は数値順・挿入順

  • safariは挿入順

  • 頭数値は文字列扱い


検証4

0とか00とか0絡むとどうなる?

var obj = {

'b': 'b',
'a': 'a',
'01': '01',
'00': '00',
'0': '0'
};
obj[1] = 1;


Node.js

console.log(Object.keys(obj));

// [ '0', '1', 'b', 'a', '01', '00' ]

console.log(JSON.stringify(obj));
// {"0":"0","1":1,"b":"b","a":"a","01":"01","00":"00"}


Chrome

console.log(Object.keys(obj));

// ["0", "1", "b", "a", "01", "00"]

console.log(JSON.stringify(obj));
// {"0":"0","1":1,"b":"b","a":"a","01":"01","00":"00"}


FireFox

console.log(Object.keys(obj));

// Array [ "0", "1", "b", "a", "01", "00" ]

console.log(JSON.stringify(obj));
// "{"0":"0","1":1,"b":"b","a":"a","01":"01","00":"00"}"


Safari

console.log(Object.keys(obj));

// ["b", "a", "01", "00", "0", "1"]

console.log(JSON.stringify(obj));
// {"b":"b","a":"a","01":"01","00":"00","0":"0","1":1}


結論


  • safari以外は数値順・挿入順

  • safariは挿入順

  • 0は数値、00は文字列


検証5

階層構造

var obj = {

a: {
3: '3',
2: 2,
1: '1'
},
2: {
c: 'c',
1: 1
}
};
obj[1] = '1';
obj[0] = {};


Node.js

console.log(Object.keys(obj));

// [ '0', '1', '2', 'a' ]

console.log(JSON.stringify(obj));
// {"0":{},"1":"1","2":{"1":1,"c":"c"},"a":{"1":"1","2":2,"3":"3"}}


Chrome

console.log(Object.keys(obj));

// ["0", "1", "2", "a"]

console.log(JSON.stringify(obj));
// {"0":{},"1":"1","2":{"1":1,"c":"c"},"a":{"1":"1","2":2,"3":"3"}}


FireFox

console.log(Object.keys(obj));

// Array [ "0", "1", "2", "a" ]

console.log(JSON.stringify(obj));
// "{"0":{},"1":"1","2":{"1":1,"c":"c"},"a":{"1":"1","2":2,"3":"3"}}"


Safari

console.log(Object.keys(obj));

// ["a", "2", "1", "0"]

console.log(JSON.stringify(obj));
// {"a":{"3":"3","2":2,"1":"1"},"2":{"c":"c","1":1},"1":"1","0":{}}


結果


  • safari以外は数値順・挿入順

  • safariは挿入順


検証6

「1000を堺に挙動がかわる」記事を発見したので調査


http://d.hatena.ne.jp/teramako/20140205/p1

var obj = {

'b': 'b',
'a': 'a',
'1000': '1000',
'999': '999',
2: '2'
};
obj[1001] = 1001;
obj[998] = 998;


Node.js

console.log(Object.keys(obj));

// [ '2', '998', '999', '1000', '1001', 'b', 'a' ]

console.log(JSON.stringify(obj));
// {"2":"2","998":998,"999":"999","1000":"1000","1001":1001,"b":"b","a":"a"}`


Chrome

console.log(Object.keys(obj));

// ["2", "998", "999", "1000", "1001", "b", "a"]

console.log(JSON.stringify(obj));
// {"2":"2","998":998,"999":"999","1000":"1000","1001":1001,"b":"b","a":"a"}


FireFox

console.log(Object.keys(obj));

// Array [ "b", "a", "1000", "999", "2", "1001", "998" ]

console.log(JSON.stringify(obj));
// "{"b":"b","a":"a","1000":"1000","999":"999","2":"2","1001":1001,"998":998}"


Safari

console.log(Object.keys(obj));

// ["b", "a", "1000", "999", "2", "1001", "998"]

console.log(JSON.stringify(obj));
// {"b":"b","a":"a","1000":"1000","999":"999","2":"2","1001":1001,"998":998}


結果


  • Node, Chromeは数値順・挿入順

  • FireFor, Safariは挿入順


検証7

途中から1000を超えるとどうなる? Firefox編

var obj = {

b: 'b',
a: 'a',
999: 999,
900: 900
};
obj[1] = '1';
obj[1000] = '1000!';
obj[998] = 998;
obj['1002'] = 1002;
obj[1001] = 1001;
obj[0] = 0;


FireFox

console.log(Object.keys(obj));

// Array [ "0", "1", "900", "998", "999", "1000", "1001", "1002", "b", "a" ]

console.log(JSON.stringify(obj));
// "{"0":0,"1":"1","900":900,"998":998,"999":999,"1000":"1000!","1001":1001,"1002":1002,"b":"b","a":"a"}"


結果


  • 数値順・挿入順…


検証8

検証7を全部初期値にすると… FireFox編

var obj = {

b: 'b',
a: 'a',
999: 999,
900: 900,
1: 1,
1000: '1000!',
998: 998,
'1002': 1002,
1001: 1001,
0: 0
};


FireFox

console.log(Object.keys(obj));

// Array [ "0", "1", "900", "998", "999", "1000", "1001", "1002", "b", "a" ]

console.log(JSON.stringify(obj));
// "{"0":0,"1":"1","900":900,"998":998,"999":999,"1000":"1000!","1001":1001,"1002":1002,"b":"b","a":"a"}"


結果


  • 数値順・挿入順…


検証9

ラスト!! FireFox編

var obj = {

b: 'b',
a: 'a',
1000: '1000!',
999: 999,
900: 900,
1: 1,
998: 998,
'1002': 1002,
1000: 1001,
0: 0
};


FireFox

console.log(Object.keys(obj));

// Array [ "b", "a", "1000", "999", "900", "1", "998", "1002", "1001", "0" ]
console.log(JSON.stringify(obj));
// "{"b":"b","a":"a","1000":"1000!","999":999,"900":900,"1":1,"998":998,"1002":1002,"1001":1001,"0":0}"


結果


  • 最初に挿入される数値が1000以上だと挿入順になる