Conceptos Básicos Javascript: Herencia por prototipos

Llegó la hora de entrar el en tema que realmente confunde a los recién llegados a Javascript, principalmente para quienes vienen de lenguajes que implementan la orientación a objetos mediante clases, que son la gran mayoría.

Orientación a Objetos

Primero deberemos aclarar que significa Programación Orientada a Objetos (POO u OOP en ingés).

Según la Wikipedia, la descripción es:

es un paradigma de programación que usa objetos y sus interacciones, para diseñar aplicaciones y programas informáticos. Está basado en varias técnicas, incluyendo herencia, abstracción, polimorfismo y encapsulamiento.

Como vemos un lenguaje orientado a objetos no necesariamente tiene que implementarse mediante clases, cualquier sistema que proporcione herencia, abstracción, polimorfismo y encapsulamiento es una implementación de orientación a objetos válida. Como ya dijimos, el sistema de clases es el más extendido, utilizado por C++, Java, C#, PHP, Python, ActionScript3, Perl, Objective-C, Ruby, etc… Javascript no tiene clases, utiliza el sistema de herencia por prototipos, veamos la diferencia:

En un lenguaje basado en clases tenemos dos tipos de conceptos, los objetos en sí, referencias que pueden ser almacenadas, modificadas y pasadas como argumentos. Y por otro lado las clases, objetos intangibles, no podemos guardarlos en variables ni pasar como argumento, no podemos manipularlos ni comprobar si existen excepto por reflexión, que consiste en herramientas del lenguaje para obtener objetos (tangibles, del tipo anterior) que representan a las clases a las que no podemos acceder. En un lenguaje de éste tipo las clases están una capa por encima de los objetos y definen la herencia, abstracción, encapsulamiento y polimorfismo de los objetos que se obtendrán a partir de ellas, tienen una función de plantillas para crear objetos definidas antes de ejecutarse el código del programa.

En un lenguaje orientado a prototipos no hay clases que definan la herencia, los objetos mismos heredan de otros objetos. No hay clases cuando el programa se inicia, sino que se crean objetos y se le ordena a otros objetos que hereden de ellos. Por ejemplo, si tenemos un objeto eventEmitter y queremos crear instancias creamos nuevos objetos y hacemos que hereden de eventEmitter.

[[Prototype]]

Una vez entendido el concepto podemos pasar a la práctica, sabemos que para crear instancias de clases hacemos new MyClass() pero cómo hacemos que objetos hereden de objetos? Aquí entran los prototipos. Todos los objetos Javascript tienen una propiedad oculta que llamaremos [[Prototype]], con corchetes (aunque en algunos navegadores es posible acceder a ella mediante la propiedad .__proto__, con dos barras bajas a cada lado, pero no es estándar) que es un puntero al objeto del cual hereda. Y que significa que hereda? Podríamos resumir la herencia en que un objeto tiene las mismas propiedades que otro.

Con ésto nos ahorramos tener que poner las mismas propiedades en más de un objeto. Esto trae un nuevo concepto que puede confundir a muchos: en Javascript todo es una instancia, y cuando heredamos de un objeto también se puede decir que estamos creando una instancia de ése objeto, para evitar confunsiones suele decirse que un objeto “extiende” otro. Imaginemos que tenemos un objeto perro que hereda de animal. Que significa ésto? que la propiedad [[Prototype]] de perro es animal, o lo que es lo mismo:

perro.__proto__ == animal; // true

El código de ejemplo es el siguiente:

var animal = {};
animal.estaVivo = function() {
    return true;
};

var perro = {};
perro.__proto__ = animal;
console.log(perro.estaVivo);

Pruébame

Vemos que perro.estaVivo es la función que asignamos a animal cómo puede ser ésto? Por la herencia por prototipos. Javascript ha buscado la propiedad estaVivo en perro pero no la ha encontrado, entonces accede a su propiedad [[Prototype]] (o __proto__) donde nosotros guardamos animal. Entonces busca estaVivo en animal y lo encuentra. Por eso perro.estaVivo nos devuelve el método de animal. Podríamos representarlo así:

Diagrama

Y si animal no hubiese tenido la propiedad estaVivo? En ese caso debemos tener en cuenta que animal también es un objeto y que todos los objetos tienen prototipo, en caso de que no le asignemos ninguno su prototipo es Object.prototype. Es otra forma de decir que en Javascript todos los objetos extienden Object.prototype. Object.prototype es el equivalente a la clase Object de Java o C#.

