Mostrando las entradas con la etiqueta Javascript. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Javascript. Mostrar todas las entradas

domingo, 7 de febrero de 2016

Create a nested array recursively in Javascript


Create a nested array recursively in Javascript


Let’s say you have an array like this:
[
    {id: 1, title: 'hello', parent: 0},
    {id: 2, title: 'hello', parent: 0},
    {id: 3, title: 'hello', parent: 1},
    {id: 4, title: 'hello', parent: 3},
    {id: 5, title: 'hello', parent: 4},
    {id: 6, title: 'hello', parent: 4},
    {id: 7, title: 'hello', parent: 3},
    {id: 8, title: 'hello', parent: 2}
]
And you want to have the objects nested like this:

[
    {id: 1, title: 'hello', parent: 0, children: [
        {id: 3, title: 'hello', parent: 1, children: [
            {id: 4, title: 'hello', parent: 3, children: [
                {id: 5, title: 'hello', parent: 4},
                {id: 6, title: 'hello', parent: 4}
            ]},
            {id: 7, title: 'hello', parent: 3}
        ]}
    ]},
    {id: 2, title: 'hello', parent: 0, children: [
        {id: 8, title: 'hello', parent: 2}
    ]}
]
Here’s a recursive function that makes it happen.
function getNestedChildren(arr, parent) {
    var out = []
    for(var i in arr) {
        if(arr[i].parent == parent) {
            var children = getNestedChildren(arr, arr[i].id)

            if(children.length) {
                arr[i].children = children
            }
            out.push(arr[i])
        }
    }
    return out
}
Example 
function buildTree(arr, parent) {
    var out = []
    for(var i in arr) {
        if(arr[i].control_padre_id === parent) {
            var children = buildTree(arr, arr[i].id)

            if(children.length) {
                arr[i].children = children
            }
            arr[i].is_active = Boolean(arr[i].is_active) ;

            out.push(arr[i])
        }
    }
    return out
} ;

var menu = buildTree(data, null) ;

 console.log(menu) ;
