Array


Introducción

Un array es una asignación de memoria lineal en el que los elementos son accesibles mediante números enteros que se utilizan para calcular los desplazamientos. Los arrays pueden ser estructuras de datos muy rapidas. Desafortunadamente, JavaScript no tiene nada parecido a este tipo de arrays.

En su lugar, JavaScript proporciona un objeto que tiene algunas características similares a los arrays. Convierte los subíndices de array en cadenas que se utilizan para hacer las propiedades. Es significativamente más lento que un array real, pero puede ser más fácil de utilizar. La recuperación y actualización de las propiedades funcionan igual que con objetos, con la diferencia de que hay un truco especial con los nombres de las propiedades de enteros. Los arrays tienen su propio formato literal. Los arrays también tienen un conjunto de métodos integrados que veremos más adelnate.

Literales de un Array

Los literales de array proporcionan una notación muy conveniente para la creación de nuevos valores del array. Un literal de array es un par de corchetes de cero o más valores separados por comas. Un literal de array puede aparecer en cualquier lugar donde una expresión pueda aparecer. El primer valor tendrá el nombre de la propiedad ' 0' , el segundo valor obtiene el nombre de la propiedad '1', y así sucesivamente:

var empty = [];
var numeros = [
        'cero', 'uno', 'dos', 'tres', 'cuatro',
        'cinco', 'seis', 'siete', 'ocho', 'nueve'
    ];

empty[1]       // undefined
numeros[1]     // 'uno'

empty.length      // 0
numeros.length    // 10

El literal del objeto:

var numeros_objeto = {
    '0':'zero', '1':'uno', '2':'dos',
    '3':'tres', '4':'cuatro', '5':'cinco',
    '6':'seis', '7':'siete', '8':'ocho',
    '9':'nueve'
};

produce un resultado similar. Ambos, números y numeros_objetos son objetos que contienen 10 propiedades, y esas propiedades tienen exactamente los mismos nombres y valores. Pero también hay diferencias significativas. Los numeros heredan de Array.prototype y, numeros_objetos heredan de Object.prototype, por lo que numeros heredan un conjunto más amplio de métodos útiles. Además, numeros obtienen la misteriosa propiedad length, mientras que numeros_objetos no lo hace.

En la mayoría de los lenguajes, los elementos de un array están obligados a ser del mismo tipo. JavaScript permite a un array contener cualquier mezcla de valores:

var diversidad = [
    'una cadena', 98.6, true, false, null, undefined,
    ['anidado', 'array'], {objeto: true}, NaN,
    Infinity
];

diversidad.length    // 10

Longitud

Cada array tiene una propiedad length. A diferencia de la mayoría de los demás lenguajes, la longitud de los arrays de JavaScript no son de un límite superior. Si deseas guardar un elemento con un subíndice que sea mayor o igual que la longitud actual, la longitud aumentará para contener el elemento nuevo. No hay error de límites en un array.

var miArray = [];
miArray.length    // 0

miArray[1000000] = true;
miArray.length             // 1000001
// miArray contiene una propiedad.

El operador subíndice postfijo [] convierte su expresión en una cadena mediante el método toString de la expresión si tiene uno. Esa cadena se utiliza como nombre de la propiedad. Si la cadena se parece a un número entero positivo que es mayor que o igual a la longitud actual del array y es menor que 4.294.967.295, entonces la longitud del array se ajusta al nuevo subíndice más uno. El valor de length puede ser establecido explícitamente. Haciendo que length tenga un valor mayor no asigna más espacio al array. Haciendo que length tenga un valor menor causará que todas las propiedades con un subíndice mayor o igual a la nueva longitud sean eliminados.

numeros.length = 3;
// numeros es ['cero', 'uno', 'dos'];

Un elemento nuevo se puede agregar al final de un array mediante la asignación a length actual del array:

numeros[numeros.length] = 'shi';
// numeros es ['cero', 'uno', 'dos', 'shi'];

A veces es más conveniente utilizar el método push para conseguir lo mismo:

numeros.push('andar');
// numeros es ['cero', 'uno', 'dos', 'shi', 'andar']

Delete

Dado que los arrays de JavaScript son realmente objetos, el operador delete puede ser utilizado para extraer elementos de un array:

delete numeros[2];
// numeros es ['cero', 'uno', undefined, 'shi', 'go']

