最初のころはObjectの順序は保証されていないと思っていたのでまとめました。
Javascriptエンジン
今回検証する3つのエンジン
v8
- Node.js
- Chrome
SpiderMonkey
- FireFox
Nitoro
- Safari
結論
v8: Node.js, Chrome
- Objectの順序
- 数値順
- 挿入順
- 1aなど数字から始まる文字は文字列扱い
- 0は数値扱いで00は文字列扱い
SpiderMonkey: FireFox
- Objectの基本的な順序
- 数値順
- 挿入順
- 最初に挿入される数値が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以上だと挿入順になる