JSON : -> var data = [{"id":1,"control_padre_id":null,"jerarquia":"10","nombre":"Gesti\u00f3n de Informaci\u00f3n","valor":"","descripcion":"Gesti\u00f3n de Informaci\u00f3n","tipo_control_id":1,"glosa":"","is_active":"true"},{"id":2,"control_padre_id":1,"jerarquia":"1001","nombre":"Maestros","valor":"maestros","descripcion":"menu","tipo_control_id":2,"glosa":"","is_active":"true"},{"id":21,"control_padre_id":20,"jerarquia":"1001","nombre":"Maestros","valor":"maestros1","descripcion":"menu","tipo_control_id":2,"glosa":"","is_active":"true"},{"id":3,"control_padre_id":2,"jerarquia":"100101","nombre":"Personas","valor":"maestros.personas","descripcion":"sub menu","tipo_control_id":2,"glosa":"","is_active":"true"},{"id":22,"control_padre_id":21,"jerarquia":"100101","nombre":"Personas","valor":"maestros.personas1","descripcion":"sub menu","tipo_control_id":2,"glosa":"","is_active":"true"},{"id":4,"control_padre_id":3,"jerarquia":"10010101","nombre":"Listar","valor":"list","descripcion":"fa-list","tipo_control_id":3,"glosa":"","is_active":"true"},{"id":23,"control_padre_id":22,"jerarquia":"10010101","nombre":"Listar","valor":"list","descripcion":"fa-list","tipo_control_id":3,"glosa":"","is_active":"false"},{"id":5,"control_padre_id":3,"jerarquia":"10010102","nombre":"Nuevo","valor":"new","descripcion":"fa-plus","tipo_control_id":3,"glosa":"","is_active":"true"},{"id":24,"control_padre_id":22,"jerarquia":"10010102","nombre":"Nuevo","valor":"new","descripcion":"fa-plus","tipo_control_id":3,"glosa":"","is_active":"false"},{"id":6,"control_padre_id":3,"jerarquia":"10010103","nombre":"Editar","valor":"edit","descripcion":"fa-pencil-square-o","tipo_control_id":3,"glosa":"","is_active":"true"},{"id":25,"control_padre_id":22,"jerarquia":"10010103","nombre":"Editar","valor":"edit","descripcion":"fa-pencil-square-o","tipo_control_id":3,"glosa":"","is_active":"false"},{"id":8,"control_padre_id":1,"jerarquia":"1002","nombre":"Accesos","valor":"accesos","descripcion":"menu","tipo_control_id":2,"glosa":"","is_active":"false"},{"id":9,"control_padre_id":8,"jerarquia":"100201","nombre":"Roles","valor":"accesos.roles","descripcion":"sub menu","tipo_control_id":2,"glosa":"","is_active":"true"},{"id":10,"control_padre_id":9,"jerarquia":"10020101","nombre":"Listar","valor":"list","descripcion":"fa-list","tipo_control_id":3,"glosa":"inbarra","is_active":"true"},{"id":11,"control_padre_id":9,"jerarquia":"10020102","nombre":"Nuevo","valor":"new","descripcion":"fa-plus","tipo_control_id":3,"glosa":"inbarra","is_active":"true"},{"id":12,"control_padre_id":9,"jerarquia":"10020103","nombre":"Editar","valor":"edit","descripcion":"fa-pencil-square-o","tipo_control_id":3,"glosa":"intable","is_active":"true"},{"id":13,"control_padre_id":9,"jerarquia":"10020104","nombre":"Eliminar","valor":"delete","descripcion":"fa-trash-o","tipo_control_id":3,"glosa":"intable","is_active":"true"},{"id":14,"control_padre_id":8,"jerarquia":"100202","nombre":"Usuarios","valor":"accesos.usuarios","descripcion":"sub menu","tipo_control_id":2,"glosa":"","is_active":"true"},{"id":15,"control_padre_id":14,"jerarquia":"10020201","nombre":"Listar","valor":"list","descripcion":"fa-list","tipo_control_id":3,"glosa":"","is_active":"true"},{"id":16,"control_padre_id":14,"jerarquia":"10020202","nombre":"Nuevo","valor":"new","descripcion":"fa-plus","tipo_control_id":3,"glosa":"","is_active":"false"},{"id":17,"control_padre_id":14,"jerarquia":"10020203","nombre":"Editar","valor":"edit","descripcion":"fa-pencil-square-o","tipo_control_id":3,"glosa":"","is_active":"true"},{"id":18,"control_padre_id":14,"jerarquia":"10020204","nombre":"Eliminar","valor":"delete","descripcion":"fa-trash-o","tipo_control_id":3,"glosa":"","is_active":"true"},{"id":19,"control_padre_id":14,"jerarquia":"10020205","nombre":"accesos","valor":"access","descripcion":"fa-check-square-o","tipo_control_id":3,"glosa":"","is_active":"true"},{"id":20,"control_padre_id":null,"jerarquia":"20","nombre":"Reportes","valor":"","descripcion":"Gesti\u00f3n de Informaci\u00f3n","tipo_control_id":1,"glosa":"","is_active":"true"}] ;

jueves, 18 de junio de 2015

Obtener el primer y ultimo dia del mes actual

Obtener el primer y ultimo dia del mes actual
<script>

var date = new Date();
var primerDia = new Date(date.getFullYear(), date.getMonth(), 1);
var ultimoDia = new Date(date.getFullYear(), date.getMonth() + 1, 0);

document.write("<br>El primer día es: "+primerDia.getDate());
document.write("<br>El ultimo día es: "+ultimoDia.getDate());

</script>

viernes, 1 de mayo de 2015

El Patrón Módulo Javascript en Profundidad

Funciones anónimas auto-ejecutables.
Un patrón muy utilizado a la hora de escribir código JavaScript son las funciones anónimas auto-ejecutables.
La idea es la siguiente: aprovechar las propiedades de ámbito de las variables de JavaScript y el uso de clausuras para escribircódigo más limpio que no interfiera con otro código JavaScriptque pudiera haber en la página. De hecho es la técnica que utilizan muchas de las bibliotecas importantes para inicializarse.
Por ejemplo, consideremos el siguiente fragmento de código JavaScript:
var v1 = 0;

function miFunc1(){
 v1 = 5;
 alert(v1);
}

