JavaScript中关联数组中[]和{}的区别

4
现在要实现一个简单的数据库。 我认为这个问题的重复标签是错误的。链接的问题对我的需求没有任何帮助。 用户ID引用用户数据,我有两个选项:DB1DB2
var DB1 = {
    user: {}
};
var DB2 = {
    user: []
};

DB1.user['001'] = {
    email: 'name@email.com',
    name: 'ken'
};
DB2.user['001'] = {
    email: 'name@email.com',
    name: 'ken'
};

console.log(DB1.user['001']);
console.log(DB2.user['001']);

在这种情况下,DB1和DB2表现得完全相同,至少在我看来是这样的。

它们有什么区别?只是表达{}或[]的方式吗?

如果不同,哪一个更有效率?

感谢您的想法。

更新:

非常感谢所有友善详细回答我的人。

我可能明白了,在这种情况下,数组[]用于关联方式实际上是对象。

在这种情况下,它(与对象而非数组相同)的行为相同,好的,我知道了。

那么,我想知道的是,在这种情况下,它只是表达式[]和{}的区别吗?

更重要的是,在这种情况下,如果不仅仅是表达式,它们之间有何不同,哪一个更有效率,这就是我想知道的。谢谢。

更新2:

好的,这并不像许多人认为的那样显而易见。我编写了以下测试代码:

var DB1 = {
    user:
    {}
};
var DB2 = {
    user: []
};
var DB3 = {
    user: []
};

for (var i = 0; i < 100000; i++)
{
    var id = ('0000' + i)
        .slice(-5);

    DB1.user[id] = {
        email: 'name@email.com',
        name: 'ken'
    };

    DB2.user[id] = {
        email: 'name@email.com',
        name: 'ken'
    };

    DB3.user[i] = {
        email: 'name@email.com',
        name: 'ken'
    };

}
//confirm the value just in case
console.log(DB1.user['00000']);
console.log(DB1.user['00001']);
console.log(DB1.user['99999']);
console.log(DB1.user['100000']);

for (var t = 0; t < 10; t++)
{
    console.log('-----------test ' + t);
    console.time('DB1');
    for (var i = 0; i < 100000; i++)
    {
        var id = ('0000' + i)
            .slice(-5);

        var data = DB1.user[id];
    }
    console.timeEnd('DB1');

    console.time('DB2');
    for (var i = 0; i < 100000; i++)
    {
        var id = ('0000' + i)
            .slice(-5);

        var data = DB2.user[id];
    }
    console.timeEnd('DB2');


    console.time('DB3');
    for (var i = 0; i < 100000; i++)
    {
        var id = ('0000' + i)
            .slice(-5);

        var id1 = id * 1;
        var data = DB3.user[id1];
    }
    console.timeEnd('DB3');
}

结果:

{ email: 'name@email.com', name: 'ken' }
{ email: 'name@email.com', name: 'ken' }
{ email: 'name@email.com', name: 'ken' }
undefined

-----------test 0
DB1: 46ms
DB2: 68ms
DB3: 28ms
-----------test 1
DB1: 39ms
DB2: 33ms
DB3: 26ms
-----------test 2
DB1: 32ms
DB2: 39ms
DB3: 25ms
-----------test 3
DB1: 57ms
DB2: 33ms
DB3: 27ms
-----------test 4
DB1: 39ms
DB2: 35ms
DB3: 27ms
-----------test 5
DB1: 39ms
DB2: 32ms
DB3: 27ms
-----------test 6
DB1: 33ms
DB2: 36ms
DB3: 26ms
-----------test 7
DB1: 39ms
DB2: 41ms
DB3: 40ms
-----------test 8
DB1: 32ms
DB2: 32ms
DB3: 28ms
-----------test 9
DB1: 36ms
DB2: 31ms
DB3: 28ms

对于10万条记录,数组DB略微更快,但我认为我将使用关联数组风格的对象DB。


3
JS中没有关联数组,它们是对象。 - DanMan
可能是JavaScript中对象与数组的键/值对的重复问题。 - Sirko
1
{} 更高效。[] 是一个数组,它具有所有对象的好处以及数组的功能。 - reergymerej
1
我看到你没有得到任何关于效率的答案 - 关于效率,v8 JavaScript引擎实际上会将每个对象都视为数组!每个对象都有一个键/值存储和一个数组存储,它们存储编号属性,因此在Chrome / Node中,对象和数组都可以_以同样的效率_存储数组值(前提是数组不是稀疏的(即索引是数字和连续的)。顺便说一句 - 您的基准测试不正确,您应该考虑阅读有关如何计时代码的文章。 - Benjamin Gruenbaum
4个回答

7

[] 是数组字面量;它等同于new Array()

{} 是对象字面量;它等同于new Object()

如果你只是存储一些项,则应该只使用数组,否则请使用对象。


谢谢,我知道Array和Object的字面意思。我想知道的是在这种情况下它们之间的区别。你能告诉我为什么我只应该使用数组吗? - user1028880
非常抱歉,我没有找到任何人正确回答在这种情况下哪个“表达式”更有效。再次强调,我理解这里的数组/对象机制。在DB1和DB2中效率是否相同或不同。至少是一个是或否的问题。谢谢。 - user1028880

6
DB1和DB2都表现得完全一致,至少在我看来是这样的。
其实不然。在JavaScript中,[]表示数组,而{}表示对象。标准数组在JavaScript中并不是真正的数组,它们只是带有一些特殊行为的对象。你可以像操作其他对象那样添加非数组条目属性到数组对象中。在你的例子中,你没有将数组作为数组使用,所以两种方法都可以,但如果你将数组作为数组使用(使用数组索引、lengthpushsplice等),那么只有[]版本才能工作,因为只有它提供了一个真正的数组。

当你需要使用数组的功能时,请使用数组。当你只需要将名称映射到值时,请使用对象。如果使用数组,请确保使用真正的数组索引,而不是非索引属性名称,如'001'。关于此的详细信息请参阅下文。

以下是您未将数组作为数组使用的示例:

DB1.user['001'] = ...;

那并没有创建一个数组项。证明如下:
var a = [];
a['001'] = "foo";
console.log(a.length); // 0

它在对象上创建了一个名为"001"的属性,但该属性不是数组条目。相比之下:
a[1] = "foo";

或者

a['1'] = "foo";

...创建一个数组条目:

var a = [];
a[1] = "foo";
console.log(a.length); // 2 (see below)

为什么会有这种区别?标准数组只是带有特殊行为的对象。其中一个关键的特殊行为与某个属性名的类别有关,具体来说就是那些在正常数字形式下都是由数字组成的属性名(没有前导零)(尽管我们表现得像它们是数字,但它们仍然是字符串)。具有标准数字形式名称的属性(并且在范围内,允许从0到2的32次方-2,包括两端)是一个数组条目。
我一直在说“标准数组”,因为JavaScript正在引入“类型化数组”(实际上,它们已经在大多数引擎中存在):
var a = new Int32Array(10);

类型化数组是实际的数组,与 [] "数组"完全不同。


顺带一提:为什么这里的 length2

var a = [];
a[1] = "foo";
console.log(a.length); // 2

因为JavaScript数组本质上是稀疏的,并且我所说的其中一种特殊行为是,当你向一个数组添加符合数组条目定义的属性时,"length"会设置为最高编号的数组条目值加1。因此,即使我们的"a"数组只有一个条目,它的"length"也为2。
进一步的副注:在JavaScript中,对象不被称为"关联数组",这主要是PHP术语,用于描述它拥有的一种非常特殊的数据结构,即有序名称/值地图。在JavaScript中,我们称之为"对象"(主要),或者有时称之为"maps"或"dictionaries"。它们是无序的,不像PHP的关联数组。
更重要的是,在这种情况下,如果不仅仅是表达式,两种方法的差异以及哪种更有效率,这就是我想知道的。
由于您没有将数组用作数组,我预计对象版本会略微更有效率,因为引擎将根据您使用数组作为数组而进行初始优化,然后在您执行诸如“'001'”属性名称之类的操作时回退到对象行为。因此,最好从一开始就使用对象。
但总的来说,JavaScript "效率"是一个非常困难的话题。在一个引擎上有效的方法在其他引擎上可能无效。即使您不相信过早优化在其他领域是浪费时间,但在JavaScript中确实如此。显然不要做蠢事,但总的来说,等到出现性能问题,然后在出现问题的平台上解决该问题(然后测试您支持的其他平台,以确保您没有在那里引入新问题)。

@KenOKABE:我在回答中添加了一点内容。基本上,当你需要数组功能时,请使用数组。当您只需要将名称映射到值时,请使用对象。从问题中不清楚是否需要数组功能(pushlength等)。如果需要,请使用数组和正确的数组索引(而不是“'001'”);如果不需要,则只需使用对象。 - T.J. Crowder
非常抱歉,我没有找到任何人正确回答在这种情况下哪个“表达式”更有效。再次强调,我理解这里的数组/对象机制。在DB1和DB2中效率是否相同或不同。至少是一个是肯定的,一个是否定的问题。是的,我确实需要使用“001”,而不是数组方式的索引。谢谢。 - user1028880
@KenOKABE:“很抱歉没有人能够恰当地回答你的问题......” 没必要这么无礼。你的问题根本没有给人留下你真正理解 JavaScript 标准数组的印象。关于效率:我认为如果你不将数组用作数组,使用对象会更好,末尾附注原因。 - T.J. Crowder
T.J. Crowder,再次感谢您的建议。我已经为我的需求编写了一个测试代码并得出了结果。请参考。 - user1028880

2
user: {}

创建一个对象,而
user: []

创建一个数组。数组继承自Object,因此您可以像这样添加随机属性。
DB2.user['001'] = {..};

转换为数组。例如:

var myArray = [];
myArray["js"] = "awesome";
myArray.push("a");
myArray.push("b");
console.log(myArray);          // [ 'a', 'b', js: 'awesome' ]

非常抱歉,我没有找到任何人正确回答在这种情况下哪个“表达式”更有效。再次强调,我理解这里的数组/对象机制。在DB1和DB2中,效率是相同还是不同的?至少是一个是或否的问题。是的,我确实需要使用“001”,而不是数组索引方式。谢谢。 - user1028880
1
如果您已经知道键,那么使用 Object 是惯用的方式。但是,如果您想要维护数据的顺序,那么 Array 应该是您的选择。使用键访问值,在两者中的性能都相同,因为 Array 内部重用了许多 Object 的方法。 - thefourtheye
1
@thefourtheye:“使用键访问值,在两者中具有相同的性能,因为Array在内部重用了Object的许多方法。”只有当您使用非索引属性时,例如OP的“'001'”时才是如此。如果您将数组用作数组,并使用数组索引,则某些引擎会对其进行优化。 - T.J. Crowder
谢谢你再次的关注。我已经为我的需求编写了一个测试代码和结果,请查阅。 - user1028880

0

符号相同,但是你创建的是不同的对象。[]是一个数组,因此您将在原型中获得所有Array methods{}是一个对象,因此您将获得Object methods

对于您的情况,数组可能是最好的选择,因为它确保其元素的顺序。在对象中,没有保证顺序

如果您关心顺序,请使用数组[],否则请使用对象{}

效率测试

var i = 10000;
console.time('arr');
while (i--) {
    ([]);
}
console.timeEnd('arr');


i = 10000;
console.time('obj');
while (i--) {
    ({});
}
console.timeEnd('obj');

结果

数组:10.527毫秒
对象:8.974毫秒


非常抱歉,我没有找到任何人正确回答在这种情况下哪个“表达式”更有效。再次强调,我理解这里的数组/对象机制。在DB1和DB2中,效率是相同还是不同的?至少是一个是或否的问题。是的,我确实需要使用“001”,而不是数组索引方式。谢谢。 - user1028880
@KenOKABE 我添加了测试效率的代码。使用 {} 是更高效的表达式。 - reergymerej
1
@blurd 你的回答里有没有打错什么字? :) - thefourtheye
@KenOKABE 我假设你想要使用数组来创建数据库,因为它可以跟踪顺序。如果你*只关心效率,那么对象是最好的选择。 - reergymerej
@BenVoigt 这很尴尬。 :\ 谢谢。 - reergymerej
谢谢您再次关注。我已经为我的需求编写了一个测试代码和结果,请参考。 - user1028880

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接