var animal = {};
console.log(animal.__proto__ === Object.prototype);

Pruébame

Y si tampoco encuentra la propiedad en Object.prototype? lo busca en el [[Prototype]] de Object.prototype pero sorpresa! Object.prototype.__proto__ es null. Eso significa que es el último objeto de la jerarquía de herencia, si llegado a éste punto Javascript no encuentra la propiedad que le pedimos devuelve undefined.

Esta jerarquía de prototipos suele llamarse cadena de prototipos del objeto. Por ejemplo, Object.prototype tiene la propiedad .toString(), entonces si volvemos a crear perro heredando de animal, su propiedad .toString() que será? Javascript recorrerá la jerarquía de prototipos de perro hasta encontrar .toString() que está en Object.prototype.

var animal = {};
animal.estaVivo = function() {
    return true;
};

var perro = {};
perro.__proto__ = animal;
console.log(perro.toString === Object.prototype.toString);

Pruébame

Como modificar una propidad inaccesible?

Bien, la teoría ha ido correctamente, pero como ya dijimos, __proto__ no es estándar, y por lo tanto no podemos contar con que funcione en cualquier motor de Javascript, entonces cómo se supone que vamos a implementar herencia en Javascript? Para ello Javascript provee de una funcionalidad un tanto difícil de entender así que intentaremos ir poco a poco.

Toda función, creada en Javascript tiene una propiedad llamada .prototype que no debe confundirse con [[Prototype]], el [[Prototype]] de las funciones apunta a Function.prototype que es un objeto que tiene funciones como .call(), .apply() y .bind(). No, en éste caso nos referimos a que todas las funciones tienen una propiedad llamada prototype que es un objeto vacío. Y porqué se llama prototype si no tiene nada que ver con el [[Prototype]] de la función? Porque los objetos que creemos llamando a ésa función con new tendrán su [[Prototype]] apuntando a la propiedad prototype de la función:

function myFunct() { }
var obj = new myFunct();
console.log(obj.__proto__ === myFunct.prototype); 

Pruébame

Sorpresa! Hemos modificado la propiedad oculta [[Prototype]] de obj! Quizás te preguntes porqué no se estandariza la propiedad accesible __proto__? Porque con el sistema de las funciones el lenguaje se asegura que sólo podemos modificar la propiedad [[Prototype]] de objetos nuevos, no de existentes. De ésta forma, en las implementaciones estándar donde no podemos acceder a la propiedad __proto__ no podemos modificar el prototipo de una función o de Object.prototype ni podemos evitar que un objeto extienda de Object.prototype, poniendo su propiedad __proto__ a null romperíamos ésta regla del lenguaje.

Pero entonces myFunct es una clase? Podría decirse que si, pero no es una clase como las que estamos acostumbrados a ver, es una función, es un objeto y es tangible, el hecho de crear nuevos objetos con new seguido de una función es solo una sintaxis que se añadió a Javascript para parecerse a Java, lenguaje en plena expansión cuando Javascript fue diseñado. Ahora que entendemos que myFunct.prototype es igual al [[Prototype]] de los objetos que creemos con la función podemos crear objetos que extiendan del mismo objeto:

function myFunct() { }
myFunct.prototype = {
    name: "Alice",
    lastname: "Smith",
    fullname: function() { 
        return this.name + ' ' + this.lastname;
    }
};

var instancia1 = new myFunct();
var instancia2 = new myFunct();

console.log(instancia1.fullname() + 'n' + instancia2.fullname());
console.log(instancia1.__proto__ == instancia2.__proto__); 

Pruébame

E incluso podemos crear un objeto que extienda de una instancia de myFunct!

instancia1.name = "Bob";
function extenderInstancia1() { }
extenderInstancia1.prototype = instancia1;
var subInstancia = new extenderInstancia1();

var texto = "Fullname: " + subInstancia.fullname() + 'n';
texto += "Es instancia de extenderInstancia1? " + (subInstancia instanceof extenderInstancia1) + 'n';
texto += "Es instancia de myFunct? " + (subInstancia instanceof myFunct) + 'n';
texto += "Es instancia de Object? " + (subInstancia instanceof Object);

alert(texto); 

Pruébame

extend()

Pero éste lío de tener funciones que parecen clases pero no son clases exactamente y crean instancias y tener que crear funciones para extender es bastante confuso, por ello, los defensores de no mezclar la herencia por prototipos con éstas falsas clases proponen usar la función extend:

function extend(proto) {
    function intermediario() { }
    intermediario.prototype = proto;
    return new intermediario;
}

Y con ésta función podemos extender objetos sin necesidad de crear funciones intermedias:

var base = {
    name: "Alice",
    lastname: "Smith",
    fullname: function() { 
        return this.name + ' ' + this.lastname;
    }
};

var instancia1 = extend(base);
var instancia2 = extend(base);

instancia1.name = "Bob";
var subInstancia = extend(instancia1);
console.log(subInstancia.fullname()); 

Pruébame

Como vemos, el código queda bastante más claro, es por ésto que en la 5ª edición de ECMAScript (el estándar en el que está basado Javascript), se decidió añadir Object.create() que cumple la misma funcionalidad que la función extend() que hemos creado.

Resumen

Es un camino duro pasar de un lenguaje basado en clases a uno basado en prototipos, requiere mucha práctica, una mente abierta y muchas ganas de aprender. Pero las ganancias son grandes, incluso para desarrolladores que no necesiten tocar Javascript considero que aprender éste patrón aporta ventajas porque entender ambos patrones en mente nos abre a nuevas ideas, nos ayuda a tener siempre presente que las cosas no tienen porque ser como estamos acostumbrados a que sean, y a buscar nuevas soluciones a nuevos problemas y por último pero no menos importante, nos mantiene activos. Espero que sea fácil seguir el post aunque se que ha crecido más allá de lo deseado, pido comprensión ya que escribir no es mi punto fuerte, pero para eso está la práctica, para mejorar 😉

