何时使用数组以及何时使用对象?

时间:2016-01-20 10:45:14

标签: javascript arrays javascript-objects

我最近读过很多关于对象和数组的文章,但由于某种原因,他们有相反的信息/事实。我需要你的帮助才能一劳永逸地学习:什么时候最好使用数组和什么时候对象?

明显的原因是当您需要特定订单时使用数组。还有什么?这个例子怎么样?

  • 有很多推动
  • 有很多检查数组是否包含
  • 有很多删除

请注意,此示例的数字要小得多,我需要(数千个)

我为这个问题写过的代码,除了这个问题,它几乎没有我做过的事情:

var x = [];
var y = [];
var z = [];

var clickedX = [];
var clickedY = [];
var clickedZ = [];

var count = 100;

for ( var a = 0; a < count; a++ ) {

    //For the sake of this example: random int 1, 2 or 3
    var type = Math.floor(Math.random() * 3) + 1;

    createDiv( type );
}


function createDiv( thisType ) {

    var self = this;
    var div = self.div;

    var type = thisType;

    if( !div ) {

        div = this.div = document.createElement( 'div' );
        div.className = 'marker';

        //Push to "right" array
        if( type == '1' ) {

            x.push( self );
        }
        else if ( type == '2' ) {

            y.push( self );
        }
        else {

            z.push( self );
        }

        //Attach click event
        div.onclick = function() {

            // X
            var indexX = x.indexOf( self );

            if( indexX > -1 ) { 

                //Push to new array
                clickedX.push( self );

                //Remove from old array
                x.splice( indexX, 1 );
            }

            // Y
            var indexY = y.indexOf( self );

            if( indexY > -1 ) { 

                //Push to new array
                clickedY.push( self );

                //Remove from old array
                y.splice( indexY, 1 );
            }

            // Z
            var indexZ = z.indexOf( self );

            if( indexZ > -1 ) { 

                //Push to new array
                clickedZ.push( self );

                //Remove from old array
                z.splice( indexZ, 1 );
            }
        }; // onclick
    } // if( !div )
} // createDiv()

我目前正在处理的数据示例:

// Data Im dealing with

objects = { 

    { objects1: [
                    0: { object : [4-5 assigned values (int, string, array)] }, 
                    1: { object : [4-5 assigned values (int, string, array)] },
                    //etc
                ] 
    }, 
    { objects2: [
                    0: {object}, 
                    1: {object},
                    //etc
                ] 
    } 
}

// 1. I need to iterate through every "object" in both "objects1" and "objects2"
// 2. I need to iterate through "array" in every "object" in "objects1"


for( /* "object" count in "objects1" */ ) {

    //Do something for each "object" in "objects1"

    for( /* items in "array" count */ ) {

        //Do something for each item in "array"
    }
}

// AND

for( /* "object" count in "objects2" */ ) {

    //Do something for each "object" in "objects2"
}

3 个答案:

答案 0 :(得分:4)

阵列

基本上,当您有一个后续数据列表时,您需要使用数组,并且您将使用它作为集合。

很容易添加迭代计算检查是否存在
删除数组中的项目很困难。

此外,它还存储订单 例如,如果你有10个整数,并且你需要找到最小值的索引,那么使用数组是合乎逻辑的。

物件

当你的物品有钥匙(特别是非整数)时,使用物品,你将逐一使用它们。

添加删除检查存在属性是否方便。 但是,迭代通过对象属性不太方便,并且绝对不适合获取其数量

也无法存储商品订单

时间复杂度

回答关于推送,检查存在和删除的问题:

  • 属性设置和数组推送都花费O(1)时间,但我坚信第一个有点慢
  • 检查是否存在需要相同的O(1)时间
  • 删除元素是不适合的数组 - 它需要移动所有项目并花费O(n)时间,而您可以删除O(1)的属性

错误的用法示例

有一些非常糟糕的用法。如果您有以下内容,那么您使用数组或对象错误。

  1. 为数组指定一个随机值:

    var a = [];
    a[1000] = 1;
    

    它会将数组的length属性更改为1001,如果您尝试输出此数组,则会得到以下内容:

    [undefined,undefined,undefined,undefined... 1]
    

    如果不是故意的话,这绝对没用。

  2. 为对象分配后续值

     var a = {};
    
     for (var i = 0; i < 10; i++)
     {
         a[i] = 1;
     }
    
  3. 您的代码

    谈论你的代码,有很多很多方法可以做到这一点 - 只需选择一个。我会用以下方式做到这一点:

    var items = [];
    
    for (var i = 0; i < count; i++)
    {
        var o = {
            type: Math.floor(Math.random() * 3) + 1,
            isClicked: false
        };
    
        var div = document.createElement('div');
        div.className = 'marker';
    
        div.onclick = function() {
            o.isClicked = true;
        };
    
        o.div = div;
        items.push(o);
    }
    
    function GetDivs(type, isClicked)
    {
        var result = items;
        if (type) 
            result = result.filter(function(x) { return x.type === type; });
        if (isClicked !== undefined) 
            result = result.filter(function(x) { return x.isClicked === isClicked; });
        return result;
    }
    

    然后,您将能够获得您想要的任何物品:

    var all = GetItems(0); // or even GetDivs()
    var allClicked = GetItems(0, true);
    var allNotClicked = GetItems(0, false);
    
    var divsTypeA = GetItems(1);
    var clickedDivsTypeB = GetItems(2, true);
    var notClickedDivsTypeC = GetItems(3, false);
    

    使用这种方法,您根本不需要删除任何项目 - 只需将它们标记为已点击或不点击,这需要花费O(1)时间。

    的jQuery

    如果使用jQuery和数据HTML属性,则根本不需要使用数组或对象:

    for (var i = 0; i < count; i++)
    {
        $('<div/>')
          .addClass('marker')
          .attr('data-type', Math.floor(Math.random() * 3) + 1)
          .appendTo('body')
          .click(function() {
              $(this).addClass('clicked');
          });
    }
    

    现在,您可以使用选择器查找任何项目:

    var all = $('.marker');
    var allClicked = $('.marker.clicked');
    var allNotClicked = $('.marker:not(.clicked)');
    
    var divsTypeA = $('.marker[data-type='1']');
    var clickedDivsTypeB = $('.marker[data-type='2'].clicked');
    var notClickedDivsTypeC = $('.marker[data-type='1']:not(.clicked)');
    

    但是,如果真的有数千条记录,最后一种方法可能会产生滞后。同时,在您的页面上拥有1000个动态div是一个好主意吗? :)

