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


Tengo entendido que puedo almacenar datos mixtos en una matriz JavaScript, así como cambiar cualquier elemento en la matriz a algún otro tipo. Cómo hace el intérprete para realizar un seguimiento de qué lugar en la memoria física se encuentra cualquier elemento. También 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.

Asumo que los arrays solo almacenan referencias a objetos reales, y las primitivas se envuelven detrás de las escenas cuando se colocan en matriz.

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

Sé que probablemente ya respondí a mi propia pregunta, pero no lo sé con certeza y no puedo encontrar ninguna información sobre el asunto.

Author: user3056052, 2013-12-02

2 answers

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

Que significa, una declaración como:

var arr = new Array(100000);

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

var arr = [];

Matrices en Javascript son escasos, lo que significa que no todos los elementos de 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 se encuentran por una clave y no por un desplazamiento. Son simplemente un método de conveniencia y no están destinados a ser utilizados para el análisis numérico complejo.

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

Por ejemplo:

Puede crear una matriz vacía y agregar dos elementos en el índice 0 y el índice 99. La longitud sería 100, pero el número 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. Tengo entendido que puedo almacenar mezclas datos en una matriz JavaScript, así como cambiar cualquier elemento en la matriz a algún otro tipo. ¿Cómo realiza el intérprete el seguimiento de 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?

R. Probablemente ya lo sepas si has leído mis comentarios anteriores. 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 cambiar el valor de un elemento no afecta a otros elementos, ya que no se almacenan en un bloque de memoria contiguo.

--

P. Asumo que los arrays solo almacenan referencias a objetos reales, y las primitivas se envuelven detrás de escena cuando se colocan en arrays. Asumiendo que este es el caso, si tengo un manejador diferente en la variable primitiva y cambio el valor almacenado en la matriz ¿se mantiene la sincronicidad?

A. No, los primitivos no están envueltos. Cambiar una primitiva que fue asignada a una matriz no cambiará el valor de la matriz, ya que se almacenan por valor. Por otro lado, los objetos 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

También, 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 Javascript como bloques contiguos de memoria, usted debe mirar en el uso de TypedArray. TypedArray le permite asignar un bloque de memoria como una matriz de bytes y acceder a los datos binarios sin procesar de manera más eficiente.

Puede obtener más información sobre las complejidades de Javascript leyendo la especificación ECMA-262 (ver 5.1).

 28
Author: Nick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-07 19:51:28

Aquí hay algo para pensar. Hice un jsperf para probar una optimización de matriz simple que algunos motores JavaScript implementan.

El caso de prueba crea dos arrays con un millón de elementos cada uno. El array a contiene solo números; el array b contiene los mismos números excepto para el 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;
}

La propiedad valueOf del objeto en el primer elemento de la matriz b devuelve 0 por lo que la aritmética será la misma que la primera matriz.

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

Arreglo rápido:

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

Arreglo lento:

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

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

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
Author: Michael Geary,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-02 08:58:28