178 thoughts on “Conceptos Básicos Javascript: Herencia por prototipos

  1. Buenas, acabo de quedar confuso, yo hacia la herencia con prototype, pero de repente te vi hacerla con __proto__, cual es la diferencia?

    var animal = function(){}
    animal.prototype.estaVivo = function(){
    return true;
    }
    var perro = function(){}
    perro.prototype = new animal();
    console.log(new perro().estaVivo());

    var animal = function(){};
    animal.estaVivo = function() {
    return true;
    };
    var perro = function(){};
    perro.__proto__ = animal;
    console.log(perro.estaVivo());

    Un saludo!

    1. Buenas Andrew

      La herencia por prototipos se hace por la propiedad interna de cada objeto [[Prototype]].

      La propiedad `prototype` del constructor (`animal.prototype`) es el objeto que será el prototipo de lo que crees con ese constructor. La propiedad `__proto__` es directamente la propiedad [[Prototype]] del objeto en si que, según el estándar, no es accesible ni editable.

      En resumen, `Animal.prototype` te permite definir de antemano el prototipo de las instancias de Animal mientras que `__proto__` te permite modificar directamente el prototipo del objeto que estás tocando, pero `__proto__` no es estándar y no todos los navegadores lo soportan, en muchos casos como Google Docs ha producido bugs extraños (http://productforums.google.com/forum/#!topic/docs/0hQWeOvCcHU) y se está haciendo un esfuerzo por eliminarlo (https://mail.mozilla.org/pipermail/es-discuss/2011-December/019048.html) 🙂

    1. Gracias Daniel.

      Si, en principio cualquier función puede ser un constructor. Que lo sea o no depende de como quieras usarlo. En este caso como lo invoco con new si sería un constructor, aunque por convenio al ser un constructor debería empezar con mayúsculas 😛

  2. Muy claro el artículo, Hay una cosa que no me ha quedado del todo claro, y es la sobreescritura de funciones, es posible hacerlo, te pongo un ejemplo Tengo dos definiciones de clases, A y B de tal manera que A heredará de B, esta herencia la he puesto en el propio constructor A.js:

    // A.js
    (function () {
        var A () {
        };
        this.A = A;
        A.prototype.fun(){
            return "uno";
        }
    } ()
    
    // B.js
    (function () {
        var B () {
           this.__proto__ = new A()
        };
        this.B = B;
        B.prototype.fun(){
            return "dos";
        }
    } ()
    

    Si ejecuto el siguiente código

    var b = new B;
    console.log(b.fun()) // uno
    

    Si he conseguido sobreescribir un metodo de Object, en concreto toString mediante este método pero creo que aquí se me olvida algo.

    1. Corrijo parte del código A.js

      // A.js
      (function () {
          function A () {
          };
          this.A = A;
          A.prototype.fun = function (){
              return "uno";
          }
      } ())
      
      // B.js
      (function () {
          function B () {
              this.__proto__ = new A()
          };
          this.B = B;
          B.prototype.fun = function (){
              return "dos";
          }
      } ())
      
      1. Si se puede sobreescribir métodos aunque no es fácil, pero primero creo que tu código no hace lo que esperabas. En el segundo archivo B.js cuando haces this.__proto__ = new A() estás sobreescribiendo el prototipo de la instancia de B por una instancia de A por lo que ya no prototipa B.prototype.

        Para heredar de A necesitas que B.prototipe prototipe A.prototype, esto se puede hacer de dos formas

        B.prototype = new A();
        // o mejor
        B.prototype = Object.create(A.prototype);
        

        Entonces lo que necesitas es asignar B.prototype antes de empezar a añadir métodos.

        function A() { }
        A.prototype.fun = function() {
          return "uno";
        };
        
        function B() { }
        B.prototype = Object.create(A.prototype);
        B.prototype.fun = function() {
          return "dos";
        };
        
        var b = new B();
        console.log(b.fun());
        

        http://jsfiddle.net/amatiasq/SCLyD/

  3. Hola Matías.

    Me gusta mucho Javascript(Me da muchos dolores de cabeza derrepente jeje).

    Hace poco empece a adentrarme mas a la POO y el prototypado de JS, sin embargo no tengo muchas ideas de como aplicarlo en aplicaciones del día a día (Por ejemplo, sistemas con formularios que es lo que mas se solicita.) En el ejemplo que vi era un juego muy sencillo, en el cual se notaba las grandes ventajas de usar POO.

    Supongo que unicamente se le saca jugo con aplicaciones mas complejas o Plugins.

    1.-¿Podrías orientarme con el uso que tu le das en aplicaciones comunes?

    2.-¿Seria genial si hicieras un articulo sobre como realizar plugins básicos =D?.
    Realmente seria de mucha utilidad

    Gracias por tu tiempo, acabo de descubrir tu blog y creo que merece la pena leer los demás artículos y recomendarlo.

    Saludos

    1. Buenas Lugo,

      Cada vez más gente está usando Javascript, ya notarás que la comunidad ha madurado mucho en los últimos años y lo que hacíamos hace dos años (incluidos la mayoría de los tutoriales) y están obsoletos, por eso me gusta escribir sobre cosas de Javascript en sí y no sobre librerías.

      Si quieres ver como uso javascript en mi día a día te recomiendo mirar mi proyecto Lulas que consiste en células que se comen unas a otras. Es un proyecto que he cuidado mucho y que usa pocas librerías externas.

      Uso RequireJS para crear módulos y todo lo demás es javascript puro y código propio, por ejemplo aquí puedes ver los dos pasos para hacer herencia en Javascript: constructor y prototipo. En algunos puntos me pasé un poco de listo porque es un proyecto experimental pero no dudes en preguntar cualquier duda.

      Casualmente este mes la organización que dirige el estándar ha lanzado ECMAScript2015 (antes ECMAScript 6) que cuando los navegadores lo implementen podremos usar módulos nativos de Javascript (si, nativos) y clases nativas (que por detrás hace exactamente lo mismo que te acabo de mostrar en Lulas pero es más bonito de escribir 😛

      Sobre los plugins es muy tonto, yo una vez me puse a buscar como loco cómo hacer plugins y la verdad es que no hay una forma estándar de hacerlo, un sistema de plugins es solo un objeto y un objeto maestro que lo controle ejemplo. A partir de ahí depende de qué tanto lo quieras complicar, te recomiendo leer y practicar patrones de diseño que van muy bien para crear las abstracciones que necesitas para crear plugins. Algunos son un poco difíciles de traer a Javascript pero se puede, no hay que confundirlos con patrones comunes que hacemos en javascript (que es lo que sale cuando busco patrones de diseño javascript).

  4. Хочу рассказать свою историю. Меня бросили 3 раза, говорили, что я пустое место, но потом опять я «единственная и не повторимая». Это продолжалось до середины января и, в конце концов, он мне сказал, что никогда меня не хотел, что все через силу, я ему противна, он мне ничего не обещал никогда, и вообще, он со мной нечасто спал, чтоб считалось что мы встречаемся (1-2 раза в нед). Сразу на след. день после всех этих слов я пришла к нему, ибо он заболел и кроме меня некому за ним ухаживать. В этот же день он «завалил» меня, сказав, что он просто дико хочет меня. Потом неделю он откровенно провоцировал меня уйти от него, вел себя отвратительно, если до этого он использовал меня (я все готовила, убирала, стирала) то там это был ад. И, в конце концов, он мне написал что любит только меня и никого больше, с тех пор он относится ко мне как к принцессе. Но он по-прежнему спит с бывшей ее фото
    Дальше начался дикий ад, он постоянно орал на меня, что я лезу в его личную жизнь, что я мешаю ему, что я слишком жирная/страшная и т.д., даже орал за то, что я мешаю жить ЕЙ!!! Также он мне постоянно плакался, как любит ее, не может забыть, каждый день просыпается с мыслью о ней. Мне, естественно, слушать это, мягко говоря, неприятно, но я всячески успокаивала и поддерживала. Но вместе с этим не отпускал меня опять же как будто важна ему. Он зачастую даже не скрывал измены (смазка закончилась нереально быстро, презервативов ушло 20шт при том, что он без них в основном занимается сексом, со мной вообще всегда без них) я молчала все это время.

  5. Я незнаю с чего начать…я обычная девушка…мне 18 лет…я ревнивая, наивная, доверчивая, у меня есть парень которому тоже 18 лет, нас разделяет 70 км, он мне сегодня сказал что переписывался с девушкой из другой страны, он дал мне ее ссылку и она действительно с другой страны и она старше его на 2 года….но ещё он мне кинул запись с пошлым намеком и сказал что это не мне, я вспылилась и он начал предъвлять претензии по поводу моей ревности, я спросила кому тогда же он скинул эту запись, он сказал что своему другу, но я не верю, мой парень врал мне уже , но там совсем по мелочи…я уже не могу никому доверять…мне врали много раз. тварь
    Мы стали все чаще видеться и все больше времени проводить вместе. В последних месяцах года работы у него стало меньше и он практически у меня жил. Я приходила с работы, мы покупали еду, он помогал мне готовить, играл в компьютерную игру, которой и меня заинтересовал. Все шло чудесно, пока я не обнаружила, что на своем запароленном телефоне он общается с бывшей. Он стал уверять, что общаются они с ней только сугубо как кумовья, так как крестили вместе ребенка. Я старалась объяснить, что все понимаю, что длительные отношения не проходят просто так, а оставляют раны. Но для того чтобы они зажили нужно просто обрезать всякое общение с бывшей, хотя бы на какое-то время.

  6. Хочу рассказать свою историю. Меня бросили 3 раза, говорили, что я пустое место, но потом опять я «единственная и не повторимая». Это продолжалось до середины января и, в конце концов, он мне сказал, что никогда меня не хотел, что все через силу, я ему противна, он мне ничего не обещал никогда, и вообще, он со мной нечасто спал, чтоб считалось что мы встречаемся (1-2 раза в нед). Сразу на след. день после всех этих слов я пришла к нему, ибо он заболел и кроме меня некому за ним ухаживать. В этот же день он «завалил» меня, сказав, что он просто дико хочет меня. Потом неделю он откровенно провоцировал меня уйти от него, вел себя отвратительно, если до этого он использовал меня (я все готовила, убирала, стирала) то там это был ад. И, в конце концов, он мне написал что любит только меня и никого больше, с тех пор он относится ко мне как к принцессе. Но он по-прежнему спит с бывшей Здесь
    Сама позвонила ему, прекрасно зная, что он всегда прибежит, так и случилось. Рядом с ним я сразу почувствовала себя прежней — сильной, уверенной в себе, красавицей. А также желанной и любимой. Надо сказать, в своё время я скрылась от него, прекратив отвечать на все звонки, потому что он вёл себя как самый настоящий маньяк. Не смотря на все, прекрасно зная как он ко мне относится, и что он совершенный не адекват, я все равно с ним встретилась в ночном клубе. Все его друзья и их подруги таращили на меня глаза и шептались: «Та самая»..

  7. Thank you so much for giving everyone an exceptionally spectacular opportunity to read critical reviews from this web site. It is usually so pleasurable and also jam-packed with fun for me personally and my office fellow workers to search your blog on the least thrice weekly to see the new issues you will have. And definitely, I am just certainly astounded concerning the splendid tips you give. Selected 1 ideas in this post are honestly the most effective I’ve had.

  8. I and also my friends have been viewing the best strategies from your website and so unexpectedly I had a horrible feeling I had not expressed respect to the web site owner for those secrets. Those young men are actually for that reason passionate to read all of them and have now unquestionably been enjoying them. I appreciate you for truly being simply helpful and also for figuring out such superb useful guides most people are really desirous to be aware of. Our sincere regret for not saying thanks to you earlier.

  9. I must express appreciation to this writer for rescuing me from such a situation. Right after surfing through the search engines and getting recommendations which are not helpful, I assumed my entire life was well over. Existing minus the strategies to the difficulties you’ve resolved by means of your entire site is a critical case, and the ones that would have badly affected my career if I had not noticed your site. That understanding and kindness in dealing with every aspect was valuable. I am not sure what I would’ve done if I had not come upon such a stuff like this. I can also at this point relish my future. Thank you very much for your reliable and result oriented guide. I will not hesitate to refer the sites to any person who needs to have care about this subject matter.

  10. Пришла и моя очередь рассказать свою грусную и ужасную историю. Начну с того что я сама росла в неполной семье, вернее родной отец был, но не участвовал в воспитании совсем.С мамой моей ругались и дрались, изменял ей и пил. Потом она развелась и дом поделили пополам.. Как бы и отец был, но сказать что люблю его я не могу, хотя сейчас на старости они все таки и стали жить вместе, и отец закодировался, но та обида осталась до сих пор со мной. А к чему такая предыстория. Все к тому что я для себя решила что у меня такого точно не будет. Будет любящая семья и заботливый муж. И вот я на 10 неделе беремености, от человека которого и люблю и ненавижу одновременно. бестия
    Через время на работе начались финансовые проблемы и оставаться там не было смысла. Мне больше нечего было терять в этом городе и я переехала к Андрею. В быту и сексе у меня вообще не было никаких к нему претензий. Руки растут откуда надо, голова работает, секс замечательный…только вот одно НО…подозрения и недоверие к нему как были, так и остались. Периодически она ему писала, присылала фотографии, звонила. Я нервничала, а он говорил, что она его кума и они теперь всю жизнь будут общаться, хочу я этого или нет. Раз я узнала, что он ездил к ней, но якобы под предлогом хорошего общения с ее родителями. Она же по телефону позволяла себе оскорбления в мою сторону, при этом он ничего ей на это не говорил. Все время звала в гости к куме, а если он отказывал, то начинала писать, что испортит ему жизнь. Раз даже в лицо ему угрожала, а он просто промолчал. В это время родители и близкие души во мне не чаяли! Мол, наконец, нашел себе толковую девушку, которая с радостью заботится об Андрее. Бывшую же его абсолютно все вспоминают только плохими словами, так как она все время от него гуляла, пила, да и, вообще, с окружающими вела себя как грубиянка и только тянула с Андрея деньги.

  11. I have been browsing online more than 2 hours today, yet I never found
    any interesting article like yours. It’s pretty
    worth enough for me. In my view, if all web owners and bloggers made good content as you did,
    the web will be a lot more useful than ever before.

  12. Hello would you mind letting me know which web host you’re utilizing?
    I’ve loaded your blog in 3 different browsers and I must say this blog
    loads a lot faster then most. Can you recommend a good internet
    hosting provider at a fair price? Thank you, I
    appreciate it!

  13. It’s appropriate time to make a few plans for the
    long run and it is time to be happy. I have read this
    submit and if I may just I desire to recommend you few interesting issues
    or suggestions. Perhaps you could write subsequent articles regarding this article.
    I want to learn even more issues about it!

  14. Hi, I do think this is an excellent web site. I stumbledupon it ;
    ) I may come back once again since I book marked it.
    Money and freedom is the greatest way to change,
    may you be rich and continue to help other people.

  15. It is perfect time to make some plans for the future and it’s time to be happy.

    I have read this post and if I could I want to suggest you few interesting things or suggestions.

    Perhaps you can write next articles referring to this article.
    I desire to read even more things about it!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *