Objetos


Introducción

Vamos a conocer como es la estructura de objetos, parte básica y fundamental en javascript. Presta especial atención a esta sección ya que conociendo las formas básicas te ayudará a comprender rápidamente como funciona JavaScript.

Tabla de contenidos:

Los Objetos

Los tipos simples de JavaScript son números, cadenas, booleanos (true y false), null y undefined. Todos los demás valores son objetos. Los números, cadenas y valores booleanos son como objetos ya que tienen métodos, pero son inmutables. Los objetos en JavaScript son colecciones mutables por clave. En JavaScript, las matrices son objetos, las funciones son objetos, las expresiones regulares son objetos, y, por supuesto, los objetos son objetos.

Un objeto es un contenedor de propiedades, donde una propiedad tiene un nombre y un valor. El nombre de la propiedad puede ser cualquier cadena, incluyendo la cadena vacía. En JavaScript el valor de una propiedad puede ser cualquier valor con excepción de undefined.

Los objetos en JavaScript son de clase libre. No hay restricción en los nombres de nuevas propiedades o en los valores de las propiedades. Los objetos son útiles para la recopilación y organización de datos. Los objetos pueden contener otros objetos, por lo que pueden fácilmente representar estructuras de árboles o grafos.

JavaScript incluye una característica de vinculación de prototipos que permite que un objeto herede las propiedades de otro. Cuando esto se usa bien, puede reducir el tiempo de inicialización de objetos y el consumo de memoria.

Objetos Literales

Los objetos literales proporcionan una notación muy conveniente para la creación de nuevos valores del objetos. Un literal de objeto es un par de llaves que rodean a cero o más pares nombre/valor. Un objeto literal puede aparecer en cualquier lugar donde pueda aparecer una expresión:

var objeto_vacio = {};
var amigo = {
    "primer-nombre": "Carolina",
    segundo_nombre: "Sara",
    apellido: "Carames"
};

El nombre de la propiedad puede ser cualquier cadena de caracteres, incluyendo una cadena vacía. Las comillas en el nombre de la propiedad de un objeto literal son opcionales siempre que el nombre sea un nombre legal de JavaScript  y no una palabra reservada. Así que en el caso de "primer-nombre" se requieren comillas ya que no es un nombre legal por contener el signo - que separa las palabras, pero para segundo_nombre son opcionales debido a que el simbolo _ (guión bajo o subrayado) si esta permitido. Adicionalemnte y no menos importante es que las comas se utilizan para separar los pares. 

También se puede  obtener el valor de una propiedad de una expresión cualquiera, incluyendo otro objeto literal. También puedes anidar objetos:

var vuelo = {
    linea_aerea: "Oceanic",
    "número": 815,
    partida: {
        IATA: "SYD",
        hora: "2004-09-22 14:55",
        ciudad: "Sydney"
    },
    arribo: {
        IATA: "LAX",
        hora: "2004-09-23 10:42",
        ciudad: "Los Angeles"
    }
};

Recuperación

El valor de un objeto puede ser recuperado envolviendo una expresión de cadena en un sufijo [ ] . Si la expresión de cadena es una constante, y si se trata de un nombre legal de JavaScript y no una palabra reservada, entonces se puede utilizar la notación de punto ( . ) . Realmete prefiero la notación de punto .  porque es mas compacta y se lee mejor.

amigo["primer-nombre"];    // "Sara"
vuelo.partida.IATA         // "SYD"

 Se produce un valor undefined si se intenta recuperar un elemento inexistente: 

amigo["segundo-nombre"]      // undefined
vuelo.estado                 // undefined
amigo["PRIMER-NOMBRE"]       // undefined

Se puede utilizar el operador || para rellenar los valores por defecto:

var segundo_nombre = amigo["segundo-nombre"] || "(ninguno)";
var estado = vuelo.estado || "desconocido";

console.log( segundo_nombre );    // Retorna (ninguno)
console.log( estado );            // retorna desconocido

