简体   繁体   English

如何最好地使用非连续索引执行JavaScript数组?

[英]How best to do a JavaScript array with non-consecutive indexes?

I'm writing a Google Chrome extension, in JavaScript, and I want to use an array to store a bunch of objects, but I want the indexes to be specific non-consecutive ID numbers. 我正在使用JavaScript编写Google Chrome扩展程序,我想使用数组来存储一堆对象,但我希望索引是特定的非连续 ID号。

(This is because I need to be able to efficiently look up the values later, using an ID number that comes from another source outside my control.) (这是因为我需要能够使用来自我控制之外的其他来源的ID号来有效地查找值。)

For example: 例如:

var myObjects = [] ;

myObjects[471] = {foo: "bar"} ;

myObjects[3119] = {hello: "goodbye"}

When I do console.log(myObjects) , in the console I see the entire array printed out, with all the thousands of 'missing' indexes showing undefined . 当我执行console.log(myObjects) ,在控制台中我看到整个数组打印出来,所有数千个“缺失”索引显示undefined

My question is: does this matter? 我的问题是:这有关系吗? Is this wasting any memory? 这会浪费任何记忆吗?

And even if it's not wasting memory, surely whenever I loop over the array, it wastes CPU if I have to manually skip over every missing value? 即使它没有浪费内存,当我循环遍历数组时,如果我必须手动跳过每个缺失值,它会浪费CPU吗?

I tried using an object instead of an array, but it seems you can't use numbers as object keys. 我尝试使用对象而不是数组,但似乎你不能使用数字作为对象键。 I'm hoping there's a better way to achieve this? 我希望有更好的方法来实现这一目标吗?

First of all, everyone, please learn that what the for-in statement does is called enumeration (though it's an IterationStatement ) in order to differentiate from iteration . 首先,每个人,请了解for-in statement所做的是枚举 (尽管它是一个IterationStatement ),以区别于迭代 This is very important, because it leads to confusion especially among beginners. 这非常重要,因为它会导致特别是初学者之间的混淆。

To answer the OP's question: It doesn't take up more space ( test ) (you could say it's implementation dependent, but we're talking about a Google Chrome Extension! ), and it isn't slower either ( test ). 要回答OP的问题:它不占用更多的空间( 测试 )(你可以说它依赖于实现,但我们谈论的是谷歌Chrome扩展! ),它也不慢( 测试 )。

Yet my advice is: Use what's appropriate! 但我的建议是: 使用合适的东西! In this situation: use objects ! 在这种情况下:使用对象

What you want to do with them is clearly a hashing mechanism, keys are converted to strings anyway so you can safely use object for this task. 你想用它们做什么显然是一种散列机制,无论如何都要将键转换为字符串 ,这样你就可以安全地使用对象来完成这项任务。

I won't show you a lot of code, other answers do it already, I've just wanted to make things clear. 我不会向你展示很多代码,其他答案已经完成了,我只想说清楚。

// keys are converted to strings 
// (numbers can be used safely)
var obj = {}
obj[1] = "value"
alert(obj[1])   // "value"
alert(obj["1"]) // "value"

Note on sparse arrays 关于稀疏数组的注意事项

The main reason why a sparse array will NOT waste any space is because the specification doesn't say so. 稀疏数组不会浪费任何空间的主要原因是因为规范没有这么说。 There is no point where it would require property accessors to check if the internal [[Class]] property is an "Array" , and then create every element from 0 < i < len to be the value undefined etc. They just happen to be undefined when the toString method is iterating over the array. 没有必要要求属性访问器检查内部[[Class]]属性是否为“Array” ,然后创建0 <i <len中的每个元素为undefined的值等。它们恰好是当toString方法迭代数组时undefined It basically means they are not there . 它基本上意味着他们不存在

11.2.1 Property Accessors 11.2.1属性访问者

The production MemberExpression : MemberExpression [ Expression ] is evaluated as follows: 生成MemberExpressionMemberExpression [ Expression ]的计算方法如下:

  1. Let baseReference be the result of evaluating MemberExpression . baseReference成为评估MemberExpression的结果。
  2. Let baseValue be GetValue ( baseReference ). baseValueGetValuebaseReference )。
  3. Let propertyNameReference be the result of evaluating Expression . propertyNameReference是评估Expression的结果。
  4. Let propertyNameValue be GetValue ( propertyNameReference ). propertyNameValueGetValuepropertyNameReference )。
  5. Call CheckObjectCoercible ( baseValue ). 调用CheckObjectCoerciblebaseValue )。
  6. Let propertyNameString be ToString ( propertyNameValue ). propertyNameStringToStringpropertyNameValue )。
  7. If the syntactic production that is being evaluated is contained in strict mode code, let strict be true , else let strict be false . 如果正在评估的语法生成包含在严格模式代码中,则let stricttrue ,否则let strictfalse
  8. Return a value of type Reference whose base value is baseValue and whose referenced name is propertyNameString , and whose strict mode flag is strict . 返回类型为Reference的值,其基值为baseValue ,其引用名称为propertyNameString ,其严格模式标志为strict

The production CallExpression : CallExpression [ Expression ] is evaluated in exactly the same manner, except that the contained CallExpression is evaluated in step 1. 除了在步骤1中计算包含的CallExpression之外,生产CallExpressionCallExpression [ Expression ]的计算方式完全相同。

ECMA-262 5th Edition ( http://www.ecma-international.org/publications/standards/Ecma-262.htm ) ECMA-262第5版 http://www.ecma-international.org/publications/standards/Ecma-262.htm

You can simply use an object instead here, having keys as integers, like this: 你可以在这里简单地使用一个对象,将键作为整数,如下所示:

var myObjects = {};
myObjects[471] = {foo: "bar"};
myObjects[3119] = {hello: "goodbye"};

This allows you to store anything on the object, functions, etc. To enumerate (since it's an object now) over it you'll want a different syntax though, a for...in loop, like this: 这允许你在对象,函数等上存储任何东西。为了枚举(因为它现在是一个对象),你需要一个不同的语法,一个for...in循环,像这样:

for(var key in myObjects) {
  if(myObjects.hasOwnProperty(key)) {
    console.log("key: " + key, myObjects[key]);
  }
}

For your other specific questions: 对于您的其他具体问题:

My question is: does this matter? 我的问题是:这有关系吗? Is this wasting any memory? 这会浪费任何记忆吗?

Yes, it wastes a bit of memory for the allocation (more-so for iterating over it) - not much though, does it matter...that depends on how spaced out the keys are. 是的,它浪费了一些内存用于分配(更多 - 因此迭代它) - 虽然不多,但这很重要......这取决于密钥的间隔距离。

And even if it's not wasting memory, surely whenever I loop over the array, it wastes CPU if I have to manually skip over every missing value? 即使它没有浪费内存,当我循环遍历数组时,如果我必须手动跳过每个缺失值,它会浪费CPU吗?

Yup, extra cycles are used here. 是的,这里使用了额外的周期。

I tried using an object instead of an array, but it seems you can't use numbers as object keys. 我尝试使用对象而不是数组,但似乎你不能使用数字作为对象键。 I'm hoping there's a better way to achieve this? 我希望有更好的方法来实现这一目标吗?

Sure you can!, see above. 当然可以!,见上文。

I would use an object to store these. 我会使用一个对象来存储这些。 You can use numbers for properties using subscript notation but you can't using dot notation; 您可以使用下标表示法使用数字作为属性,但不能使用点表示法; the object passed as the key using subscript notation has toString() called on it. 使用下标表示法作为键传递的对象已经调用了toString()

var obj = {};
obj[471] = {foo: "bar"} ;

It would be implementation dependent, but I don't think you need to worry about wasted memory for the "in between" indices. 这将取决于实现,但我认为您不必担心“介于两者之间”索引的内存浪费。 The developer tools don't represent how the data is necessarily stored. 开发人员工具不代表数据必须如何存储。

Regarding iterating over them, yes, you would be iterating over everything in between when using a for loop. 关于迭代它们,是的,当你使用for循环时,你会迭代它们之间的所有东西。

If the sequential order isn't important, then definitely use a plain Object instead of an Array. 如果顺序顺序不重要,那么肯定使用普通的Object而不是Array。 And yes, you can use numeric names for the properties. 是的,您可以为属性使用数字名称。

var myObjects = {} ;

myObjects["471"] = {foo: "bar"} ;

myObjects["3119"] = {hello: "goodbye"};

Here I used Strings for the names since you said you were having trouble with the numbers. 在这里,我使用字符串作为名称,因为你说你的数字有问题。 They ultimately end up represented as strings when you loop anyway. 无论如何,当你循环时,它们最终会表示为字符串。

Now you'll use a for-in statement to iterate over the set, and you'll only get the properties you've defined. 现在,您将使用for-in语句迭代集合,并且您将只获得已定义的属性。


EDIT: 编辑:

With regard to console.log() displaying indices that shouldn't be there, here's an example of how easy it is to trick the developer tools into thinking you have an Array. 关于console.log()显示不应该存在的索引,这里有一个例子,说明欺骗开发人员工具认为你有一个数组是多么容易。

var someObj = {};

someObj.length = 11;
someObj.splice = function(){};

someObj[10] = 'val';

console.log(someObj);

Clearly this is an Object, but Firebug and the Chrome dev tools will display it as an Array with 11 members. 显然这是一个对象,但Firebug和Chrome开发工具会将其显示为一个包含11个成员的数组。

[undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, "val"]

So you can see that the console doesn't necessarily reflect how/what data is actually stored. 因此,您可以看到控制台不一定反映实际存储的数据/数据。

As I understand it from my reading of Crockford's "The Good Parts," this does not particularly waste memory, since javascript arrays are more like a special kind of key value collection than an actual array. 正如我从Crockford的“The Good Parts”中读到的那样,这并不特别浪费内存,因为javascript数组更像是一种特殊的键值集合,而不是实际的数组。 The array's length is defined not as the number of addresses in the actual array, but as the highest-numbered index in the array. 数组的长度不是定义为实际数组中的地址数,而是定义为数组中编号最大的索引。

But you are right that iterating through all possible values until you get to the array's length. 但你是正确的,迭代所有可能的值,直到你达到数组的长度。 Better to do as you mention, and use an object with numeric keys. 最好像你提到的那样做,并使用带有数字键的对象。 This is possible by using the syntax myObj['x']=y where x is the symbol for some integer. 这可以通过使用语法myObj['x']=y ,其中x是某个整数的符号。 eg myObj['5']=poodles Basically, convert your index to a string and you're fine to use it as an object key. 例如myObj['5']=poodles基本上,将索引转换为字符串,您可以将其用作对象键。

You could attempt to do something like this to make it loud and clear to the JIST compiler that this is a more objecty-ish array like so: 您可以尝试执行类似这样的操作,使JIST编译器大声清楚地知道这是一个更像对象的数组,如下所示:

    window.SparseArray = function(len){
      if (typeof len === 'number')
        if (0 <= len && len <= (-1>>>0))
          this.length = len;
        else
          new Array(len); // throws an Invalid array length type error
      else
        this.push.apply(this, arguments);
    }
    window.SparseArray.prototype = Array.prototype

I would simply use a constant prefix, to avoid such problems. 我只是使用一个常量前缀,以避免这样的问题。

var myObjects = {};
myObjects['objectId_'+365] = {test: 3};

will default to Js-Objects. 将默认为Js-Objects。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何从Javascript数组中选择非连续元素? - How to select non-consecutive elements from a Javascript array? Codewars Challenge - JavaScript - 找到数组中的第一个非连续数字 - Codewars Challenge - JavaScript - Find the first non-consecutive number in Array Javascript:使用非连续键迭代数组 - Javascript: Iterating over array with non-consecutive keys 用随机非连续数字填充数组 - Fill an array with random non-consecutive numbers 未排序数组中的最小非连续数 - Smallest non-consecutive number in unsorted array 如何在字符串中匹配两个不连续的单词以进行 React/Javascript 搜索? - How to match two non-consecutive words in a String for React/Javascript search? 如何从数组中删除重复的条目,同时保留非连续的重复项? - How to remove repeated entries from an array while preserving non-consecutive duplicates? 在未排序的数组中查找所有非连续数对 - Finding all pairs of non-consecutive number in unsorted array 正则表达式Javascript,用于匹配第一个特定字符之前的字母数字字符串中的5个非连续数字 - Regex Javascript for matching 5 non-consecutive numbers from an alphanumeric string before the first specific character 如何拒绝包含日期格式的非连续字符的字符串 - How can I reject a string containing non-consecutive characters in a date format
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM