No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Última oportunidad para asegurar tu aprendizaje por 1 año a precio especial

Antes: $249

Currency
$189/año

Paga en 4 cuotas sin intereses

Paga en 4 cuotas sin intereses
Suscríbete

Termina en:

0D
2H
6M
17S

Module pattern y namespaces: propiedades privadas en JavaScript

13/20
Recursos

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:

  1. 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:

    function isObject(subject) {
      return typeof subject == "object";
    }
    
    function isArray(subject) {
      return Array.isArray(subject);
    }
    
    function requiredParam(param) {
      throw new Error(param + " es obligatorio");
    }
    
    function createStudent({
      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.

  2. Crearemos las funciones con las que el usuario puede editar y leer el valor del atributo privado _name:

    function isObject(subject) {
      return typeof subject == "object";
    }
    
    function isArray(subject) {
      return Array.isArray(subject);
    }
    
    function requiredParam(param) {
      throw new Error(param + " es obligatorio");
    }
    
    function createStudent({
      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 ;
    }
    
  3. 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:

    function isObject(subject) {
      return typeof subject == "object";
    }
    
    function isArray(subject) {
      return Array.isArray(subject);
    }
    
    function requiredParam(param) {
      throw new Error(param + " es obligatorio");
    }
    
    function createStudent({
      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 objeto
    const juan = createStudent({ email: "[email protected]", name: "Juanito" });
    
    // Intentamos eliminar y alterar los métodos changeName y readName
    delete juan.changeName; // false
    delete juan.readName; // false
    juan.changeName = function (nombreImpostor) { // NO se ve afectada la función original
    	return "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. 🤔💪

Contribución creada por: Martín Álvarez (Platzi Contributor)

Aportes 28

Preguntas 11

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

o inicia sesión.

💚 Like si te enamoraste de Object.defineProperty con esta clase 👊

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 defineProperty
  Object.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,
    },
  });

Que buen maestro es Timothée Chalamet

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 😄

Todo era felicidad y entusiasmo hasta que llegué a estas últimas clases y cada vez me empecé a perder más 😥

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 ref. 💚

Hola! como estan?
Bien, ese pequeno reto del profe para que el usaurio no pueda hacer juan name = “nicolas”, lo resolvi de esta manera:

newName(name) {
            Object.defineProperty(juan, "name", {
                value: name,
                writable: false,
                configurable: true,
                enumerable: true,
            })
        },
        changeName(newName) {
            this.name = newName;
        },

En este punto estoy extremadamente perdido 😦

en este caso, object.freeze() no es posible usarlo debido al scope de las funciones

changeName(newName){
        
        const nombre = newName.toLowerCase()
        console.log(nombre)
        for(i in malaPalabras){
            if(nombre.includes(malaPalabras[i].toLowerCase())){
                return console.log(`Esta palabra esta prohibida`)
            }
        }
        this.firsName = newName
    }

ame la terrible palabra “PATAAAATAAAAA”

Para el reto del profe deja una solución posible

 function verify(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");
        }

};

Excelente explicación del profesor

Para poder solucionar lo planteado en el minuto 3:50 (hacer que el nombre no cambie después), se logra con Object.defineProperty. De esta forma:

changeName(newName){
            this.name = newName;
            Object.defineProperty(this, 'name', {
                writable: false,
            })
        },
//dentro del return de la función

Para el reto sobre nombres prohibidos, cree un array con la lista de nombres no permitidos.

const noNames = ["nombreProhibido", "nombreProhibido1", "nombreProhibido2"]

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.

changeName(newName) {
            if (noNames.includes(newName)) {
                console.warn("Nombre invalido, seleccione otro")
            } else {
                private._name = newName;
            }
        }
function verify(newName){
    const blackList = ["fuck","Bastard","Berk","Knob","Manky","Minger","Pillock"];
    for(ind in blackList){
        if(newName == blackList[ind]){
            return false;
        }else{
            return true;
        }
    }
}

if(verify(newName)){
                _private["_name"];
            }else{
                throw new Error(newName + " no es una palabra permitida >:(");
            }
        },

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

PATATAS!

vuelvo y digo…

ACTUALIZEN EL CURSO!!!

La mejor frase.
“Esto nos lleva a diferentes problemas"
o más bien
"A diferentes soluciones”

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:

function crearPersona(nombre) {
  var edad = 25;  // Atributo privado

  // Función que accede al atributo privado
  function obtenerEdad() {
    return edad;
  }

  // Función que modifica el atributo privado
  function cambiarEdad(nuevaEdad) {
    edad = nuevaEdad;
  }

  // Objeto que expone solo las funciones públicas
  return {
    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.

Patatas 🤬🤬🤬

Mi resumen:

// ### Evitar modificaciones en atributos de objetos

/*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:*/

function createStudent3({
    name,
    age
} = {}) {
    const privateAttributes = { //métodos privados
        "_name" : name,
    }
    const publicAttributes = {//lo que se podrá ver y manipular
        age,
        readName(){
            return privateAttributes["_name"];
        },
        changeName(param) {
            privateAttributes["_name"] = param;
        }
    }
    return publicAttributes;
}

const alfonso = createStudent3({name : "alfonso",age : 14});

console.log(alfonso);
/*
{
    age: 14,
    readName: [Function: readName],
    changeName: [Function: changeName]
}
*/
console.log(alfonso.readName()); //alfonso
alfonso.changeName("alfonsito"); //alfonso //solo a través del método changeName es posible cambiar el nombre, ya que no es posible hacerlo de manera directa
alfonso._name = "GOKU"; //No cambiará de nombre
console.log(alfonso.readName()); //alfonsito

//Sin embargo si lo dejamos así, se podrá modificar el valor de métodos, por lo que se usará Object.defineProperty() para evitar ello

Object.defineProperty(alfonso,"readName",{
    writable : false,
    configurable : false
})
Object.defineProperty(alfonso,"changeName",{
    writable : false,
    configurable : false
})

console.log(Object.getOwnPropertyDescriptors(alfonso));

/*
{
    age: { value: 14, writable: true, enumerable: true, configurable: true },
    readName: {
        value: [Function: readName],
        writable: false,
        enumerable: true,
        configurable: false
    },
    changeName: {
        value: [Function: changeName],
        writable: false,
        enumerable: true,
        configurable: false
    },
    _name: {
        value: 'GOKU',
        writable: true,
        enumerable: true,
        configurable: true
    }
}
*/

Con cada cosa nueva que veo de Javascript me hace desear más el momento de llegar a aprender Typescript.

Hoal! Este es mi codigo para poder firzar el retorno del objeto!

const isObject = (object) => {
    return typeof object == "object"
}//es un array o un objeto


function deepFreeze(obj) {

    for (key in obj) {
        let keyIsObject = isObject(obj[key])

        if(keyIsObject) {
             deepFreeze(obj[key])
        } else {
            Object.freeze(obj[key])
        }
    }

    return Object.freeze(obj)

}



function user({
    name, 
    contactInfo = requiredParam('contactInfo'), //parametro por defecto. Si no le paso el contactInfo, llamare a la fn contactInfo y retornara un error
    active = true,
    apellido,
    cursos = []
    } = {} )
    {
    


    return deepFreeze({
        name,
        contactInfo,
        addCourse(course) {
            this.cursos.push(course)
        },
        changeName(newName) {
            this.name = newName
        },
        active,
        apellido,
        cursos
    })


}