¿Cómo se encapsulan métodos y atributos en JavaScript?
JavaScript es un lenguaje con particularidades únicas que se manifiestan en diversas formas a la hora de trabajar con prototipos y clases. Aunque el encapsulamiento es un concepto familiar en muchos lenguajes, en JavaScript la forma de implementarlo difiere un poco. Aquí analizaremos cómo podemos proteger nuestros datos y métodos de cambios no deseados.
¿Cómo protegemos los atributos en JavaScript?
En lenguajes de programación tradicionales, es común marcar atributos como privado o público para controlar el acceso. Sin embargo, JavaScript no tiene un soporte nativo para el acceso privado. En su lugar, se sigue una convención: prefixar el nombre del atributo con un guion bajo (_). Este método pretende ser una señal amistosa a otros desarrolladores para que entiendan que esos atributos no deberían ser manipulados directamente desde fuera de la clase.
¿Qué son los getters y setters?
Getters y setters son métodos especiales que nos permiten interceptar y controlar el acceso a los propiedades de los objetos:
Getters: Permiten acceder a los valores de propiedades encapsuladas.
Setters: Facilitan la modificación de dichos valores, permitiendo agregar lógica adicional, como validaciones, antes de realizar cambios.
classCourse{constructor(name){this._name= name;// uso de prefijo para denotar privacidad}getname(){returnthis._name;// acceso controlado a la propiedad}setname(newName){if(!newName.includes("malito")){this._name= newName;}else{console.warn("Way, no puedes actualizar el curso con ese nombre.");}}}let curso =newCourse("Curso gratis de programación básica");console.log(curso.name);// Accede al nombre utilizando el gettercurso.name="Curso avanzado de programación";// Modifica el nombre usando el setterconsole.log(curso.name);// Verifica el cambio
¿Cómo se previenen cambios indeseados?
Utilizando setters, podemos establecer restricciones o validaciones que deben cumplirse antes de modificar propiedades. En el caso ilustrado, se previene que el nombre del curso pueda incluir valores considerados inapropiados como "malito".
Desafíos y ejercicios
Practicar con getters y setters es esencial para dominar su uso en JavaScript. Aquí te propongo dos desafíos:
Describe cómo se utilizan getters y setters sin la sintaxis de clases: Comprende cómo trabajar con ellos en prototipos tradicionales de JavaScript.
Aplica getters y setters en un proyecto propio: Actualiza atributos dentro de un sistema más complejo (como un clon de una aplicación educativa) para gestionar estudiantes y cursos.
Estos pasos no solo consolidarán tu conocimiento sobre encapsulamiento en JavaScript, sino que también te prepararán para escribir código más robusto y sostenible. ¡Adelante, sigue explorando! Tu habilidad para gestionar la lógica de negocio con JavaScript crecerá exponencialmente con la práctica.
En ES2020 se introdujo la sintaxis campos privados en las clases. Se hace uso de un numeral como prefijo del nombre de la variable.
¿Cúal sería la ventaja de usar esto? Que no existe la posibilidad de que alguien modifique la variable privada desde la instancia a menos de que use el setter que le dimos.
Con el ejemplo en esta clase, quedaría así:
Qué son los getters y setters
Una función que obtiene un valor de una propiedad se llama getter y una que establece el valor de una propiedad se llama setter.
Esta característica a sido implementada en ES2015, pudiendo modificar el funcionamiento normal de establecer u obtener el valor de una propiedad, a estas se les conoce como accessor properties.
Funcionamiento
En ocasiones queremos valores basados en otros valores, para esto los data accessors son bastante útiles.
Para crearlos usamos los keywords get y set
const obj ={getprop(){returnthis.__prop__;},setprop(value){this.__prop__= value *2;},};obj.prop=12;console.log(obj.prop);//24
Creamos un objeto, con una única propiedad, que tiene un getter y un setter. de esta manera cada vez que establezcamos un valor para prop se multiplicará por dos.
Nota: utilice prop por convención, pero no implica que es un valor especial, este es un valor normal.
Otra manera de crear un accessor properties es de manera explícita usando Object.defineProperty
const obj ={};Object.defineProperty(obj,//objeto target'prop',//nombre propiedad{enumerable:true,configurable:true,getprop(){//getterreturnthis.__prop__;},setprop(value){//setterthis.__prop__= value *2;},});obj.prop=12;var atr =Object.getOwnPropertyDescriptor(obj,'prop')console.log(atr);
La ventaja que tenemos de esta manera, es que podemos establecer los atributos que queremos tenga la propiedad.
Esta cool el aporte, muchas gracias. solo una acotación. Investigando, los getter y setter se pueden implementar desde antes de ECMAScript2015
Gracias por el aporte, esto si que me aclaro muchisimo el entender como que y para que son esos tal de getters y setters.
Me puse a jugar un rato con los "prototypes" y logre esto:
Mi respeto... Esto si es verdadero encapsulamiento.... Gracias por compartir este ejemplo....
Los getters y setters son geniales. Pero me paso algo extraño:
si pongo cursoProgBasica .name = "Cualquier nombre" el SET comprueba que cumpla lo que le pedi. PEEEEROOO si pongo por consola:
cursoProgBasica._name = "cualquier cosa" ME SALTEA la barrera del SET y me toma como correcto lo que ponga! A alguien mas le paso?
Yes! ¡Así se hackea JavaScript! ¡MUY BIEN!
.
En el Curso Intermedio de POO en JS vamos a ver varias estrategias para combatir ese mismo problemita :D
Es cierto, colocándolo así no da el error 🙃
Les dejo mi código sobre un manga xD usando la nueva sintaxis de #👇
const hasCopyright =falseclassManga{ #mangaka; #name;constructor({ name, mangaka }){this.#name= name;this.#mangaka= mangaka;}getmangaka(){returnthis.#mangaka;}getname(){returnthis.#name;}setname(name){if(hasCopyright){console.log('This Manga name has copyright!');}else{this.#name= name;}}}constREQUIEM_ADVENTURES=newManga({name:'Requiem Adventures',mangaka:'UltiRequiem',});console.log(REQUIEM_ADVENTURES);console.log(REQUIEM_ADVENTURES.mangaka);console.log(REQUIEM_ADVENTURES.name);REQUIEM_ADVENTURES.name='Adventures Requiem?';console.log(REQUIEM_ADVENTURES.name);
Tambien les dejo mi repositorio con notas y código del curso 👉 UltiRequiem/oop-js-platzi.
Getters se usan para acceder a las propiedades en un objeto.
Setters para cambiar or silenciar una propiedad en un objeto
Función generadora de números de Fibonacci usando getters y setters.
functionFibonacciGenerator(){this._a=0;this._b=1;}FibonacciGenerator.prototype={getnext(){let c =this._a+this._b;this._a=this._b;this._b= c;return c;},setnth(number){if(number<=0|| number>30)console.error("out-bound");else{let c =0;this._a=0;this._b=1;while(--number) c =this.next;}}}let fib =newFibonacciGenerator();fib.nth=10;//10th fibonaccifib.next;// 89fib.next;//144fib.next;//233
No olvides asignar la propiedad constructor de tu prototipo con el valor de tu función FibonacciGenerator para las posteriores validaciones de instancias.
Los getters y setters son construcciones de los objetos que permiten acceder a valores del mismo sin revelar la forma de su implementación.
Hackeado 😎😎
Que master 🤣
Hackeado X2
Nos van a banear de Platzi 😂🤣
Me tomo tiempo entender bien esta clase, pero al final pude organizar los getters y setters, adicional organicé los setters de los atributos que eran arrays, de forma que se puedan insertar y eliminar campos de estos arrays utilizando las funciones ++splice++ y ++push++, espero les sirva esta solución.
classTeacher{constructor({ id, name, speciality, courses =[],}){this.id= id;this._name= name;this.speciality= speciality;this._courses= courses;}getname(){returnthis._name;}setname(newTeacher){this._name= newTeacher;}getcourses(){returnthis._courses;}setcourses(newCourse){for(let i =0; i <this._courses.length; i++){if(this._courses[i]=== newCourse){this._courses.splice(i,1);console.log("You have deleted "+ newCourse.name+" of "+this._name+" list of Courses");}else{this._courses.push(newCourse);}}}}
Holas les comparto parte de mi código :)
muy interesante las clases he aprendido bastante
jajajajajaj
Entiendo que con el uso de Getters and Setters podremos evitar errores al interactuar con los usuarios, ya que me permite selecionar los atributos de las clases y condicionarlos con validaciones de manera que el usuario cambie solo lo que nos interesa
Lo que estoy viendo es que cuando trabajo con módulos me da error ❌
Pero cuando esta todo en un mismo archivo JS, si da bueno ✅
Por que pasa esto❓ 🤔
Tienes que exportar cursoProgramacionBasica dentro de main.js. Si es una variable o función, dependiendo de lo que es.
// exporta la función previamente declaradaexport{ myFunction };// exporta una constanteexportconst foo =Math.sqrt(2);
Luego importas lo que estas exportando dentro del archivo main.js
¿Podrías mostrarnos tu código JavaScript? Al parecer ahí está el posible error.
Compañeros una cosa que me acabo de dar cuenta, que los más avanzados ya lo sabrán, pero realmente es un dolor de cabeza tener todas las clases, objetos, instancias, etc en el mismo .js ya que ahora que ejecute en la consola me salieron errores que revisando es por el orden de ejecución de las clases u objetos que deben ser declarados o inicializados previamente y como tenia TODO en el mismo .js ahí tratando de "ordenarlos" (que según yo estaba todo ordenado) caí en un bucle en el que todas las clases deben ser declaradas entre todas antes una y otra jaja osea queda una mezcla completa de código sin ningún orden, así que ahora entiendo porque lo hacen en diferentes archivos o bueno supongo que una de estas debe ser una razón
Este sólo es un ejemplo básico de lo que se puede hacer con getters y setters; sin embargo, leí en un post que como parte de las buenas prácticas de programación, incluso si no vas a modificar un atributo, todos los atributos en general deberían ser accedidos por medio de getters y setters.
Como se vería el ejemplo de la clase si fuese directamente embebido en el objeto, sin una clase, con la restricción de que el valor** name **no puede ser una cadena vacía ni undefined.
var cursoProgBas ={ name_value, clases, instructor, año,getname(){returnthis.name_value;},setname(nuevoNombrecito){if(nuevoNombrecito ===""||typeof nuevoNombrecito ==="undefined"){console.error("El nombre no es válido o no ha sido asignado.")}else{this.name_value= nuevoNombrecito;}}}
Me gusta!
Hola
Les comparto mi codigo, el objeto estutdiante tiene la restricción de que el platziRank solo puede recibir number si es tipo "string" mostrará un error.
Interesante siempre habia visto POO pero únicamente en Java y en JS es como BOOM!! Constante 🤯
Y me recuerda mucho a la POO en Python. Si porque Python también tiene POO
mi pregunta es
estoy revisando información sobre getter and setters y en su mayoría sale información de JAVA en la cual entiendo que si declaramos un método de tipo private este no es accesible desde otra clase y es allí donde utilizas los getter y setter
pero en javascript si no podemos declarar como public o private que sentido tiene usarlos
? 🤔
Por lo general es buena práctica usar getters y setters para modificar los atributos de cualquier clase evitando errores, por ejemplo, si tienes un atributo que puede tener únicamente un valor numérico, alguien más podría modificarlo llamándolo así
MyClass.myAtribute='I’m a string ';
sin embargo si lo tuviera que modificar con un getter, la función getter podría tener una validación para que únicamente admita valores numéricos y evite este tipo de errores.
Creo q entiendo tu pregunta. quiza en 6 meses ya sabes la respuesta pero aca voy a intentarlo.
cuando estas programando y
dias despues de instanciar tu objeto o
varios eventos despues (eventos que han afectado a tu objeto).
o quieres hacer eventos que modifiquen tu objeto.
vas a desear que solo sea modificable lo que a ti como dev te convenga algunas props de tu objeto no querras que las toquen ni querras modificarlas tu mismo por algun error (que puede pasar).
entonces tener propiedades privadas es desde php , java , creo q para todos los lenguajes vital vital vital.
si js no los tiene yo lo considero un error pero hay gente muy habil que ha conseguido lograr emular el private para que sea mas seguro no romper tu propio programa.
a veces viene otro desarrollador o tu mismo , te olvidaste como se llama tu instancia y le pones el nombre de otra instancia de otra clase y sobre ella empiezas a modificar atributos que no querias modificar (estas modificando una instancia de otro objeto que en principio ni querias modificar y quiza ni lo tienes en tu mente).
luego tu app hace cualquier cosa menos lo que quieres.