Si Intentas recuperar valores desde undefined se producirá una excepción TypeError. Puedes evitarlo con el operador &&:

vuelo.equipo                             // undefined
vuelo.equipo.modelo                      // throw "TypeError"
vuelo.equipo && vuelo.equipo.modelo      // undefined

Actualización

Puedes actualizar el valor de un objeto mediante una asignación. Si en el objeto ya existe el nombre de la propiedad, el valor de la propiedad es reemplazado:

amigo['primer-nombre'] = 'Sebastian';

Si en el objeto la propiedad no existe, el objeto es ampliado, añadiendo la propiedad asignada:

amigo['segundo-nombre'] = 'Diana';
amigo.seudonimo = 'Muñeca';
vuelo.equipo = {
    modelo: 'Boeing 777'
};
vuelo.estado = 'con retraso';

Referencia

Los Objetos que se pasan por referencia. Nunca se copian:

var x = amigo;
x.seudonimo = 'Carlos';
var alias = amigo.seudonimo;
    // alias es 'Carlos' porque x y amigo
    // estan referenciados al mismo objeto

var a = {}, b = {}, c = {};
    // a, b, and c cada uno se refiere a un
    // objeto vacio diferente

a = b = c = {};
    // a, b, and c todos se refieren
    // al mismo objeto vacio

Prototype

Cada objeto está vinculado a un objeto prototipo del que se puede heredar propiedades. Todos los objetos creados a partir de un objeto literal estan vinculados a un Object.prototype, el cual es un objeto estandar que viene  con JavaScript.

Cuando creamos un nuevo objeto, podemos seleccionar el objeto que debe ser el prototype. El mecanismo que JavaScript proporciona para hacer esto es complicado y complejo, pero se puede simplificar de manera significativa. Vamos a añadir un método crear para la función de MiObjeto.  El método crear crea un nuevo objeto que utiliza un objeto antiguo como su prototipo. Luego veremos un poco más de esto.

if (typeof MiObjeto.crear !== 'function') {

    MiObjeto.crear = function (o) {
        var F = function () {};
        F.prototype = o;
        return new F();
    };
}
var otro_amigo = MiObjeto.crear(amigo);

El enlace prototype no tiene ningún efecto sobre la actualización. Cuando en un objeto hacemos cambios  el prototype del objeto no se toca:

otro_amigo['primer-nombre'] = 'Pablo';
otro_amigo['segundo-nombre'] = 'David';
otro_amigo.seudonimo = 'Pavi';

El enlace prototype se utiliza sólo en la recuperación. Si tratamos de recuperar el valor de la propiedad de un objeto, y si el objeto carece del nombre de la propiedad, entonces JavaScript intenta recuperar el valor de la propiedad del objeto prototype. Y si ese objeto carece de la propiedad, entonces va a su prototipo, y así sucesivamente hasta que el proceso finalmente toque fondo con Object.prototype. Si la propiedad deseada no existe en ninguna parte de la cadena de prototipo, entonces el resultado es el valor undefined. Esto se llama delegación.

La relación prototipo es una relación dinámica. Si añadimos una nueva propiedad a prototype, esa propiedad será inmediatamente visible en todos los objetos que se basan en ese prototipo:

amigo.profesion = 'actor';
otro_amigo.profesion // 'actor'

Reflexión

Es fácil inspeccionar un objeto para determinar qué propiedades tiene he intentar recuperar las propiedades y examinar los valores obtenidos. El operador typeof puede ser muy útil para determinar el tipo de una propiedad:

typeof vuelo['número']     // 'number'
typeof vuelo.estado        // 'string'
typeof vuelo.arribo        // 'object'
typeof vuelo.manifiesto    // 'undefined'

A veces se debe tener cuidado, ya que cualquier propiedad en la cadena del prototype puede producir un valor:

typeof vuelo.toString      // 'function'
typeof vuelo.constructor   // 'function'

