Clases y objetos en Javascript
Desde la norma de ECMAScript5 Javascript puede considerarse un lenguaje de programación orientado a objetos, pero con algunas peculiaridades.
No posee todas las características de otros lenguajes orientados a objetos como Java o C++, pero si es capaz de manejar y crear objetos. Además permite la herencia, pero no la sobrecarga de funciones.
Es un lenguaje de programación orientado a objetos pero basado en prototipos. Sigue leyendo para ver que son los prototipos, es fácil de entender y de usar.
Al hablar de heredar se habla de que los objetos descendientes pueden acceder a propiedades y métodos del objeto desde donde se crearon (objeto padre). No se trata de que reciba copias de su constructor sino referencias a sus propiedades y métodos. Esto lo implementa mediante prototype
Para quien conozca la programación orientada a objetos del estilo de java o C++: Javascript no tiene clases solo definiciones de objetos, constructors, que se usan como modelos para construir otros objetos. Estos objetos padre o modelos serían lo más parecido a las clases de la programación orientada a objetos.
Aunque en la última versión aparezca una estructura semántica con el nombre class. Estas clases son en realidad constructores tipo Function, pero aportan algunas facilidades como extends y métodos estáticos (static). Es una manera de parecerse a los hermanos mayores como Java, C++ y otros.
De hecho Javascript trabaja con un objeto global que gobierna a todos los demás objetos (es el señor de los objetos).
Y por supuesto todo el entorno web es visto por Javascript como objetos, con sus propiedades y métodos. Gracias a esto puede usarse para para interactuar con las páginas web. En algunos ejemplos verás que se utiliza alert( ) para mostrar ventanas con resultados de los scripts, en realidad alert es una abreviatura de window.alert( ), se trata del método alert( ) del objeto window. Incluso console es un objeto.
En resumen
En programación los elementos materiales se deben representar por datos. Un precio es un número, eso es fácil.
Una televisión es una marca, un precio, un tamaño, un modelo. Un objeto viene de perlas para representar este elemento compuesto.
Los objetos permiten implementar en código esos elementos materiales para que Javascript los puede manejar.
El caso de la television: puedes definir un tipo de objeto que la represente, sus propiedades serían marca, pulgadas, modelo, precio. Y un método podría ser imprimir para imprimir una etiqueta.
Esto sería la definición del objeto, su constructor (algo así como una clase).
Cada televisor concreto es un objeto material que responde al esquema de televisor, es una instancia del objeto televisor.
Los objetos en Javascript
La solución Javascript a los objetos no es nada compleja. Parte de un objeto global (Object) a partir del cual implementa una serie objetos predefinidos que a su vez son constructores, como Array, Function, String...
Estos objetos predefinidos heredan métodos y propiedades del objeto global e incorpora los suyos propios, que también pueden ser heredados por los objetos instanciados a partir de ellos, mediante la cadena de prototype.
Todo lo que se asigne a objeto.prototype es heredado por los objetos creados a partír de ése objeto. Lo que no se asigne son propiedaes y métodos estáticos, no heredables.
Este mecanismo permite los objetos crados por un programa puedan definir métodos y propiedades heredables asignándolos a prototype, además de métodos estáticos.
Al instanciar un objeto, creas una variable concreta con las propiedades y métodos del objeto desde el que se instancia. Esas propiedades pueden tener un valor por defecto, pero lógicametne pueden sobreescribirse. Ya no se trata de un objeto constructor sino de una instancia del objeto.
Recuerda: un objeto primero se define, se describe como es, y luego se instancia, se materializa en variables para utilizarlos. La definición es lo abstracto (constructor) y la el objeto es lo que se maneja (instancia), se usa.
Digamos que la clase, el constructor o el objeto es lo abstracto. Mientras que la instancia del objeto es un objeto concreto y manejable. El coche es un concepto abstracto, pero mi coche es un objeto material y concreto, es una instancia de la clase coche.
Dentro de las definiciones de objetos disponemos de la variable this, esta variable se refiere al propio objeto, con ella los consturctores pueden inicializar el objeto o los métodos pueden trabjar con las propiedades del objeto.
Un objeto se puede crear de varias maneras:
- Directamente, con una expresión.
- Con Object.create
- A partir de una function.
- A partir de una class.
En cualquier caso recuerda que los objetos que creas viven dentro de un objeto global de Javascript, y heredan propiedades y métodos de este objeto global. Propiedades y métodos que puedes sobreescribir.
En resumen
Cada constructor de Javascript posee una propiedad denominada prototype: todo lo que se asigne a un objeto.prototype es heredado cuando se crea otro objeto a partir del él.
Las instancias de objetos no poseen la propiedad prototype, pero pueden acceder a los métodos y propiedades que sus constructores le propagan mediante ella.
El objeto this es una referencia al propio objeto que puede utilizarse dentro de sus métodos para referirse a él mismo.
Los métodos se nombran mediante el nombre del objeto propietario seguipo por el nombre del método separados por un punto.
Las popiedades y métodos se nombran mediante el nombre del objeto propietario seguido por el nombre de la propiedad o método separados por un punto.
objeto.metodo(args)
objeto.propiedad
También pueden usarse los nombres de métodos y propiedades (entrecomillados) como si fueran indices del objeto, encerrados entre corchetes:
obj["propiedad"] es lo mismo que obj.propiedad
Copiar objetos
En general cualquier variable es un posición de memoria con un valor almacenado. Si dices que la variable precio es 32 estas diciendo que existe un lugar en la memoria de la máquina que almacena el valor 32. Cuando se usa la variable precio Javascript está utlizando el valor almacenado. Si quieres que ese valor se copie en otra variable, por ejemplo total simplemente haces una asignación total = precio
Pero los objetos estructurados (array, Date, Object) no actúan así. Cuando defines o instancias un objeto estructurado y le das nombre, ese nombre guarda la referencia a lugar en a memoria donde se almacena el objeto, no a su valor. Por ejemplo lista = new Array(12,14,15,22), esta variable es el lugar donde se almacena esa lista de valores.
Si usas lista estás usando esa referencia, no un valor como ocurre en las variables no estructuradas como number o string. Si por ejemplo haces que items = lista, no copias el contenido de lista a items, copias la dirección donde están los datos. Por eso si consultas items verás los mismo datos que había en lista 12,14,15,22. Esto te va a ocurrir con cualquier tipo de objeto estructurado, no con los que implementan a datos tipo number, string o boolean.
Entonces la pregunta es ¿como puedo copiar un objeto en otro? Tendrías que escribir una función para cada tipo de objeto o bien usar structuredClone(), es una función que clona un objeto.
Prueba estos códigos
var precios = [20,30,40,50]
var valores = precios;
console.log( valores) // [20,30,40,50]
precios[0] = 80;
console.log( precios) // [80,30,40,50]
console.log( valores) // [80,30,40,50]
Como ves al modificar precios el cambio también afecta a valores, realmente se refieren al mismo lugar en la memoria son como alias.
var precios = [20,30,40,50]
var valores = structuredClone(precios);
console.log( valores) // [20,30,40,50]
precios[0] = 80;
console.log( precios) // [80,30,40,50]
console.log( valores) // [20,30,40,50]
Ahora precios y valores son objetos array diferentes, son una copia uno del otro.
Resumen
Los objetos son un tipo de dato que guarda una referencia al lugar donde está su contenido, su valor.
Las variables con datos primitivos guardan su valor, al copiarlas una en otra se están clonando.