function miFunc2(){
 v1 = 10;
 alert(v1);
}
En este código tan sencillo estamos definiendo una variable y dos funciones. Dado que desde ambas funciones debemos poder acceder a la misma variable común "x", la declaramos de manera global, siendo accesible desde toda la página. Este código, si bien funcionará correctamente, tiene varios problemas, entre los que cabe destacar los dos siguientes:
  • La variable, siendo global, será accesible desde cualquier función de la página, no solo desde las dos que la necesitan y tampoco solo desde nuestras funciones. Otras funciones de otros scripts que incluyamos en la página también tendrán acceso.
  • Por mucho cuidado que tengamos, si los nombres de la variable o de las funciones coinciden con los de otras variables o funciones globales definidas en otro script, tendremos un conflicto y se producirán errores. Estamos polucionando innecesariamente el objeto global.
Lo que buscamos es la manera de poder definir funciones que compartan información entre sí, la almacenen para ejecución diferida y que no polucionen el código global de la página.
Obviamente podríamos definir una clase, la cual podríamos instanciar luego para ser utilizada. La clase nos permitiría definir miembros privados (aunque en JavaScript esto no es tan directo como en otros lenguajes) así como propiedades y métodos específicos de la misma. Posteriormente la instanciamos y hacemos uso de ella.
Eso puede estar bien en ocasiones, pero si el código es de un solo uso (como por ejemplo una inicialización) o son funciones que queremos usar de modo estático (sin instanciar nada explícitamente) estamos matando moscas a cañonazos. Y más teniendo en cuenta que en JavaScript la orientación a objetos no es tan sencilla y directa como en otros lenguajes.
Así que vamos a hacer un pequeño cambio en el código anterior y lo envolveremos con una cierta estructura, como se muestra a continuación:
(function (){
 var v1 = 0;

 function miFunc1(){
  v1 = 5;
  alert(v1);
 };

 function miFunc2(){
  v1 = 10;
  alert(v1);
 };
})();
¿Cómo? ¿Qué hemos hecho aquí? Vamos a verlo con calma.
El código es casi idéntico al anterior, pero en este caso lo hemos rodeado con unas llaves y una palabra clavefunction.
Nota: Fíjate además que para evitar problemas para distinguir cada instrucción de código, a las funciones originales se les añade un punto y coma al final, después de la última llave. No es indispensable pero ayuda mucho con la legibilidad del código y evita posibles problemas de interpretación.
Con esta sintaxis estamos definiendo una función anónima (no estamos indicando nombre alguna para ésta). Es como la definición de una función cualquiera, solo que sin nombre:
function () {....}
Además a esta función la rodeamos de paréntesis, con lo cual obtenemos una referencia a la misma (más sobre esto en breve), y posteriormente le colocamos dos paréntesis más, así:
(function (){....})();
¿Qué estamos haciendo? Los dos paréntesis finales se utilizan para llamar a la función anónima. En JavaScript una función se ejecuta cuando la llamamos usando los paréntesis. Sin paréntesis se obtiene una referencia a la misma. Por ejemplo:
var f1, f2;
f1 = miFuncion;
f2 = miFuncion();
Tras ejecutar este código, la variable f1 tendrá una referencia a la función miFuncion. La variable f2 sin embargo almacenará el valor devuelto por la función miFuncion tras su ejecución. La diferencia está en los paréntesis. De hecho podríamos llamar a la misma función escribiendo simplemente f1(); ya que f1 contiene una referencia a la función como he dicho.
Por lo tanto lo que hacemos con la estructura anterior es definir una función anónima y al mismo tiempo llamarla.
¡Con eso se crea, se ejecuta y desaparece!
De esta manera conseguimos que todo lo que hay dentro esté aislado del resto del código de la página. Mantiene su propia identidad pero no interfiere. En un ejemplo real, aparte de realizar posibles tareas de inicialización dentro, crearíamos probablemente algunos objetos especializados que expondríamos al exterior a través del objeto global, creando así clases de una sola instancia (Singleton), que además tendrían acceso a ciertos datos internos los cuales jamás interferirían con el resto del código tampoco.
¿Por qué hay que rodearla con paréntesis? ¿Funcionaría sin eso?
Vamos a probarlo: quitémosle los paréntesis que rodean a la definición de función y vamos a ver que pasa... Esto es lo que muestra la consola de los principales navegadores:
Error_Falta_Parentesis_Func_Anonima
Es decir, que todos generan un error de sintaxis, aunque el mensaje que devuelven es diferente y en general no resulta de mucha ayuda.
El problema estriba en que el intérprete del lenguaje no sabe cómo interpretar el código que tenemos escrito, ya que después de function siempre va el nombre de la función, salvo que esta sea anónima y por lo tanto la estemos asignando a alguna variable o la evaluemos. Por eso, si la rodeamos de paréntesis, estamos forzando a que se evalúe.
Pero esta no es la única forma de hacerlo, y de hecho verás por ahí código similar que en lugar de paréntesis utiliza cualquier otro operador que actúe sobre la función, ya que así se obliga a ejecutarla y obtener su resultado, por ejemplo:
!function (){....}();
o bien:
+function (){....}();
e incluso cosas mucho más peregrinas e innecesarias, como:
!+-~function (){....}();
que también funciona, pero son una tontería desde mi punto de vista.
A mi personalmente me parece que la forma más apropiada es la primera que he ilustrado, con los paréntesis, por que es clara, directa y no fuerza realizar operación adicional alguna, pero conviene reconocer otras formas por si las vemos por ahí.

Paso de parámetros de inicialización

Otra utilidad de uso muy común es pasarle parámetros de inicialización a la función, de modo que podamos referenciarlos desde la función anónima, modificarlos y mantener sus valores originales si son tipos por valor. Este patrón es muy común en algunas bibliotecas y de hecho jQuery lo ha utilizado durante muchos años para inicializarse:
(function (w){
 function miFunc1(){
  alert(w.document.title);
 };

 miFunc1();
})(window);
De este modo, por ejemplo, estamos pasando el objeto global como parámetro inicial y lo usamos desde dentro con un alias "w" que perdurará cuando llamemos a las diferentes funciones internas si las exponemos hacia el exterior. Además, pasando el objeto window de esta manera y almacenándolo en "w" estamos también ganando rendimiento. El motivo es que al estar definido en una variable local a las funciones que definamos dentro de la función anónima, el intérprete las encuentra antes y es mas eficiente en su uso. De hecho es muy habitual pasar como parámetro de inicialización otros objetos comunes como document, por ejemplo:
(function (w, d, undefined){
 function miFunc1(){
  alert(d.title);
 };

 miFunc1();
})(window, document);
Fíjate en un detalle importante en este código anterior. ¿Para qué es el parámetro undefined de la función anónima que además no se usa?
En JavaScript nada nos impide escribir código como el siguiente:
undefined = 1;
aunque undefined sea una palabra clave. Lo que hacemos es cambiar la definición de undefined y esto obviamente afecta al resto del código que estamos utilizando. ¿Por qué iba a hacer alguien esto? No lo sé, pero lo cierto es que ocurre (muchas veces incluso por error al hacer comparaciones erróneamente usando = (asignando) en lugar de == para comparar).
En las versiones modernas de los navegadores, que implementan ECMAScript 5 o posterior, la instrucción anterior no tiene efecto. Pero en navegadores antiguos como Internet Explorer 8 o anterior, sí que funciona y puede causar estragos (pruébalo con el modo de compatibilidad de las herramientas del desarrollador y verás que así es).
Por ello incluir un tercer parámetro de nombre undefined, el cual no se le pasa a la llamada de la función anónima (fíjate en que solo se le pasan 2), lo que hace en la práctica es definir una variable local /parámetro de la función que se llama undefined y nos aseguramos de que tendrá el valor de undefined siempre (salvo que se se haya redefinido antes, claro). Por eso mismo en código antiguo sobre todo lo verás utilizado así en muchas ocasiones y era considerado una buena práctica.

En resumen

En definitiva, con las funciones anónimas auto-ejecutadas conseguimos ejecutar código y definir funciones y propiedades aisladas del resto de los elementos de script de la página, evitando posibles interferencias. También nos permite entre otras cosas precargar valores para ejecución tardía, aislar variables y métodos para uso interno de nuestro código o definir bien las variables de contexto (this) sobre las que se va a ejecutar el mismo.
Además es la base de algunos patrones de diseño en JavaScript, siendo el más común el patrón Módulo, aunque también de otros como los patrones Singleton o Factoría.
En futuros artículos aquí o en campusMVP, usaré este patrón para generar el código de utilidades y le veremos más utilidad. En cualquier caso lo verás utilizado constantemente por ahí, así que es recomendable que lo conozcas.

http://www.jasoft.org/Blog/post/Escribiendo-codigo-JavaScript-limpio-funciones-anonimas-auto-ejecutables.aspx
http://www.etnassoft.com/2011/04/11/el-patron-de-modulo-en-javascript-en-profundidad/
http://www.etnassoft.com/2011/04/11/el-patron-de-modulo-en-javascript-en-profundidad/

lunes, 28 de abril de 2014

Javascript Orientado a Objetos.

Javascript Orientado a Objetos.

Si bien la mayoría de los desarrolladores utilizan a Javascript solamente a través de algunas funciones y no más que algunas llamadas durante ciertos eventos, lo cierto es que Javascript es mucho más que eso. Vamos a ser sinceros, no es un lenguaje orientado a objetos como los que estamos acostumbrados utilizar, con el concepto universalmente aceptado de "Clases" e "Instancias". En Javascript las cosas son un tantito diferentes.

Javascript fue originalmente concebido como un lenguaje de programación funcional, y no un lenguaje típicamente orientado a Objetos, porque vamos, modas son modas y en ese entonces estaban muy de moda los lenguajes al estilo C (C, C++, Java, el que prefieran). Esto causó dos modificaciones en el lenguaje. La aparición del concepto de Objeto - junto a la herencia prototípica-, y el operador "new".

Así, Javascript es muy confuso al comienzo para muchos desarrolladores, sobre todo aquellos que no han programado mucho, por pensar que están en un mundo, y en realidad se encuentran en otro. Pero comprendiendo solo un par de conceptos clave, se podrá entender mucho mejor este lenguaje.

Solo tengan en cuenta que este es un artículo inicial, que solo tocará varios de estos temas muy por encima y será necesario más investigación por parte del estudiante de este lenguaje, para comprender más profundamente estos conceptos.
Como nota aclaratoria, vamos a estar utilizando Javascript puro para los ejemplos, sin ningún agregado extra. O sea que si solo sabes utilizar jQuery (o alguna librería como ésta) y nunca has programado solamente en Javascript, esta es una buena oportunidad para que veas un poco más a fondo este lenguaje.


El Objeto Literal


Un Objeto, en Javascript, difiere respecto a otros lenguajes, a que no necesita ser la instancia de una Clase. Simplemente es una estructura de propiedades/valor. Nada más. Nada menos. Muy similar a un Array, solo que éste último solo acepta índices numéricos, cuando el Objeto en Javascript acepta "cadenas de texto" (strings) como claves. Y como valor, podemos asignar otras cadenas, números, constantes, funciones (aquí es donde comenzamos con el concepto de "método") y hasta otros objetos. Un objeto se puede declarar de varias maneras en Javascript. Vamos a ver la más simple de todas:
var circulo   = {};
circulo.radio = 9;
circulo.color = 'red';
Pero también podemos definir todos los valores de un Objeto de una manera más directa:
var circulo = {
    radio : 9,
    color : 'red'
}

Métodos


Cómo habíamos dicho, un Objeto puede contener como valor, una función o una referencia a una función. Como sabemos, en Javascript una función es un elemento de "primer nivel", o sea, pueden ser guardadas dentro de variables. Veamos como entra esto en juego cuando hablamos de Objetos guardando funciones.

function calcularArea(radio) {
    return radio * radio * Math.PI;
}

var circulo = {
    radio : 9,
    area : calcularArea(this.radio)
}

De esta manera, el objeto circulo posee un atributo llamado area que contiene el resultado de llamar a la función calcularArea. Esto es... guarda el RESULTADO de la función, pero no la función en si. Para que el objeto guarde la función, podemos hacer lo siguiente:

var circulo = {
    radio: 9,
    area : calcularArea,
}

Así, para conocer el área de nuestro Objeto Círculo, simplemente llamamos al método que acabamos de crear.

var area = circulo.area(circulo.radio);

¿No les suena que hay algo raro acá? Si definimos el método area como la referencia a una función, entonces, nuestro método no es más que una función global! No nos sirve tenerla de esta manera. Por eso, vamos a definir los métodos como realmente corresponde. Y aquí es donde entra el concepto de this.

var circulo = {
    radio : 9,
    area : function() {
        return this.radio * this.radio * Math.PI;
    }
}

¿Qué función tiene el operador this aquí? 

Imaginen a this como un parámetro implícito que se le pasa a cada función, indicando en su valor, al contexto en el que se encuentra la función. En este caso del ejemplo, this obtiene como valor una referencia el objeto circulo. Por eso cuando nos estamos refiriendo athis.radio Javascript sabe que no nos referimos a una variable radio global, sino a la que está definida dentro de this.


Cuando definimos una función global, como el calcularArea del ejemplo anterior, la variable thisapunta al contexto global, que es lo mismo que window. ¿Cómo pueden chequear esto rápidamente? Abran la consola de alguno de sus navegadores y escriban:

function test() {
    console.log(window == this);
}
test();

Un Objeto. Varias Instancias.


Cuando en Javascript creamos un objeto como hemos visto hasta ahora, no estamos hablando de una clase. Estamos hablando de un Objeto, listo, preparado para funcionar. Lo que en otros lenguajes llamaríamos una instancia. Pero esto no es del todo útil si queremos tener varias instancias de un mismo objeto al mismo tiempo. Así que aquí es donde entra en juego el operador new.

El operador new se aplica, por más que parezca extraño, sobre una función y no sobre un objeto. ¿Por qué?, se preguntarán. Básicamente, porque Javascript utilizará esta función en particular como constructor del Objeto que queremos instanciar, y nos devolverá un Objeto inicializado. Vamos a ver un ejemplo:

function Circulo() {}
var redondo = new Circulo();

Lo que estamos haciendo aquí es crear una instancia de un tipo nuevo de Objeto llamado Circulo, y asignándoselo a la variable redondo. Vamos un paso más allá:

function Circulo() {
    this.radio = 2;

    this.area = function() {
        return this.radio * this.radio * Math.PI;
    }
}

var redondo = new Circulo();
redondo.area() // devuelve 12.566370614359172

Aqui vemos nuevamente el uso de this para indicar que estamos con un contexto nuevo. En este caso this no representa al objeto window ya que estamos utilizando new. Ahora, this representa el contexto del Objeto Circulo que estaremos devolviendo y asignando a la variable. Así, podemos contar con distintas instancias aunque utilicen todas el mismo código de inicialización. Vamos con un ejemplo más completo donde paramos el parámetro radio:

function Circulo(radio) {
    this.radio = radio;

    this.area = function() {
        return this.radio * this.radio * Math.PI;
    }
}

c1 = new Circulo(3);
c2 = new Circulo(4);

c1.area() // devuelve 28.274333882308138
c2.area() // devuelve 50.26548245743669

Herencia. Prototype.


Una de las diferencias claves de Javascript con otros lenguajes de programación, es la manera en la que implementa la Herencia de Objetos. En Javascript se utiliza la Herencia Prototípica, y esto implica ciertas cosas:

* Un Objeto por defecto, siempre hereda sus métodos de otro Objeto, que se encuentra accesible a través del atributo prototype.
* Uno puede cambiar, en tiempo de definición, de qué tipo de Objeto se hereda.
* La Herencia prototípica es una cadena, si se hereda de un Objeto, a su vez éste heredará de otro objeto. Al final de la cadena, siempre se heredará del Objeto Object.

Volviendo con los ejemplos anteriores, vamos a extender nuestro Objeto circulo directamente modificando el Objeto prototype que hereda.

function Circulo(radio) {
    this.radio = radio;

    this.area = function() {
        return this.radio * this.radio * Math.PI;
    }
}

Circulo.prototype.diametro = function() {
    return this.radio * 2;
}

Circulo.prototype.circunferencia = function() {
    return Math.PI * this.diametro();
}

var circulo = new Circulo(3); 
circulo.area() // devuelve 28.274333882308138
circulo.diametro() // devuelve 6
circulo.circunferencia() // devuelve 18.84955592153876

De esta manera, pudimos modificar agregando dos nuevos métodos, diametro y circunferencia, tan solo modificando el objeto prototype. Pero si queremos que un objeto herede completamente los métodos de OTRO objeto, entonces la manera de llevar a cabo la herencia es reemplazando el objeto prototype por completo. Veamos esto en un ejemplo totalmetne distinto:

function humano() {
    this.ojos = 2;
    this.brazos = 2;
    this.alimentacion = "omnivoro";
}

function freddito() {
    this.alimentacion = "paleo";
    this.conocimiento = Infinity;
}

freddito.prototype = new humano();
var Freddier = new freddito();
console.log(Freddier.brazos); // devuelve 2
console.log(Freddier.alimentacion); // devuelve "paleo"

Composición de Objetos.


Para completar este repaso de cómo trabajar con Javascript orientado a objetos, un tema que no es menor, la composición de objetos.Ya sabemos como crear clases, dotándolas de atributos y métodos, como extender un objeto de otro, y como llegar a tener nuestra funcionalidad encapsulada. Pero aún nos queda ver cómo podemos hacer que los objetos trabajen juntos entre si. La manera en la que se crean estructuras de objetos y se trabaja con ellos se llama Composición y hay ciertos tipos pre-definidos.

Composición.
En este tipo de composición, el Objeto principal o "padre" es quién define o contiene los objetos internos o "hijos". Al eliminarse este objeto principal, los objetos internos no tienen sentido de existencia por si mismos, y son eliminados también. Un ejemplo de esto sería al decir El Objeto A tiene un Objeto de clase B.

function Tentaculo() {}

function Pulpo() {
    this.extremidades = [];

    for(var i = 1; i <= 8; i++) {
        this.extremidades.push(new Tentaculo());
    }
}

var pulpopaul = new Pulpo();
console.log(pulpopaul.extremidades);

Asociación.En la Asociación, se termina definiendo o componiendo un objeto utilizando otros objetos, pero con una relación distinta a la Composición. Aquí, al elminiarse uno de los Objetos, los demás aún mantienen un sentido y siguen su curso. Un ejemplo de esto sería decir El Objeto A usa un Objeto de tipo B.

function Profesor() {
    this.name = "Pablo Rigazzi";
}

function Curso (profesor) {
    this.profesor = profesor;

    this.saludar = function() {
        console.log("Hola alumnos, soy el profesor " + this.profesor.name);
    }
}

var yo = new Profesor();
var TeAmoJavascript = new Curso(yo);
TeAmoJavascript.saludar();

Polimorfismo.Si bien ya vimos ejemplos de esto en otros ejemplos de este mismo texto, ahora vamos a ponerle oficialmente un nombre. El Polimorfismo en un lenguaje orientado a objetos, nos ofrece la oportunidad de que distintos Objetos, puedan responder a métodos o atributos del mismo nombre, y por eso, puedan ser reemplazados por otros Objetos. En el caso del Polimorfismo, la manera más habitual de referirse es El Objeto A es un subtipo o clase de Objeto B.

En el siguiente ejemplo, vamos a crear dos Objetos, con una interfaz similar (los métodos que contienen) y veremos como pueden ser utilizados indistintamente, y Javascript reconoce perfectamente cuál tiene que utilizar en cada caso.

function expresarse( ser_vivo ) {
    ser_vivo.hablar();
}

function Gato()
{
    this.hablar = function() {
        var parasiempre = '';
        for(var i=0; i<1000; i++) {
            parasiempre += 'nyan';
        }
        console.log(parasiempre);
    }
}

function Humano()
{
    this.hablar = function() {
        console.log('Hola, soy un humano!');
    }
}

function Freddier()
{
    this.hablar = function() {
        console.log('Christian, contexto!');
    }
}

Freddier.prototype = new Humano();

Teniendo esta definición de clases, y gracias al Polimorfismo, el siguiente código es válido y se ejecuta correctamente:

var humano   = new Humano();
var freddito = new Freddier();
var nyancat  = new Gato();

expresarse(humano);
'Hola, soy un humano!'
expresarse(freddito);
"Christian, contexto!"
expresarse(nyancat);
Se imaginaran...

Información para uso personal