我最近读过很多关于对象和数组的文章,但由于某种原因,他们有相反的信息/事实。我需要你的帮助才能一劳永逸地学习:什么时候最好使用数组和什么时候对象?
明显的原因是当您需要特定订单时使用数组。还有什么?这个例子怎么样?
请注意,此示例的数字要小得多,我需要(数千个)。
我为这个问题写过的代码,除了这个问题,它几乎没有我做过的事情:
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"
}
答案 0 :(得分:4)
基本上,当您有一个后续数据列表时,您需要使用数组,并且您将使用它作为集合。
很容易添加,迭代,计算,检查是否存在。
删除数组中的项目很困难。
此外,它还存储订单 例如,如果你有10个整数,并且你需要找到最小值的索引,那么使用数组是合乎逻辑的。
当你的物品有钥匙(特别是非整数)时,使用物品,你将逐一使用它们。
添加,删除,检查存在属性是否方便。 但是,迭代通过对象属性不太方便,并且绝对不适合获取其数量。
也无法存储商品订单。
回答关于推送,检查存在和删除的问题:
有一些非常糟糕的用法。如果您有以下内容,那么您使用数组或对象错误。
为数组指定一个随机值:
var a = [];
a[1000] = 1;
它会将数组的length
属性更改为1001,如果您尝试输出此数组,则会得到以下内容:
[undefined,undefined,undefined,undefined... 1]
如果不是故意的话,这绝对没用。
为对象分配后续值
var a = {};
for (var i = 0; i < 10; i++)
{
a[i] = 1;
}
谈论你的代码,有很多很多方法可以做到这一点 - 只需选择一个。我会用以下方式做到这一点:
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和数据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)
当所有其他方法都失败时运行测试,再次取决于您打算使用数据结构的内容,一切都是权衡,性能||效率
准备好等待几秒钟才能完成测试。
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;
答案 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
]
}
进入漂亮的物体。
严肃地说,阅读我在这些链接中所写的内容,我的理由就是那里的所有内容。