这个问题看起来似乎微不足道,但是有些事情让我困扰了一段时间,所以我想我会问。如果这个问题对你来说很愚蠢/天真,请提前道歉。
因此,在JavaScript中,对象文字{}是引擎盖下的哈希表。这意味着它们具有接近恒定的时间查找和插入。所以我一直在想的问题是(除了方便之外)为什么我会使用JavaScript数组代替对象文字?
以JavaScript中创建队列为例;
1)首先,我们将使用Object文字作为我们的存储组件;
var Queue = function() {
this.storage = {};
this.order = [];
this.length = 0;
this.add = function(item) {
this.storage[item] = 1;
this.order.push(item);
this.length++;
};
this.remove = function() {
var removed = this.order.shift();
delete this.storage[removed];
this.length--;
return removed;
};
this.contains = function(value) {
return this.storage[value] ? true : false;
};
this.size = function() {
return this.length;
};
};
2)其次,使用数组作为我们的队列存储组件
var Queue2 = function() {
this.storage = [];
this.add = function(item) {
this.storage.push(item);
return this;
};
this.remove = function() {
return this.storage.shift();
};
this.contains = function(target) {
var clone = this.storage.slice(0);
clone.sort();
var recurse = function(low, high) {
if (high === low) return false;
var mid = Math.floor((high - low) / 2) + low;
if (clone[mid] === target) return true;
else if (clone[mid] > target)
return recurse(low, mid);
else if (clone[mid] < target)
return recurse(mid + 1, high);
};
return recurse(0, clone.length);
}
};
让我们创建两个独立的队列;
var objQueue = new Queue();
var arrayQueue = new Queue2();
现在我们可以为我们的队列添加100万个随机密码。
for (var i = 0; i < 1000000; i++) {
objQueue.add(Math.random().toString(36).slice(2));
}
for (var i = 0; i < 1000000; i++) {
arrayQueue.add(Math.random().toString(36).slice(2));
}
通常情况下,我们永远不必一次完成所有这些操作。但是,是的,它需要更长的时间才能填满我们的对象队列。我们必须在Queue构造函数中创建一个单独的数组来跟踪顺序。是的,这很烦人。不幸的是,当将键作为数字添加到JavaScript对象时,JavaScript会自动对数字键进行排序。因此,如果你添加4,然后是6,然后是2,那么1.对象将如下所示:
{ '1': 1, '2':1, '4':1, '6':1 }
对于队列,我们希望它看起来像这样:
{ '4': 1, '6':1, '2':1, '1':1 }
注意:添加字符串时不是这种情况。使用字符串时,会保留添加顺序,因此无需创建单独的数组来保留顺序。我不确定这是故意的还是只是一个错误?但在这种特殊情况下,由于我们正在创建一个队列和命令很重要,这很令人讨厌。在这种情况下,这可能是人们可能更喜欢使用阵列进行存储的原因之一。
从两个案例中删除队列将具有相同的时间复杂度,因为我们总是删除第一个值。那里没什么大不了的。
但是如果我们想要搜索我们的队列会发生什么?这可能违背了Queue应该用于什么的性质(是吗?我不知道,也许我们的队列是优先队列,我们已经厌倦了等待,我们想搜索我们的号码在队列中)但是我们只想说我们想要搜索我们创建的这个巨大的队列。
让我们在两个非随机队列的末尾添加一个值:
objQueue.add('bvflq9kk61xajor');
arrayQueue.add('bvflq9kk61xajor');
现在让我们在数组队列中搜索这个值并测量时间:
var start1 = new Date().getTime();
var result1 = arrayQueue.contains('bvflq9kk61xajor');
var end1 = new Date().getTime();
var time1 = end1 - start1;
现在让我们在对象队列中搜索这个值并测量时间:
var start2 = new Date().getTime();
var result2 = objQueue.contains('bvflq9kk61xajor');
var end2 = new Date().getTime();
var time2 = end2 - start2;
结果
console.log('Execution time for Array Queue: ' + time1);
console.log('RESULT:', result1);
//Execution time for Array Queue: **3873**
//RESULT: true
console.log('Execution time for Object Queue: ' + time2);
console.log('RESULT', result2);
//Execution time for Array Queue: **0**
//RESULT: true
阵列队列需要花费更长时间才能执行的主要原因是因为我必须在对它执行二进制搜索之前对其进行排序。二进制搜索速度很快,但需要对数组进行预排序。每次我向数组Queue添加一个新值时,我都可以对数组进行预排序,但这会破坏Queue的目的:FIFO(先进先出),然后我们开始运行相同的顺序我们对象的问题。
所以我想我真正想知道的问题是,当我们可以做大部分需要用JS对象做的事情时,为什么我们甚至不打扰数组呢?特别是当JS对象是哈希表时,我们接近它们的恒定时间查找。
我想如果你从来没有计划搜索你的数据那么重要,但事情是什么时候?当您用数据填充对象或数组时,您将不可避免地想要搜索您的数据?是?没有?我在这里完全错了吗?当你去搜索这些数据时,你会被引导将它存储在本质上是一个哈希表中。正确?
我在这里完全错了吗?遗漏了什么?会喜欢一些关于何时使用数组以及何时使用对象文字的反馈。我猜测一个案例就是你的数据集很小。