Help us understand the problem. What is going on with this article?

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

More than 5 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以上だと挿入順になる
suguru03
Backend Developerです。 Aigle, Neo-Asyncなど高パフォーマンスのJavaScriptライブラリを公開してます。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away