答案 1 :(得分:1)

当所有其他方法都失败时运行测试,再次取决于您打算使用数据结构的内容,一切都是权衡,性能||效率

准备好等待几秒钟才能完成测试。

&#13;
&#13;
function gimmeAHugeArray( length ){
  var arr = [];
  for( var ii = 0; ii < length; ii++ ){
    arr.push( (ii * 100000 ).toString(16) );
  }
  return arr;
}

function gimmeAHugeObject( length ){
  var obj = {};
  for( var ii = 0; ii < length; ii++ ){
    obj[ (ii * 100000 ).toString(16) ] = ii;
  }
  return obj;
}

var hugeArray = gimmeAHugeArray( 100000 );
var hugeObject = gimmeAHugeObject( 100000 );
var key = (8000 * 100000).toString(16);

console.perf(function arrayGetWithIndexOf(){
  var val = hugeArray.indexOf( key );
});

console.perf(function objectGetWithKey(){
  var val = hugeObject[ key ];
});

console.perf(function arrayIterateAllProperties(){
  var val = null;
  for( var ii = 0, ll = hugeArray.length; ii < ll; ii++ ){
    val = hugeArray[ii];
  }
}, 50);

console.perf(function objectIterateAllProperties(){
  var val = null,
      key;
  for( key in hugeObject ){
    val = hugeObject[ key ];
  }
}, 50);
&#13;
<script src="http://codepen.io/synthet1c/pen/WrQapG.js"></script>
&#13;
&#13;
&#13;

答案 2 :(得分:1)

我将从Solo上面的评论中回答你的问题。

问题是如果我需要同时使用相同的数据怎么办?

我发现最好的方法(至少对我而言)是创建一个可能有空节点的数组,但保留另一个数组来跟踪填充的id。

它看起来像这样:

var MyArray = function()
{
    this.storage = [];
    this.ids = [];
};

MyArray.prototype.set = function(id, value)
{
    this.storage[id] = value;
    this.ids[this.ids.length] = id;
};

MyArray.prototype.get = function(id)
{
    return this.storage[id];
};

MyArray.prototype.delete = function(id)
{
    delete this.storage[id];
};

这个解决方案适用于这两种方法,因为您可以在O(1)处删除任何内容,因为每个人都有一个给定的ID,并且您可以轻松地迭代它,因为您拥有存储值的所有ID。 / p>

我还为自己的用法创建了一个非常小的类,它表现得非常好。这是链接https://github.com/ImJustAskingDude/JavascriptFastArray。这是我问过这些问题的问题:Javascript Array Performance

请阅读我在那里写的内容,此解决方案适用于非常特殊的情况,我不确切知道它是否适用于您。

这就是为什么我要求你阅读我提供的那些链接中的内容,我写了大约10页的材料,尽管其中一些是纯粹的垃圾谈论什么都没有。无论如何,我也会在这里写下几个例子。

示例:

让我们假设您拥有来自数据库的数据,数据库中的数据几乎需要具有唯一的整数ID,但每个用户可能会将它们分布在很宽的范围内,它们最不可能是连续的。

因此,您将数据库中的数据转换为对象,如下所示:

var DBData /* well, probably something more descriptive than this stupid name */ = function(id, field1, field2, field3)
{
    this.id = id;
    this.field1 = field1;
    this.field2 = field2;
    this.fiedl3 = field3;
};

鉴于此类,您将数据库中的所有数据写入其中,并将其存储在MyArray中。

var data = new MyArray();

// YOU CAN USE THIS, OR JUST READ FROM DOM
$.get(/* get data from DB into MyArray instance */, function(data) { /* parse it somehow */ var dbdata = new DBData(/* fields that you parsed including ID */);  data.set(ID, dbdata)});

当你想迭代所有数据时,你可以这样做:

只需创建一个函数来创建一个新数组,它将所有数据放在一个很好的连续块中,它会是这样的:

    function hydrate(myarray, ids)
    {
        var result = [];

        var length = ids.length;

        if(!length)
        {
            return null;
        }

        var storage = myarray.storage;

        for(var i = 0; i < length; i++)
        {
            result[result.length] = storage[ids[i]];
        }

        return result;
    };

我使用这种方法,因为您可以使用它来非常容易地将任何对象配置选择为连续数组。

处理数组数组的一个解决方案就是修改MyArray来专门处理它,或者制作一个处理它的版本。

另一种解决方案是重新考虑您的方法,并且可能将所有数据添加到单个MyArray中,但是将所有数据添加到

objects1: [
                    0: { object : [4-5 assigned values (int, string, array)] }, 
                    1: { object : [4-5 assigned values (int, string, array)] },
                    //etc
                ] 
    }, 
    { objects2: [
                    0: {object}, 
                    1: {object},
                    //etc
                ] 
    } 

进入漂亮的物体。

严肃地说,阅读我在这些链接中所写的内容,我的理由就是那里的所有内容。