En JavaScript no tenemos keywords para indicar que un atributo es privado o público a diferencia de otros lenguajes de programación. Sin embargo, podemos aplicar ciertas técnicas y métodos para lograrlo.
Atributos públicos y privados en JavaScript
Modificaremos la función creada anteriormente con la que podíamos generar nuevos objetos. Esto con la finalidad de separar los atributos que queremos que sean privados (por ahora solo el atributo name) y públicos, además de crear 2 funciones: una para poder modificar el atributo privado y otra para obtener el valor de esa propiedad privada:
Declaramos un objeto privateAtributos en el que colocaremos las propiedades que deseamos que sean privadas y otro objeto publicAtributos en el que queremos que sean públicas. Por ahora, solo name será privada y por convención se coloca un guion bajo delante del nombre de aquel atributo privado:
functionisObject(subject){returntypeof subject =="object";}functionisArray(subject){returnArray.isArray(subject);}functionrequiredParam(param){thrownewError(param +" es obligatorio");}functioncreateStudent({ name =requiredParam("name"), email =requiredParam("email"), age, twitter, instagram, facebook, approvedCourses =[], learningPaths =[],}={}){const privateAtributos ={// 👈👈// '_name' es el atributo privado// 'name' es el parámetro que recibe la función"_name": name,};const publicAtributos ={// 👈👈// El resto de atributos serán públicos: email, age, approvedCourses, learningPaths,socialMedia:{ twitter, instagram, facebook,}}return publicAtributos ;}
Por consiguiente, solo retornaremos publicAtributos, pues contiene las propiedades a las que sí podrán acceder los usuarios.
Crearemos las funciones con las que el usuario puede editar y leer el valor del atributo privado _name:
functionisObject(subject){returntypeof subject =="object";}functionisArray(subject){returnArray.isArray(subject);}functionrequiredParam(param){thrownewError(param +" es obligatorio");}functioncreateStudent({ name =requiredParam("name"), email =requiredParam("email"), age, twitter, instagram, facebook, approvedCourses =[], learningPaths =[],}={}){const privateAtributos ={"_name": name,}const publicAtributos ={// El resto de atributos serán públicos: email, age, approvedCourses, learningPaths,socialMedia:{ twitter, instagram, facebook,},readName(){// 👈👈return privateAtributos["_name"];},changeName(newName){// 👈👈 privateAtributos["_name"]= newName;},}return publicAtributos ;}
Finalmente, deberíamos evitar que el usuario modifique o elimine los métodos readName y changeName y dar así mejor seguridad a estos. Con Object.defineProperty haremos las configuraciones respectivas para evitar lo mencionado:
functionisObject(subject){returntypeof subject =="object";}functionisArray(subject){returnArray.isArray(subject);}functionrequiredParam(param){thrownewError(param +" es obligatorio");}functioncreateStudent({ name =requiredParam("name"), email =requiredParam("email"), age, twitter, instagram, facebook, approvedCourses =[], learningPaths =[],}={}){const privateAtributos ={"_name": name,};const publicAtributos ={// El resto de atributos serán públicos: email, age, approvedCourses, learningPaths,socialMedia:{ twitter, instagram, facebook,},readName(){return privateAtributos["_name"];},changeName(newName){ privateAtributos["_name"]= newName;},};Object.defineProperty(publicAtributos,"readName",{// 👈👈writable:false,configurable:false,});Object.defineProperty(publicAtributos,"changeName",{// 👈👈writable:false,configurable:false,});return publicAtributos ;}// Creamos un nuevo objetoconst juan =createStudent({email:"juanito@frijoles.co",name:"Juanito"});// Intentamos eliminar y alterar los métodos changeName y readNamedelete juan.changeName;// falsedelete juan.readName;// falsejuan.changeName=function(nombreImpostor){// NO se ve afectada la función originalreturn"patatas";}
La desventaja de protegerlos es que no nos permitiría trabajar con el polimorfismo (uno de los pilares de POO).
El funcionamiento de nuestros métodos generados changeName y readName es muy similar a los Getters y Setters. Veamos cómo aplicar estos en JavaScript. 🤔💪
:green_heart: Like si te enamoraste de Object.defineProperty con esta clase :facepunch:
🧐
si!
Existe una manera de definir o modificar varias propiedades a la vez 👀. Con la función Object.defineProperties() se puede pasar un objeto con las propiedades de cada key que quieren ser modificadas:
// Con definePropertyObject.defineProperty(public,"readName",{writable:false,configurable:false,});Object.defineProperty(public,"changeName",{writable:false,configurable:false,});// Con defineProperties Object.defineProperties(public,{readName:{configurable:false,writable:false,},changeName:{configurable:false,writable:false,},});
Yo tengo una duda sobre este código, el método
chageName() es para modficar el nombre al colocarlos en esta propiedad y colocando el configurable y el writable en FALSE, no me bloquea o me saca error para cambiar el nombre ?
@julian.mora no porque al colocar el writable y el configurable en false lo que estás evitando es que se modifique la estructura de la función como tal y evitar su eliminación respectivamente. No estás modificando la lógica de la función
Que buen maestro es Timothée Chalamet
Amigooo a mi tambien se me parece muchooooo
ATREIDES
!Paul Atreides
Module pattern y namespaces: propiedades privadas en JavaScript
JavaScript no es un lenguaje fuertemente tipado, osea, que no tenemos que definir el tipo de nuestras variables. JavaScript entenderá que tipo de variable estamos usando.
En javascript no hay una palabra clave para definir una variable privada por lo que podemos crear una función que nos permita crear esta variable.
Por lo general, podemos usar el Object.defineProperty() para crear la variable publica o privada
Otro forma de lllamar lo que se esta realizando en esta clase es el uso de closures para retornar un contexto controlado y poder usar variables privadas en JS vanilla :D
Aunque la forma presentada por juandc es mas limpia. Siempre es mas legible evitar los closures.
Precisamente eso es lo que está haciendo, la propia función es un objeto controlado al retornar un objeto con las funciones que modifican los atributos privados del contexto.
Todo era felicidad y entusiasmo hasta que llegué a estas últimas clases y cada vez me empecé a perder más 😥
tomalo con calma, el concep del deep copy fue uno que demore en interiorisar, por que no basta con solo entenderlo, te dejo un consejo, comenta las lineas importantes que veas que afectan el codigo y luego escribe detalladamente como funciona el codigo, asi tambien, generas una buena practica de documentar tus proyectos, espero ayudarte 💚
Comparto tu idea, bro.
actualmente podemos encapsular atributos y metodos privados en JS gracias al ES2022 simplemente agregando un # adelante del nombre de la variable o funcion y estas no entraran en conflicto con los metodos o atributos publicos, facilmente, podriamos tener declarados dos atributos con el mismo nombre y mas aun, una puede contener a la otra y no habra problema alguno, no se si me estoy adelantando pero solo me dio curiosidad jisjis, aqui la 💚
Hola! como estan?
Bien, ese pequeno reto del profe para que el usaurio no pueda hacer juan name = "nicolas", lo resolvi de esta manera:
Creo que la clase tiene algunos problemas, o yo soy el de los problemas, o quizá JS es el de los problemas...
Veamos lo siguiente 😬
Después de probar el código que fui escribiendo durante la clase y ver algunas cosas raras, decidí copiar y usar el código exacto de la clase y noté lo siguiente:
Si intento cambiar el nombre usando .name o ._name y luego imprimir los resultados, veo que los cambios sí fueron aceptados e incluso se muestran en consola.
Vemos como name: "Name two" y name: "Name three" se muestran dentro del objeto juan. Pero lo curioso es que si imprimimos juan.readName() muestra juancito
Pero eso no es todo, si cambiamos el nombre, los datos del objeto name: "Name two" y name: "Name three" se mantienen, pero al imprimir readName() este sí se cambió. 😥
¡Lo raro es que en el video al usar .name o ._name este nunca aparece en el objeto juan, por lo que se menciona que todo este procedimiento se hizo para que no podamos cambiar el nombre por uno como PATATAS BRAVAS!!! Siendo esto solo posible si se usa la función / método changeName.
El curso debería ser actualizado? No sé, tú dime... 🔥
changeName(newName){const nombre = newName.toLowerCase()console.log(nombre)for(i in malaPalabras){if(nombre.includes(malaPalabras[i].toLowerCase())){returnconsole.log(`Esta palabra esta prohibida`)}}this.firsName= newName
}
Hola, tengo una pregunta, sobre la constante privada, ¿Dónde se guarda esta o cómo es posible que con el método podamos acceder a ella?. Cuando vemos el objeto creado por dentro, no tiene en ningún lugar la constante privada (porque solo se retorna la parte pública)
Hice otra prueba colocando directo juan(punto)name y me creo otro atributo dentro del objeto juan y al final termine con dos name. Uno al que accedo por metodos y ese nuevo.
¡Hola! :)
Si pudieras compartirnos tu código sería más sencillo encontrar la solución. Puedes copiar y pegar utilizando el botón de </> insertar código.
¡Saludos!
Si, ya que el objeto juan en realidad no tiene name, porque la función retorna public que no incluye el atributo name.
Para el reto sobre nombres prohibidos, cree un array con la lista de nombres no permitidos.
Luego simplemente en nuestro metodo changeName, agregamos un condicional, si el newName es alguno de los elementos del array, usando el metodo .includes nos lanzara true y una advertencia, si es false entonces se cambia el nombre.
Wow interesante forma de aplicar programación orientada a objetos, pero no solo con POO, también lo podemos aplicar para nuestro desarrollo en backend o frontend, haciendo más mantenible y legible nuestro código, aunque sigo prefiriendo la sintaxis de CLASS para POO en javascript
Te explicaré el concepto de atributos públicos y privados en JavaScript.
.
En JavaScript, no existe una declaración explícita para definir atributos como públicos o privados, como en otros lenguajes de programación. Sin embargo, puedes utilizar convenciones y técnicas para simular atributos privados.
.
Atributos públicos:
Los atributos públicos en JavaScript son aquellos a los que se puede acceder y modificar desde cualquier parte del código. Se definen directamente en el objeto o función, sin ningún tipo de restricción de acceso.
.
Aquí tienes un ejemplo de un atributo público en un objeto:
var persona ={nombre:"Juan",edad:25};console.log(persona.nombre);// Acceso al atributo público "nombre"persona.edad=30;// Modificación del atributo público "edad"
En este caso, tanto el atributo "nombre" como el atributo "edad" son accesibles y modificables desde cualquier parte del código.
.
Atributos privados:
Los atributos privados en JavaScript se simulan mediante convenciones y técnicas para limitar el acceso directo a ellos desde fuera del ámbito en el que se definen. No existe una forma nativa de hacerlos privados, pero se pueden utilizar diferentes enfoques para lograrlo.
.
Un enfoque común es utilizar el concepto de clausura (closure) para crear un ámbito local y definir los atributos como variables dentro de ese ámbito. De esta manera, los atributos solo serán accesibles desde las funciones internas y no desde fuera.
.
Aquí tienes un ejemplo que demuestra cómo se pueden crear atributos privados utilizando clausuras:
functioncrearPersona(nombre){var edad =25;// Atributo privado// Función que accede al atributo privadofunctionobtenerEdad(){return edad;}// Función que modifica el atributo privadofunctioncambiarEdad(nuevaEdad){ edad = nuevaEdad;}// Objeto que expone solo las funciones públicasreturn{nombre: nombre,obtenerEdad: obtenerEdad,cambiarEdad: cambiarEdad
};}var persona =crearPersona("Juan");console.log(persona.nombre);// Acceso al atributo público "nombre"console.log(persona.obtenerEdad());// Acceso al atributo privado "edad"persona.cambiarEdad(30);// Modificación del atributo privado "edad"console.log(persona.obtenerEdad());// Acceso al atributo privado "edad" modificado
En este ejemplo, utilizamos una función llamada crearPersona para crear un objeto que encapsula tanto atributos privados como públicos. La variable edad se define dentro de la función y, por lo tanto, solo es accesible desde las funciones internas (obtenerEdad y cambiarEdad). El objeto devuelto por crearPersona solo expone las funciones públicas (nombre, obtenerEdad y cambiarEdad), lo que permite acceder a los atributos privados de manera controlada.
.
Aunque estos atributos no son estrictamente privados en el sentido tradicional, el uso de clausuras y técnicas similares nos permite ocultarlos y controlar el acceso a ellos.
.
Espero que esta explicación te ayude a entender cómo se pueden crear atributos públicos y privados en JavaScript. Si tienes más preguntas, no dudes en hacerlas.
Para el reto del profe deja una solución posible
functionverify(nameVerify){let blackList =["puto","marica","verga","idiota"];let verification =true;for(ind in blackList){if(nameVerify === blackList[ind]){ verification =false;}}if(verification){console.log("Cambio realizado con exito");}else{console.log("El nombre de usuario no esta permitido");}};
Puede usar la función “includes” que tienen los Arrays para ahorrarte un poco de código. Yo lo hice de esta manera: