This page looks best with JavaScript enabled

¿Es Javascript orientado a objetos?

 ·  ☕ 16 min  ·  ✍️ eiximenis

Nota: Este post ha sido importado de mi blog de geeks.ms. Es posible que algo no se vea del todo "correctamente". En cualquier caso puedes acceder a la versión original aquí

Ayer tuve el placer de participar en un hangout de #JsIO junto a dos bestias pardas como Erick Ruiz y Tomás Corral discutiendo si JavaScript es o no es un lenguaje orientado a objetos.

Así que aprovecho para escribir este post y hacer algunas reflexiones más al respecto sin las prisas ni la improvisación del “directo”.

¿Qué es la orientación a objetos?

Es complicado definir que significa exactamente “orientación a objetos”. Seguro que si le preguntas a varia gente distinta obtendrás diferentes respuestas. Con puntos coincidentes, pero también puntos divergentes. Esto se debe a que el concepto es lo suficientemente vago como para admitir varias interpretaciones y además de que la gran mayoría de lenguajes no son 100% orientados a objetos.

Si yo hubiese de definir orientación a objetos diría básicamente que se trata de modelar el problema, y por lo tanto de diseñar un programa, basándose en la interacción entre distintos objetos que tienen determinadas propiedades y con los cuales se pueden realizar determinadas acciones. Los objetos tienen tres propiedades fundamentales:

  1. Comportamiento: Se define como “lo que es posible hacer con un objeto”. En terminología más purista, el conjunto de mensajes a los que este objeto responde (en OOP purista se usa la terminología mensaje para referirse al paso de información entre objetos).
  2. Estado: Los objetos tienen un estado en todo momento, definido por el conjunto de las variables o campos que contienen. El estado es pues la información contenida en un objeto.
  3. Identidad: Cada objeto existe independientemente del resto. Pueden haber dos objetos iguales pero no tienen porque ser el mismo (de igual forma que dos mellizos pueden ser idénticos, pero no por ello dejan de ser dos personas).

No iría mucho más allá, porque para mi esta definición contiene la clave que diferencia de la POO de la programación procedural: Los datos (estado) y funciones relacionadas (comportamiento) están agrupados en una sola entidad (objeto), en lugar de estar dispersos en el código. Es decir, el objeto encapsula los datos y el comportamiento. Como desarrollador debemos pensar en modelar nuestro sistema como un conjunto de objetos, en lugar de como un conjunto de funciones (procedimientos) invocadas una tras otra y pasándose datos más o menos arbitrarios para solucionar el problema.

El resto son detalles: herencia, polimorfismo, visibilidad… son detalles. No son menores, ciertamente, pero desde un punto de visto teórico, son meros detalles.

Y fíjate: he sido capaz de definir POO sin usar la palabra clase una sola vez. Y es que las clases son un mecanismo para implementar la POO, pero nada más. Y por supuesto, no son el único.

JavaScript tiene objetos, y estos objetos tienen comportamiento, estado e identidad. Así que desde punto de vista… Es orientado a objetos.

Pero como entiendo que esta respuesta puede no colmar a todos, especialmente a aquellos que vengan de Java, C# o algún otro lenguaje orientado a objetos “tradicional” (debería decir basado en clases) vayamos a ver como en JavaScript también tenemos esos detalles que mencionaba antes disponibles… 😉

¿Herencia en JavaScript?

Vale… Antes que nada: Si has aprendido POO con Java, C#, C++ o algún otro lenguaje basado en clases recuerda el concepto fundamental: No hay clases en JavaScript. Por lo tanto, hazte un favor y deja de pensar en clases cuando desarrolles en JavaScript. Te ahorrarás muchos dolores de cabeza.

La herencia en JavaScript es herencia entre objetos.

  • En un lenguaje basado en clases, la herencia es una relación definida entre clases. Si una clase Rectángulo deriva de la clase Figura, todos los objetos Rectángulo heredarán todo el comportamiento y estado definidos en la clase Figura.
  • En JavaScript la herencia es una relación definida entre objetos. Si un objeto deriva de otro, heredará todo el comportamiento y estado definido en el objeto base.

El mecanismo de herencia que se usa en JavaScript se conoce como herencia por prototipo y para resumirlo diré básicamente que cada objeto tiene asociado un prototipo. Si el desarrollador invoca un método sobre un objeto y este método NO está definido en el propio objeto, el motor de JavaScript buscará el método en el prototipo de este objeto. Por supuesto el prototipo es un objeto y puede tener otro prototipo y así sucesivamente, creando lo que se conoce como cadena de prototipado. La pregunta es pues como crear y asignar el prototipo de un objeto. Hay varias maneras de hacerlo, pero veamos una rápida y sencilla:

Herencia por prototipo (1)
<div style="background: #ddd; max-height: 300px; overflow: auto">
  <ol start="1" style="background: #1e1e1e; margin: 0 0 0 2em; padding: 0 0 0 5px; white-space: nowrap">
    <li>
      <span style="background:#1e1e1e;color:#569cd6">var</span><span style="background:#1e1e1e;color:#dcdcdc"> figura </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> {</span>
    </li>
    <li>
      <span style="background:#1e1e1e;color:#dcdcdc">    </span><span style="background:#1e1e1e;color:#dcdcdc">draw</span><span style="background:#1e1e1e;color:#b4b4b4">:</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">function</span><span style="background:#1e1e1e;color:#b4b4b4">()</span><span style="background:#1e1e1e;color:#dcdcdc"> {</span>
    </li>
    <li>
      <span style="background:#1e1e1e;color:#dcdcdc">        </span><span style="background:#1e1e1e;color:#dcdcdc">console</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">log</span><span style="background:#1e1e1e;color:#b4b4b4">(</span><span style="background:#1e1e1e;color:#d69d85">"figura::draw"</span><span style="background:#1e1e1e;color:#b4b4b4">);</span>
    </li>
    <li>
      <span style="background:#1e1e1e;color:#dcdcdc">    }</span>
    </li>
    <li>
      <span style="background:#1e1e1e;color:#dcdcdc">}</span><span style="background:#1e1e1e;color:#b4b4b4">;</span>
    </li>
    <li>
      <span style="background:#1e1e1e;color:#569cd6">var</span><span style="background:#1e1e1e;color:#dcdcdc"> rect </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> Object</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">create</span><span style="background:#1e1e1e;color:#b4b4b4">(</span><span style="background:#1e1e1e;color:#dcdcdc">figura</span><span style="background:#1e1e1e;color:#b4b4b4">);</span>
    </li>
    <li>
      <span style="background:#1e1e1e;color:#dcdcdc">rect</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">draw</span><span style="background:#1e1e1e;color:#b4b4b4">();</span>
    </li>
  </ol>
</div></p>

Si ejecutas este código, la salida por la consola es “figura::draw”. La clave es el método Object.create. Est
e método crea un objeto vacío cuyo prototipo es el objeto pasado por parámetro. Esta es una forma sencilla de tener herencia en JavaScript.

Igual te preguntas si el objeto rect puede sobreescribir la implementación de draw (si vienes de Java sabrás que una clase hija puede redefinir los métodos de su clase base; si vienes de C# sabrás eso mismo siempre que los métodos sean virtuales). La respuesta es claro que sí:

Redefinicion de metodos
<div style="background: #ddd; max-height: 300px; overflow: auto">
  <ol start="1" style="background: #1e1e1e; margin: 0 0 0 2.5em; padding: 0 0 0 5px; white-space: nowrap">
    <li>
      <span style="background:#1e1e1e;color:#569cd6">var</span><span style="background:#1e1e1e;color:#dcdcdc"> figura </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> {</span>
    </li>
    <li>
      <span style="background:#1e1e1e;color:#dcdcdc">    </span><span style="background:#1e1e1e;color:#dcdcdc">draw</span><span style="background:#1e1e1e;color:#b4b4b4">:</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">function</span><span style="background:#1e1e1e;color:#b4b4b4">()</span><span style="background:#1e1e1e;color:#dcdcdc"> {</span>
    </li>
    <li>
      <span style="background:#1e1e1e;color:#dcdcdc">        </span><span style="background:#1e1e1e;color:#dcdcdc">console</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">log</span><span style="background:#1e1e1e;color:#b4b4b4">(</span><span style="background:#1e1e1e;color:#d69d85">"figura::draw"</span><span style="background:#1e1e1e;color:#b4b4b4">);</span>
    </li>
    <li>
      <span style="background:#1e1e1e;color:#dcdcdc">    }</span>
    </li>
    <li>
      <span style="background:#1e1e1e;color:#dcdcdc">}</span><span style="background:#1e1e1e;color:#b4b4b4">;</span>
    </li>
    <li>
      <span style="background:#1e1e1e;color:#569cd6">var</span><span style="background:#1e1e1e;color:#dcdcdc"> rect </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> Object</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">create</span><span style="background:#1e1e1e;color:#b4b4b4">(</span><span style="background:#1e1e1e;color:#dcdcdc">figura</span><span style="background:#1e1e1e;color:#b4b4b4">);</span>
    </li>
    <li>
      <span style="background:#1e1e1e;color:#dcdcdc">rect</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">draw </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">function</span><span style="background:#1e1e1e;color:#b4b4b4">()</span><span style="background:#1e1e1e;color:#dcdcdc"> {</span>
    </li>
    <li>
      <span style="background:#1e1e1e;color:#dcdcdc">    console</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">log</span><span style="background:#1e1e1e;color:#b4b4b4">(</span><span style="background:#1e1e1e;color:#d69d85">"rect::draw"</span><span style="background:#1e1e1e;color:#b4b4b4">);</span>
    </li>
    <li>
      <span style="background:#1e1e1e;color:#dcdcdc">}</span><span style="background:#1e1e1e;color:#b4b4b4">;</span>
    </li>
    <li>
      <span style="background:#1e1e1e;color:#dcdcdc">rect</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">draw</span><span style="background:#1e1e1e;color:#b4b4b4">();</span>
    </li>
  </ol>
</div></p>

Ahora la salida por pantalla es “rect::draw”. ¿Qué ha sucedido? Pues como hemos llamado al método draw del objeto rect y este ya lo tiene definido, JavaScript ya lo invoca y no lo busca por la cadena de prototipos.

¿Lo ves? Herencia sin clases. ¡Es posible! 😉

¿Polimorfismo en JavaScript?

Una de las preguntas que salieron en el hangout fue si había polimorfismo en JavaScript. Respondí diciendo que esta pregunta implica una forma de pensar “basada en clases” pero que sí que era posible simular el polimorfismo en JavaScript.

Pero es que una de las claves es que no es necesario el concepto de polimorfismo en JavaScript. Antes que nada aclaremos que es el polimorfismo: La posibilidad de enviar un mismo mensaje (es decir, de invocar a un método) a varios objetos de naturaleza homogénea (wikipedia). Me gusta especialmente esta definición porque define polimorfismo sin usar la palabra “clase”. Si habéis aprendido POO con un lenguaje basado en clases quizá tenéis una definición de polimorfismo redactada de forma ligeramente distinta, algo como: Que los objetos de una clase derivada pueden tratarse como objetos de la clase base, pero manteniendo su comportamiento distintivo.

Supón que estás en un lenguaje basado en clases, como C#, y tienes la clase Figura y su derivada la clase Rect. La clase Figura define un método virtual llamado Draw() que es redefinido en la clase Rect. El polimorfismo implica que puedo pasar un objeto de la clase Rect a un método que acepte como parámetro un objeto de la clase Figura. Y que si este método llama al método Draw del parámetro Figura que ha recibido… se ejecutará el método Draw de la clase Rect, porque aunque el parámetro es de tipo Figura, el objeto real es de tipo Rect.

¿Y en JavaScript? Veamos:

Polimorfismo
<div style="background: #ddd; max-height: 300px; overflow: auto">
  <ol start="1" style="background: #1e1e1e; margin: 0 0 0 2.5em; padding: 0 0 0 5px; white-space: nowrap">
    <li>
      <span style="background:#1e1e1e;color:#569cd6">var</span><span style="background:#1e1e1e;color:#dcdcdc"> figura </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> {</span>
    </li>
    <li>
      <span style="background:#1e1e1e;color:#dcdcdc">    </span><span style="background:#1e1e1e;color:#dcdcdc">draw</span><span style="background:#1e1e1e;color:#b4b4b4">:</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">function</span><span style="background:#1e1e1e;color:#b4b4b4">()</span><span style="background:#1e1e1e;color:#dcdcdc"> {</span>
    </li>
    <li>
      <span style="background:#1e1e1e;color:#dcdcdc">        </span><span style="background:#1e1e1e;color:#dcdcdc">console</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">log</span><span style="background:#1e1e1e;color:#b4b4b4">(</span><span style="background:#1e1e1e;color:#d69d85">"figura::draw"</span><span style="background:#1e1e1e;color:#b4b4b4">);</span>
    </li>
    <li>
      <span style="background:#1e1e1e;color:#dcdcdc">    }</span>
    </li>
    <li>
      <span style="ba

ckground:#1e1e1e;color:#dcdcdc">};


  • var rect = Object.create(figura);


  • rect.draw = function() {


  •     console.log(“rect::draw”);


  • };


  •  


  • function Polimorfismo(figura) {


  •     figura.draw();


  • }


  •  


  • Polimorfismo(rect);


  • La función Polimorfismo llama al método draw() del objeto que recibe. Como lo paso el objeto rect lo que se ejecuta es el método draw del objeto rect. Por lo tanto… tenemos polimorfismo automático en JavaScript. De hecho JavaScript tiene una característica conocida como Duck Typing, que bueno… es dificil de definir, pero una manera de hacerlo es: “Si camina como un pato, grazna como un pato y luce como un pato… es un pato”. O dicho de otro modo: Para el método Polimorfismo lo único que importa del parámetro figura es que tenga un método draw(). Nada más. Por lo tanto cualquier objeto que tenga un método draw es válido para ser usado como parámetro del método Polimorfismo.

    El Duck Typing se suele asociar a los lenguajes dinámicos… pero no es exclusivo de ellos. Java y C# (sin usar dynamic) no tienen Duck Typing, pero p. ej. C++ lo ofrece a través de los templates.

    ¿Clases en JavaScript?

    A esta altura del post ya debes tener claro que no. JavaScript no tiene clases, solo objetos y relaciones entre objetos. Pero existe un método de crear objetos a través de una función constructora y la palabra clave new que se parece mucho a como se hace en un lenguaje basado en clases. Eso que a priori es buena idea, ha ayudado mucho a la confusión de JavaScript… ¿Uso new para crear objetos pero no hay clases? ¿Y eso?

    Déjame mostrarte un trozo de código de como crear un objeto basado en función constructora y el uso de new:

    Funciones constructoras y new
    <div style="background: #ddd; max-height: 300px; overflow: auto">
      <ol start="1" style="background: #1e1e1e; margin: 0 0 0 2.5em; padding: 0 0 0 5px; white-space: nowrap">
        <li>
          <span style="background:#1e1e1e;color:#569cd6">var</span><span style="background:#1e1e1e;color:#dcdcdc"> Figura </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">function</span><span style="background:#1e1e1e;color:#b4b4b4">()</span><span style="background:#1e1e1e;color:#dcdcdc"> {</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    </span><span style="background:#1e1e1e;color:#569cd6">this</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">draw </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">function</span><span style="background:#1e1e1e;color:#b4b4b4">()</span><span style="background:#1e1e1e;color:#dcdcdc"> {</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">        console</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">log</span><span style="background:#1e1e1e;color:#b4b4b4">(</span><span style="background:#1e1e1e;color:#d69d85">"Figura::draw"</span><span style="background:#1e1e1e;color:#b4b4b4">);</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    }</span><span style="background:#1e1e1e;color:#b4b4b4">;</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">}</span><span style="background:#1e1e1e;color:#b4b4b4">;</span>
        </li>
        <li>
          &nbsp;
        </li>
        <li>
          <span style="background:#1e1e1e;color:#569cd6">var</span><span style="background:#1e1e1e;color:#dcdcdc"> figura </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">new</span><span style="background:#1e1e1e;color:#dcdcdc"> Figura</span><span style="background:#1e1e1e;color:#b4b4b4">();</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#569cd6">var</span><span style="background:#1e1e1e;color:#dcdcdc"> rect </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> Object</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">create</span><span style="background:#1e1e1e;color:#b4b4b4">(</span><span style="background:#1e1e1e;color:#dcdcdc">figura</span><span style="background:#1e1e1e;color:#b4b4b4">);</span>
        </li>
        <li>
          &nbsp;
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">rect</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">draw</span><span style="background:#1e1e1e;color:#b4b4b4">();</span>
        </li>
      </ol>
    </div></p>
    

    Ahora la variable Figura no es nada más que una función. Pero un tipo especial de función que llamamos función constructora. Pero ¡ojo! lo que convierte Figura en una función constructora no es nada que defina la propia función. Es como se invoca. Es el hecho de usar new lo que convierte Figura en una función constructora. El uso de
    new implica varias cosillas, cuyo ámbito se escapa de este post, pero la norma básica es que es la forma para invocar funciones cuya funcionalidad es crear objetos. En este ejemplo pues tengo:

    • Figura: Función que sirve para construir objetos que tienen un método draw.
    • figura (con la f minúscula): Objeto creado a partir de Figura
    • rect: Objeto cuyo prototipo es el objeto figura.

    Lo interesante de usar funciones constructoras es que todos los objetos creados a través de ellas comparten el mismo prototipo. Si tenemos:

    1. var figura = new Figura();
    2. var figura2 = new Figura();

    Ambos objetos comparten el mismo prototipo. Si ahora quiero añadir un método, p.ej. clear() que esté disponible para todos los objetos creados a partir de la función constructora Figura puedo añadirlo al prototipo. Y como hago esto? Pues así:

    1. var Figura = function() {
    2.     this.draw = function() {
    3.         console.log("Figura::draw");
    4.     };
    5. };
    6.  
    7. var figura = new Figura();
    8. var figura2 = new Figura();
    9.  
    10. Figura.prototype.clear = function() {
    11.     console.log("Figura::clear");
    12. };
    13.  
    14. var rect = Object.create(figura);
    15.  
    16. figura.clear();
    17. figura2.clear();
    18. rect.clear();

    Figura.prototype es el nombre del prototipo de todos los objetos creados a través de new Figura. Este codigo imprime tres veces “Figura::clear”. Fíjate que funciona incluso cuando el método clear ha sido añadido al prototipo después de crear figura y figura2. Y es interesante el caso del objeto rect. Que ocurre cuando hacemos rect.clear()?

    • JavaScript bu
      sca el método clear() en el objeto rect. No lo encuentra y
    • Busca el método en el prototipo de rect que es figura. No lo encuentra y
    • Busca el método en el prototipo de figura que es Figura.prototype. Lo encuentra y lo ejecuta.

    Aquí tienes a la cadena de prototipado en acción.

    Fíjate que seguimos teniendo tan solo objetos. Figura no es una clase. Figura es una función. Una función para crear objetos que comparten un prototipo. Nada más.

    ¿Variables privadas en JavaScript?

    JavaScript no incorpora de serie ningún mecanismo de visibilidad para los miembros de un objeto. Todo es público por defecto. Pero por supuesto no hay nada que no podamos conseguir… 🙂

    Visibilidades en JavaScript
    <div style="background: #ddd; max-height: 300px; overflow: auto">
      <ol start="1" style="background: #1e1e1e; margin: 0 0 0 2.5em; padding: 0 0 0 5px; white-space: nowrap">
        <li>
          <span style="background:#1e1e1e;color:#569cd6">var</span><span style="background:#1e1e1e;color:#dcdcdc"> Figura </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">function</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#b4b4b4">(</span><span style="background:#1e1e1e;color:#dcdcdc">c</span><span style="background:#1e1e1e;color:#b4b4b4">,</span><span style="background:#1e1e1e;color:#dcdcdc"> stroke</span><span style="background:#1e1e1e;color:#b4b4b4">)</span><span style="background:#1e1e1e;color:#dcdcdc"> {</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    </span><span style="background:#1e1e1e;color:#57a64a">// Variable privada</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    </span><span style="background:#1e1e1e;color:#569cd6">var</span><span style="background:#1e1e1e;color:#dcdcdc"> _color </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> c</span><span style="background:#1e1e1e;color:#b4b4b4">;</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    </span><span style="background:#1e1e1e;color:#57a64a">// Variable pblica</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    </span><span style="background:#1e1e1e;color:#569cd6">this</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">stroke </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">null</span><span style="background:#1e1e1e;color:#b4b4b4">;</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    </span><span style="background:#1e1e1e;color:#57a64a">// Necesario para poder acceder</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    </span><span style="background:#1e1e1e;color:#57a64a">// a this desde los mtodos privados</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    </span><span style="background:#1e1e1e;color:#569cd6">var</span><span style="background:#1e1e1e;color:#dcdcdc"> self </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">this</span><span style="background:#1e1e1e;color:#b4b4b4">;</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    </span><span style="background:#1e1e1e;color:#57a64a">// Mtodo privado</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    </span><span style="background:#1e1e1e;color:#569cd6">var</span><span style="background:#1e1e1e;color:#dcdcdc"> _setup </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">function</span><span style="background:#1e1e1e;color:#b4b4b4">(</span><span style="background:#1e1e1e;color:#dcdcdc">s</span><span style="background:#1e1e1e;color:#b4b4b4">)</span><span style="background:#1e1e1e;color:#dcdcdc"> {</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">        </span><span style="background:#1e1e1e;color:#57a64a">// Ah podemos acceder a mtodos pblicos</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">        </span><span style="background:#1e1e1e;color:#57a64a">// a travs de self. Y a los privados directamente</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">        self</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">stroke </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> s</span><span style="background:#1e1e1e;color:#b4b4b4">;</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    }</span><span style="background:#1e1e1e;color:#b4b4b4">;</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    _setup</span><span style="background:#1e1e1e;color:#b4b4b4">(</span><span style="background:#1e1e1e;color:#dcdcdc">stroke</span><span style="background:#1e1e1e;color:#b4b4b4">);</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    </span><span style="background:#1e1e1e;color:#57a64a">// Mtodos pblicos</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    </span><span style="background:#1e1e1e;color:#569cd6">this</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">draw </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">function</span><span style="background:#1e1e1e;color:#b4b4b4">()</span><span style="background:#1e1e1e;color:#dcdcdc"> {</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">        console</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">log</span><span style="background:#1e1e1e;color:#b4b4b4">(</span><span style="background:#1e1e1e;color:#d69d85">"Figura::draw in color "</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#b4b4b4">+</span><span style="background:#1e1e1e;color:#dcdcdc"> _color  </span><span style="background:#1e1e1e;color:#b4b4b4">+</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#d69d85">" and stroke "</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#b4b4b4">+</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">this</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">stroke </span><span style="background:#1e1e1e;color:#b4b4b4">);</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    }</span><span style="background:#1e1e1e;color:#b4b4b4">;</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    </span><span style="background:#1e1e1e;color:#569cd6">this</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">getColor </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span
    

    style=“background:#1e1e1e;color:#dcdcdc”> function() {


  •         return _color;


  •     };


  • };


  •  


  •  


  • var f = new Figura(“red”, “thin”);


  • console.log(f._color); // undefined


  • console.log(f.getColor()); // red


  • console.log(f.stroke); // thin


  • //f._setup(“thick”);  // Error: Object has no method _setup


  •  


  • var f2 = new Figura(“blue”,“thick”);


  • console.log(f2._color); // undefined


  • console.log(f2.getColor()); // blue


  • console.log(f2.stroke); // thick


  • //f._setup(“thick”);  // Error: Object has no method _setup


  • f.draw();


  • f2.draw();


  • Este ejemplo muestra como definir métodos y variables privadas. ¡Hay otras técnicas y alternativas!

    Básicamente la regla es:

    ¿Herencia múltiple en JavaScript?

    Si vienes de C# o Java igual alzas una ceja ahora… ¿No era peligrosa la herencia múltiple? C# y Java no incorporan este concepto debido a su posible peligrosidad y porque muchas veces da más problemas de los que puede solucionar. El peligro de la herencia múltiple es conocido como el problema de la herencia en diamante. Todos los lenguajes que soportan herencia múltiple se deben enfrentar a este problema, así que para evitarlo algunos lenguajes como Java o C# han decidido prescindir de ella.

    JavaScript no soporta por defecto herencia múltiple p
    ero si que soporta un tipo especial de herencia múltiple llamada mixin. Con los mixins ya entramos en un terreno pantanoso si vienes de C# o Java puesto que estos dos lenguajes no soportan este concepto.

    Resumiendo, un Mixin es una clase que está pensada para ser incorporada dentro de otra clase ofreciendo funcionalidad adicional. Es como si tuvieras 3 clases A, B y C y las “combinases” todas ellas en una clase D (que además añadiría su propia funcionalidad). Algunos lenguajes como Lisp o Python soportan Mixins nativamente. Otros como C++ no, pero pueden imitarlos fácilmente debido al soporte de herencia múltiple (del que el uso de mixins es un tipo específico). Usar mixins en Java o C# es realmente complicado (aunque en Java8 el uso de default methods en interfaces lo hace posible). Si estás interesado en Mixins y C# echa un vistazo a heredar de José F. Romaniello.

    ¿Y como usar Mixins en C#? Aquí tienes un ejemplo:

    Mixins
    <div style="background: #ddd; max-height: 300px; overflow: auto">
      <ol start="1" style="background: #1e1e1e; margin: 0 0 0 2.5em; padding: 0 0 0 5px; white-space: nowrap">
        <li>
          <span style="background:#1e1e1e;color:#569cd6">var</span><span style="background:#1e1e1e;color:#dcdcdc"> asCircle </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">function</span><span style="background:#1e1e1e;color:#b4b4b4">()</span><span style="background:#1e1e1e;color:#dcdcdc"> {</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    </span><span style="background:#1e1e1e;color:#569cd6">this</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">area </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">function</span><span style="background:#1e1e1e;color:#b4b4b4">()</span><span style="background:#1e1e1e;color:#dcdcdc"> {</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">        </span><span style="background:#1e1e1e;color:#569cd6">return</span><span style="background:#1e1e1e;color:#dcdcdc"> Math</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">PI </span><span style="background:#1e1e1e;color:#b4b4b4">*</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">this</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">radius </span><span style="background:#1e1e1e;color:#b4b4b4">*</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">this</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">radius</span><span style="background:#1e1e1e;color:#b4b4b4">;</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    }</span><span style="background:#1e1e1e;color:#b4b4b4">;</span>
        </li>
        <li>
          &nbsp;
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    </span><span style="background:#1e1e1e;color:#569cd6">return</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">this</span><span style="background:#1e1e1e;color:#b4b4b4">;</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">}</span><span style="background:#1e1e1e;color:#b4b4b4">;</span>
        </li>
        <li>
          &nbsp;
        </li>
        <li>
          <span style="background:#1e1e1e;color:#569cd6">var</span><span style="background:#1e1e1e;color:#dcdcdc"> asButton </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">function</span><span style="background:#1e1e1e;color:#b4b4b4">()</span><span style="background:#1e1e1e;color:#dcdcdc"> {</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    </span><span style="background:#1e1e1e;color:#569cd6">this</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">click </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">function</span><span style="background:#1e1e1e;color:#b4b4b4">()</span><span style="background:#1e1e1e;color:#dcdcdc"> {</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">        console</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">log</span><span style="background:#1e1e1e;color:#b4b4b4">(</span><span style="background:#1e1e1e;color:#d69d85">"Button has been clicked"</span><span style="background:#1e1e1e;color:#b4b4b4">);</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    }</span><span style="background:#1e1e1e;color:#b4b4b4">;</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">    </span><span style="background:#1e1e1e;color:#569cd6">return</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#569cd6">this</span><span style="background:#1e1e1e;color:#b4b4b4">;</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">}</span><span style="background:#1e1e1e;color:#b4b4b4">;</span>
        </li>
        <li>
          &nbsp;
        </li>
        <li>
          <span style="background:#1e1e1e;color:#569cd6">var</span><span style="background:#1e1e1e;color:#dcdcdc"> a </span><span style="background:#1e1e1e;color:#b4b4b4">=</span><span style="background:#1e1e1e;color:#dcdcdc"> {</span><span style="background:#1e1e1e;color:#dcdcdc"> radius</span><span style="background:#1e1e1e;color:#b4b4b4">:</span><span style="background:#1e1e1e;color:#dcdcdc"> </span><span style="background:#1e1e1e;color:#b5cea8">10</span><span style="background:#1e1e1e;color:#dcdcdc"> }</span><span style="background:#1e1e1e;color:#b4b4b4">;</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">asCircle</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">call</span><span style="background:#1e1e1e;color:#b4b4b4">(</span><span style="background:#1e1e1e;color:#dcdcdc">a</span><span style="background:#1e1e1e;color:#b4b4b4">);</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">asButton</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">call</span><span style="background:#1e1e1e;color:#b4b4b4">(</span><span style="background:#1e1e1e;color:#dcdcdc">a</span><span style="background:#1e1e1e;color:#b4b4b4">);</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">console</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">log</span><span style="background:#1e1e1e;color:#b4b4b4">(</span><span style="background:#1e1e1e;color:#dcdcdc">a</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">area</span><span style="background:#1e1e1e;color:#b4b4b4">());</span>
        </li>
        <li>
          <span style="background:#1e1e1e;color:#dcdcdc">console</span><span style="background:#1e1e1e;color:#b4b4b4">.</span><span style="background:#1e1e1e;color:#dcdcdc">log</span><span style="background:#1e1e1e;color:#b4b4b4">(</span><span style="background:#1e
    

    1e1e;color:#dcdcdc">a.click());


    En este cas asCircle y asButton son los dos Mixins. El primero añade una funcionalidad area a todos los objetos que tengan una propiedad llamada radius. El segundo añade un método click.

    Para aplicar los Mixins sobre un objeto usamos la función call. No entraré en detalles de call ahora porque excede el objetivo de este post. Pero la clave está en que después de aplicar los Mixins, el objeto a tiene los métodos area y click.

    Y más o menos… ¿con esto podemos dar por terminado el post no? Espero, que esto os haya ayudado a entender un poco mejor la POO bajo JavaScript y que bueno… os hayáis convencido de que JavaScript no tendrá clases pero orientado a objetos es 🙂

    Saludos!

    PD: Os paso el enlace del video de youtube donde podeis ver el hangout: http://www.desarrolloweb.com/en-directo/particularidades-programacion-orientada-objetos-poo-devio-8452.html

    Si quieres, puedes invitarme a un café xD
    bitcoin QR Code
    GroupCreated with Sketch.

    eiximenis
    ESCRITO POR
    eiximenis
    Compulsive Developer