Desafortunadamente, esto deja un agujero en la matriz. Esto se debe a que los elementos a la derecha del elemento eliminado conservan sus nombres originales. Que por lo general lo que se desea es reducir los nombres de cada uno de los elementos a la derecha.

Afortunadamente, los arrays en JavaScript tiene un método splice. Se puede realizar una cirugía en una matriz, eliminar algunos de los elementos y reemplazarlos con otros elementos. El primer argumento es un ordinal en la matriz. El segundo argumento es el número de elementos a eliminar. Cualquier argumento adicional se insertan en la matriz en ese momento:

numeros.splice(2,1);
// numeros es ['cero','uno','shi','go']

A la propiedad cuyo valor es "shi" se le ha ha cambiado su clave de ' 4' a ' 3 '. Debido a que a cada una de las propiedades después de la propiedad eliminada se le debe extraer e re-insertar una nueva clave, esto no podría ir rápidamente en arrays grandes.

Enumeración

Dado que los arrays de JavaScript son realmente objetos, la declaraciónen for in se puede utilizar para recorrer sobre todas las propiedades de un array. Por desgracia, fon in no da ninguna garantía sobre el orden de las propiedades, y la mayoría de las aplicaciones de arrays esperan que los elementos sean producidos en orden numérico. Además, todavía queda el problema con las propiedades inesperadas que se extraen de la cadena de prototipos.

Afortunadamente, la declaración convencional for evita estos problemas. La declaración for de JavaScript es similar al de la mayoría de los lenguajes de programación C. Es controlada por tres cláusulas—la primera inicializa el bucle, la segunda es la condición mientras, y la tercera el incremento:

var i;
for (i = 0; i< miArray.length; i +=1) {
    console.log(miArray[i]);
}

Confusión

Un error común en los programas de JavaScript es utilizar un objeto cuando se requiere un array o un array cuando se requiere un objeto. La regla es simple: cuando los nombres de propiedad son pequeños y son números enteros consecutivos, se debe utilizar un array. De lo contrario, utilizar un objeto.

Sí el propio JavaScript es confundido acerca de la diferencia entre arrays y objetos. El operador typeof informa que el tipo de una matriz es "objeto" , lo cual no es de mucha ayuda.

JavaScript no tiene un buen mecanismo para distinguir entre arrays y objetos. Podemos trabajar en torno a esta deficiencia, definiendo nuestras propias función is_array:

var is_array = function (valor) {
    return valor &&
        typeof valor === 'object' &&
        valor.constructor === Array;
};

Desafortunadamente, no logra identificar los arrays que se construyeron en un window o frame diferente. Si queremos detectar de forma precisa arrays extranjeros, tenemos que trabajar un poco más:

var is_array = function (valor) {
    return valor &&
        typeof valor === 'object' $$
        typeof valor.length === 'number' &&
        typeof valor.splice === 'function' &&
        !(valor.propertyIsEnumerable('length'));
};
  • En primer lugar, nos preguntamos si es un valor Truthy. Hacemos esto para rechazar los valores falsy, null y otros.
  • En segundo lugar, nos preguntamos si el valor typeof es un "object". Esto será true para objetos, arrays, y (extraños valores) null.
  • En tercer lugar, nos preguntamos si el valor tiene una propiedad length que es un número. Esto siempre será cierto para arrays, pero por lo general no para objetos.
  • En cuarto lugar, nos preguntamos si el valor contiene un método splice. De nuevo, esto será cierto para todos los arrays.
  • Por último, nos preguntamos si la propiedad length es enumerable (length será producido por un bucle for in?). Ese será false para todos los arrays.
  •  

Esta es la prueba más fiable para arrayness que he encontrado. Es una pena que sea tan complicado.

Tener una prueba de este tipo, es posible escribir funciones que hacen una cosa cuando se pasa un solo valor y un montón de cosas cuando se pasa un array de valores.

Métodos

JavaScript proporciona un conjunto de métodos para actuar sobre arrays. Los métodos son funciones almacenadas en Array.prototype. Anteriormente, vimos que Object.prototype puede ser aumentado. Array.prototype se puede aumentar también.

Por ejemplo, supongamos que queremos agregar un método array que nos permitirá hacer el cálculo de un array:

Array.method('reducir', function (f, valor) {
    var i;
    for(i = 0; i < this.length; i += 1) {
        valor = f(this[i], valor);
    }
    return valor;
});

Al añadir una función a Array.prototype, cada array hereda el método. En este caso, definimos el método reducir que toma una función y un valor inicial. Para cada elemento de la matriz, se llama a la función con un elemento y el valor, y calcula un nuevo valor. Cuando haya finalizado, devuelve el valor. Si pasamos una función que suma dos números, se calcula la suma. Si pasamos una función que multiplica dos números, se calcula el producto:

// Creamos un array de numeros.

var datos = [4, 8, 15, 16, 23, 42];

// Definimos dos funciones simples. Una de ellas agregará
// dos números. La otra multiplicará los números.

var agregar = function (a, b) {
    return a + b;
};

var multi = function (a, b) {
    return a * b;
};

// Invoco el métodos para reducir los datos,
// pasados en la función agregar

var sum = datos.reducir(agregar, 0);  // la suma es 108

// Invoco nuevamente el método para reducir, esta vez
// se pasa a la función de multiplicar

var product = datos.reducir(multi, 1); // producto es 7418880

Debido a que un array es realmente un objeto, podemos agregar métodos directamente a un array individual:

// Da al array datos una función total
datos.total = function () {
    return this.reducir(agregar, 0);
};

Dado que la cadena "total" no es un número entero, agregando una propiedad total a un array no cambia su longitud. Los arrays son más útiles cuando los nombres de las propiedades son números enteros, pero no dejan de ser objetos, y los objetos pueden aceptar cualquier cadena como el nombre de una propiedad.

No es útil utilizar el método Object.create en arrays, ya que produce un objeto, no una matriz. El objeto producido heredará los valores y los métodos del array, pero no va a tener la propiedad especial length.

Dimensiones

Los arrays de JavaScript por lo general no se inicializan. Si preguntas por un nuevo array con [], estará vacío. Si accedes a un elemento que falta, obtendrás el valor undefined. Si eres consciente de ello, o si quieres naturalmente establecer todos los elementos antes de intentar recuperarlos, entonces todo está bien. Pero si estas implementando un algoritmo que asume que cada elemento se inicia con un valor conocido (como 0), entonces tu mismo debes preparar la matriz. JavaScript debería proporcionar algún tipo de método Array.dim para hacer esto, pero podemos corregir fácilmente este descuido:

Array.dim = function (dimension, inicial) {
    var a = [], i;
    for(i = 0; i < dimension; i += 1) {
        a[i] = inicial;
    }
    return a;
};

// Crea un array que contiene 10 ceros.
var miArray = Array.dim (10, 0);

JavaScript no tiene arreglos de más de una dimensión, pero al igual que en la mayoría de los lenguajes de programación como C, pueden tener arrays de arrays:

var matriz = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8]
];
matriz[2][1] // 7

Para crear un array bidimensional o un array de arrays, debes construir los arrays ti mismo:

for (i = 0; i < n; i += 1) {
    mi_matriz[i] = [];
}
// Nota: Array.dim(n, []) no funcionará aquí.
// Cada elemento podría obtener una referencia al mismo
// array, lo que sería muy malo.

Las celdas de una matriz vacía inicialmente tendrá el valor undefined. Si queremos que tengan un valor inicial diferente, se debe establecer explícitamente. Una vez más, JavaScript debería haber proporcionado un mejor soporte para matrices. También podemos corregir esto:

Array.matriz = function (m, n, inicial) {
    var a, i, j, mat = [];
    for (i = 0; i < m; i +=1) {
        a = [];
        for (j = 0; j < n; j += 1) {
            a[j] = inicial;
        }
            mat[i] = a;
        }
        return mat;
};

// Crea una matriz de 4 * 4 rellenas de ceros.

var miMatriz = Array.matriz(4, 4, 0);

console.log(miMatriz[3][3]);  // 0

// Método para hacer una matriz de identidad.
Array.identidad = function (n) {
    var i, mat = Array.matriz(n, n, 0);
    for(i = 0; i < n; i +=1){
        mat[i][i] = 1;
    }
    return mat;
};

miMatriz = Array.identidad(4);
console.log(miMatriz[3][3]);   // 1

Añadir nuevo comentario

CAPTCHA
Esta pregunta es para comprobar si usted es un visitante humano y prevenir envíos de spam automatizado.
2 + 0 =
Resuelva este simple problema matemático y escriba la solución; por ejemplo: Para 1+3, escriba 4.