JavaScript 数组如何在物理内存中表示?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20321047/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How are JavaScript arrays represented in physical memory?
提问by user3056052
It is my understanding that I can store mixed data in a JavaScript array, as well as change any element in the array to some other type. How does the interpreter keep track of what place in physical memory any element is at. Also how is the overwriting of the data in the next element prevented if I change an element to a larger data type.
我的理解是,我可以将混合数据存储在 JavaScript 数组中,也可以将数组中的任何元素更改为其他类型。解释器如何跟踪任何元素在物理内存中的位置。如果我将元素更改为更大的数据类型,如何防止下一个元素中的数据被覆盖。
I assume that arrays only store references to actual objects, and primitives are wrapped behind the scenes when placed in arrays.
我假设数组只存储对实际对象的引用,当放置在数组中时,基元被包装在幕后。
Assuming this is the case, If I have a different handle on the primitive variable and change the value stored in the array is synchronicity maintained?
假设是这种情况,如果我对原始变量有不同的句柄并更改存储在数组中的值是否保持同步?
I know I probably already answered my own question, but I don't know for sure and I can't find any information on the matter.
我知道我可能已经回答了我自己的问题,但我不确定,我找不到关于此事的任何信息。
回答by Nick
Normally, arrays allocate a contiguous block of memory of fixed length. However, in Javascript, arrays are Object types with special constructors and accessor methods.
通常,数组分配固定长度的连续内存块。但是,在 Javascript 中,数组是具有特殊构造函数和访问器方法的对象类型。
Which means, a statement like:
这意味着,像这样的语句:
var arr = new Array(100000);
does not allocate any memory! In fact, it simply sets the value of the length property in the array. When you construct an array, you don't need to declare a size as they grow automatically. So, you should use this instead:
不分配任何内存!实际上,它只是设置数组中的长度属性的值。构造数组时,不需要声明大小,因为它们会自动增长。所以,你应该改用这个:
var arr = [];
Arrays in Javascript are sparse which means not all the elements in the array may contain data. In other words, only the elements that actually contain data exist in the array. This reduces the amount of memory used by the array. The values are located by a key and not by an offset. They're simply a method of convenience and not intended to be used for complex numerical analysis.
Javascript 中的数组是稀疏的,这意味着并非数组中的所有元素都可能包含数据。换句话说,只有实际包含数据的元素存在于数组中。这减少了阵列使用的内存量。这些值由键而不是偏移量定位。它们只是一种方便的方法,并不打算用于复杂的数值分析。
Arrays in Javascript are not typed so the value of an element can be an object, string, number, boolean, function or an array. The main difference between an array and an object is the length property which has a value greater than the largest integer key in the array.
Javascript 中的数组没有类型化,因此元素的值可以是对象、字符串、数字、布尔值、函数或数组。数组和对象之间的主要区别在于长度属性的值大于数组中最大的整数键。
For example:
例如:
You could have an create an empty array and add two elements at index 0 and index 99. The length would be 100, but the number of elements in the array would be 2.
您可以创建一个空数组并在索引 0 和索引 99 处添加两个元素。长度为 100,但数组中的元素数为 2。
var arr = [];
arr[0] = 0;
arr[99] = {name: "John"};
console.log(arr.length); // prints 100
arr; // prints something like [0, undefined × 98, Object { name: "John"}]
To answer your questions directly:
直接回答您的问题:
Q. It is my understanding that I can store mixed data in a JavaScript array, as well as change any element in the array to some other type. How does the interpreter keep track of what place in physical memory any element is at? Also, how is the overwriting of the data in the next element prevented if I change an element to a larger data type?
A. You probably know this by now if you've read my comments above. In Javascript, an array is a Hashtable Object type so the interpreter doesn't need to keep track of physical memory and changing the value of an element doesn't affect other elements as they're not stored in a contiguous block of memory.
问:据我所知,我可以在 JavaScript 数组中存储混合数据,也可以将数组中的任何元素更改为其他类型。解释器如何跟踪任何元素在物理内存中的位置?另外,如果我将元素更改为更大的数据类型,如何防止覆盖下一个元素中的数据?
答:如果您已经阅读了我上面的评论,您现在可能已经知道了。在 Javascript 中,数组是 Hashtable 对象类型,因此解释器不需要跟踪物理内存,并且更改元素的值不会影响其他元素,因为它们没有存储在连续的内存块中。
--
——
Q. I assume that arrays only store references to actual objects, and primitives are wrapped behind the scenes when placed in arrays. Assuming this is the case, if I have a different handle on the primitive variable and change the value stored in the array is synchronicity maintained?
A. No, primitives are not wrapped. Changing a primitive that was assigned to an array will not change the value in the array as they're stored by value. Objects on the other hand are stored by reference, so changing the objects value will reflect that change in that array.
问:我假设数组只存储对实际对象的引用,当放置在数组中时,基元被包装在幕后。假设是这种情况,如果我对原始变量有不同的句柄并更改存储在数组中的值是否保持同步?
A. 不,原语没有被包装。更改分配给数组的原语不会更改数组中的值,因为它们是按值存储的。另一方面,对象是通过引用存储的,因此更改对象值将反映该数组中的更改。
Here's an example you can try:
这是您可以尝试的示例:
var arr = [];
var obj = { name: "John" };
var isBool = true;
arr.push(obj);
arr[1] = isBool;
console.log(arr[0]); // print obj.name
console.log(arr[1]); // print true
obj.age = 40; // add age to obj
isBool = false; // change value for isBool
console.log(arr[0]); // value here will contain age
console.log(arr[1]); // value here will still be true
Also, note that when you initialize an array in the following two ways, it has a different behavior:
另请注意,当您通过以下两种方式初始化数组时,它具有不同的行为:
var arr = new Array(100);
console.log(arr.length); // prints 100
console.log(arr); // prints []
var arr2 = new Array(100, 200);
console.log(arr2.length); // prints 2
console.log(arr2); // prints [100, 200]
If you want to use Javascript Arrays as contiguous blocks of memory, you should look into using TypedArray. TypedArray's allow you to allocate a block of memory as a byte array and access the raw binary data more efficiently.
如果您想使用 Javascript 数组作为连续的内存块,您应该考虑使用TypedArray。TypedArray 允许您将内存块分配为字节数组并更有效地访问原始二进制数据。
You can learn more about the intricacies of Javascript by reading the ECMA-262 spec (ver 5.1).
您可以通过阅读ECMA-262 规范(版本 5.1)来了解有关 Javascript 复杂性的更多信息。
回答by Michael Geary
Here is some food for thought. I made a jsperf to test a simple array optimizationthat some JavaScript engines implement.
这是一些值得深思的食物。我做了一个 jsperf 来测试一些 JavaScript 引擎实现的简单数组优化。
The test case creates two arrays with a million elements each. The a
array contains only numbers; the b
array contains the same numbers except for the first element which is an object:
测试用例创建两个数组,每个数组有一百万个元素。该a
数组仅包含数字;该b
数组包含除了它是一个对象的第一元件相同的数字:
var a = [ 0 ], b = [ { valueOf: function() { return 0; } } ];
for( var i = 1; i < 1000000; ++i ) {
a[i] = b[i] = i;
}
The valueOf
property of the object in the first element of the b
array returns 0
so the arithmetic will be the same as the first array.
数组valueOf
第一个元素中对象的属性b
返回,0
因此算术将与第一个数组相同。
Then the two tests simply sum all the values for the two arrays.
然后这两个测试简单地将两个数组的所有值相加。
Fast array:
快速阵列:
var x = 0;
for( var i = 0; i < 1000000; ++i ) {
x += a[i];
}
Slow array:
慢数组:
var x = 0;
for( var i = 0; i < 1000000; ++i ) {
x += b[i];
}
As you can see from the test results in the jsperf, in Chrome the numeric array is about 5x faster, in Firefox the numeric array is about 10x faster, and in IE it's about 2x faster.
从 jsperf 的测试结果中可以看出,在 Chrome 中,数值数组快了大约 5 倍,在 Firefox 中,数值数组快了大约 10 倍,而在 IE 中,它大约快了 2 倍。
This doesn't directly reveal the internal structures used for the array, but it gives a pretty good indication that the two are quite different from each other.
这并没有直接揭示用于数组的内部结构,但它很好地表明两者彼此完全不同。
回答by Jonas Wilms
The accepted answer says that
接受的答案说
[An array construction] does not allocate any memory!
【一个数组构造】不分配任何内存!
Thats not necessarily true. Storing arrays as unordered key-value pairs as in objects, is very inefficient as every lookup is a search. Even if the entries were sorted, it would still allocate more memory than needed. Therefore a lot of engines represent arrays in a few different ways to safe memory and optimize performance. That can also be seen in Michael Geary's example, the array that ony contains numbers gets optimized (details for V8). And sometimes the engine might decide to allocate some empty slots for a newly created array, if the underlying representation has a fixed size and can't be scaled that easily (e.g. an array list).
那不一定是真的。将数组存储为对象中的无序键值对是非常低效的,因为每次查找都是一次搜索。即使条目被排序,它仍然会分配比需要更多的内存。因此,许多引擎以几种不同的方式表示数组,以保护内存和优化性能。这也可以在 Michael Geary 的示例中看到,任何包含数字的数组都得到了优化(V8 的详细信息)。有时引擎可能会决定为新创建的数组分配一些空槽,如果底层表示具有固定大小并且不能那么容易地缩放(例如数组列表)。