Pregunta ¿Cómo se representan las matrices de JavaScript en la memoria física?


Tengo entendido que puedo almacenar datos mezclados en una matriz de JavaScript, así como cambiar cualquier elemento de la matriz por otro tipo. ¿Cómo hace el intérprete para saber en qué lugar de la memoria física se encuentra cualquier elemento? Además, ¿cómo se evita la sobreescritura de los datos en el siguiente elemento si cambio un elemento a un tipo de datos más grande?

Supongo que las matrices solo almacenan referencias a objetos reales, y las primitivas se envuelven detrás de las escenas cuando se colocan en matrices.

Asumiendo que este es el caso, si tengo un manejo diferente en la variable primitiva y cambio el valor almacenado en la matriz ¿se mantiene la sincronización?

Sé que probablemente ya contesté mi propia pregunta, pero no estoy seguro y no puedo encontrar ninguna información sobre el asunto.


32
2017-12-02 04:47


origen


Respuestas:


Normalmente, las matrices asignan un bloque contiguo de memoria de longitud fija. Sin embargo, en Javascript, las matrices son tipos de Objetos con constructores especiales y métodos de acceso.

Lo que significa, una declaración como:

var arr = new Array(100000);

no asigna ninguna memoria! De hecho, simplemente establece el valor de la propiedad de longitud en la matriz. Cuando construyes una matriz, no necesitas declarar un tamaño a medida que crecen automáticamente. Por lo tanto, deberías usar esto en su lugar:

var arr = [];

Las matrices en Javascript son dispersas, lo que significa que no todos los elementos en la matriz pueden contener datos. En otras palabras, solo los elementos que realmente contienen datos existen en la matriz. Esto reduce la cantidad de memoria utilizada por la matriz. Los valores están ubicados por una clave y no por un desplazamiento. Simplemente son un método de conveniencia y no están destinados a ser utilizados para análisis numéricos complejos.

Las matrices en Javascript no están tipadas, por lo que el valor de un elemento puede ser un objeto, cadena, número, booleano, función o una matriz. La principal diferencia entre una matriz y un objeto es la propiedad de longitud que tiene un valor mayor que la clave entera más grande en la matriz.

Por ejemplo: 

Podrías crear una matriz vacía y agregar dos elementos en el índice 0 y el índice 99. La longitud sería 100, pero la cantidad de elementos en la matriz sería 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"}]

Para responder a sus preguntas directamente:

P. Entiendo que puedo almacenar datos mezclados en una matriz de JavaScript, así como también cambiar cualquier elemento de la matriz por otro tipo. ¿Cómo hace el intérprete para saber en qué lugar de la memoria física se encuentra cualquier elemento? Además, ¿cómo se evita la sobreescritura de los datos en el siguiente elemento si cambio un elemento a un tipo de datos más grande?

A. Probablemente ya sepas esto si has leído mis comentarios arriba. En Javascript, una matriz es un tipo de Objeto Hashtable por lo que el intérprete no necesita realizar un seguimiento de la memoria física y el cambio del valor de un elemento no afecta a otros elementos, ya que no están almacenados en un bloque contiguo de memoria.

-

P. Supongo que las matrices solo almacenan referencias a objetos reales, y las primitivas se envuelven detrás de las escenas cuando se colocan en matrices. Asumiendo que este es el caso, si tengo un manejo diferente en la variable primitiva y cambio el valor almacenado en la matriz ¿se mantiene la sincronización?

R. No, los primitivos no están envueltos. Cambiar una primitiva que se asignó a una matriz no cambiará el valor en la matriz, ya que se almacenan por valor. Los objetos, por otro lado, se almacenan por referencia, por lo que cambiar el valor de los objetos reflejará ese cambio en esa matriz.

Aquí hay un ejemplo que puedes probar:

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

Además, tenga en cuenta que cuando inicializa una matriz de las dos maneras siguientes, tiene un comportamiento diferente:

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]

Si desea utilizar matrices de Javascript como bloques contiguos de memoria, debe considerar el uso TypedArray. TypedArray le permite asignar un bloque de memoria como una matriz de bytes y acceder a los datos binarios en bruto de manera más eficiente.

Puede aprender más sobre las complejidades de Javascript leyendo el Especificaciones ECMA-262 (ver 5.1).


25
2017-12-02 08:08



He aquí algunos elementos de reflexión. hice un jsperf para probar una simple optimización de matriz que algunos motores de JavaScript implementan.

El caso de prueba crea dos matrices con un millón de elementos cada una. los a la matriz contiene solo números; el b array contiene los mismos números a excepción del primer elemento que es un objeto:

var a = [ 0 ], b = [ { valueOf: function() { return 0; } } ];
for( var i = 1;  i < 1000000;  ++i ) {
    a[i] = b[i] = i;
}

los valueOf propiedad del objeto en el primer elemento de la b retornos de matriz 0 entonces la aritmética será la misma que la primera matriz.

Entonces las dos pruebas simplemente suman todos los valores para las dos matrices.

Arreglo rápido:

var x = 0;
for( var i = 0;  i < 1000000;  ++i ) {
    x += a[i];
}

Matriz lenta:

var x = 0;
for( var i = 0;  i < 1000000;  ++i ) {
    x += b[i];
}

Como puede ver en los resultados de la prueba en jsperf, en Chrome la matriz numérica es aproximadamente 5 veces más rápida, en Firefox la matriz numérica es aproximadamente 10 veces más rápida, y en IE es aproximadamente 2 veces más rápida.

Esto no revela directamente las estructuras internas utilizadas para la matriz, pero da una indicación bastante buena de que las dos son bastante diferentes entre sí.


5
2017-12-02 08:58