Hay dos enfoques para hacer frente a estas propiedades no deseadas. El primero es que tu programa busque y rechace los valores de la función. En general, cuando estás reflejando, estás interesado en los datos, por lo que debes tener en cuenta que algunos valores podrían ser funciones. 

El otro enfoque consiste en utilizar el método hasOwnProperty, que devuelve true si el objeto tiene una propiedad particular. El método hasOwnProperty no mira en la cadena prototype:

flight.hasOwnProperty('number')           // true
flight.hasOwnProperty('constructor')     // true

Enumeración

La sentencia for puede recorrer todos los nombres de las propiedades de un objeto. La enumeración incluirá todas las propiedades incluyendo funciones y propiedades del prototipo de las que podría no estar interesado Lo que es necesario para filtrar los valores que usted no desea. Los filtros más comunes son el método hasOwnProperty y usar typeof para excluir funciones:

var nombre;
for (nombre in otro_amigo) {
    if (typeof otro_amigo[nombre] !== 'function') {
        document.writeln(nombre + ': ' + otro_amigo[nombre]);
    }
}

No hay garantía en orden de como se presentan los nombres, así que prepárate para los nombres aparezcan en cualquier orden. Si deseas asegurarte de que las propiedades aparecen en un orden determinado, lo mejor es evitar la declaración en su totalidad y en su lugar crea una matriz que contiene los nombres de las propiedades en el orden correcto:

var i;
var propiedades = [
    'primer-nombre',
    'segundo-nombre',
    'apellido',
    'profesion'
];
for (i = 0; i < propiedades.length; i += 1) {
    document.writeln(propiedades[i] + ': ' +
        otro_amigo[propiedades[i]]);
    }
}

Al utilizar for en vez de for in, hemos sido capaces de obtener las propiedades que queríamos sin la preocupación de lo que podría haber sido quitado frente a la cadena del prototipo, y además los tenemos en el orden correcto.

Delete

El operador delete se puede utilizar para eliminar una propiedad de un objeto. Se eliminará una propiedad del objeto, si lo tiene. No va a tocar ninguno de los objetos de la vinculación prototipo.

La eliminación de una propiedad de un objeto puede permitir que una propiedad de vinculación del prototipo brille a través:

otro_amigo.seudonimo      // 'Sara'

// Elimina el seudonimo de otros_amigos, revelando
// el seudonimo del prototipo

delete otros_amigos.seudonimo;
otros_seudonimos.seudonimo;       // 'Sara'

Al utilizar for en vez de for in, hemos sido capaces de obtener las propiedades que queríamos sin la preocupación de lo que podría haber sido quitado frente a la cadena del prototipo, y además los tenemos en el orden correcto.

Reducción Global

JavaScript hace que sea fácil definir variables globales que pueden contener todos los activos de tu aplicación. Desafortunadamente, las variables globales debilitan la resistencia de los programas y se deben evitar.

Una forma de minimizar el uso de variables globales es crear una única variable global para su aplicación:

var MYAPP = {};

Entonces, esa variable se convierte en el contenedor para su aplicación:

MYAPP.amigos = {
    "primer-nombre": "Josue",
    "apellido": "Washington"
};

MYAPP.vuelo = {
    linea_aerea: "Oceanic",
    "número": 815,
    partida: {
        IATA: "SYD",
        hora: "2004-09-22 14:55",
        ciudad: "Sydney"
    },
    arribo: {
        IATA: "LAX",
        hora: "2004-09-23 10:42",
        ciudad: "Los Angeles"
    }
};

Al reducir su huella global a un solo nombre, se reduce significativamente la posibilidad de malas interacciones con otras aplicaciones, widgets, o bibliotecas. Tu programa también se hace más fácil de leer, porque es obvio que MYAPP.amigos se refiere a una estructura de nivel superior. En el otro apartado, veremos formas de utilizar el closure (Clausura) para ocultar la información, que es otra técnica de reducción global efectiva.

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.