Herramientas de usuario

Herramientas del sitio


informatica:programacion:cursos:programacion_avanzada_javascript:simbolos

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anteriorRevisión previa
Próxima revisión
Revisión previa
informatica:programacion:cursos:programacion_avanzada_javascript:simbolos [2024/10/17 09:43] – [DEMO: Símbolos como nombres de propiedades] tempwininformatica:programacion:cursos:programacion_avanzada_javascript:simbolos [2024/10/30 13:03] (actual) – [Variables privadas usando símbolos] tempwin
Línea 198: Línea 198:
 Dado el siguiente código, si miramos las propiedades que tiene obj tan solo obtendremos la propiedad v1. La otra propiedad (cuyo nombre es un símbolo) no la vemos de ninguna manera: Dado el siguiente código, si miramos las propiedades que tiene obj tan solo obtendremos la propiedad v1. La otra propiedad (cuyo nombre es un símbolo) no la vemos de ninguna manera:
  
-<WRAP center round todo 60%> +{{ :informatica:programacion:cursos:programacion_avanzada_javascript:15-propiedades-simbolo.png |}}
-Propiedades símbolo +
-</WRAP>+
  
 Se puede ver que la propiedad ''%%Symbol("v2")%%'' no se obtiene de ninguna manera. Para poder acceder a esta propiedad necesitamos el símbolo original. Ahora bien, **¿cuál es el valor de ''result'' en este código?** Se puede ver que la propiedad ''%%Symbol("v2")%%'' no se obtiene de ninguna manera. Para poder acceder a esta propiedad necesitamos el símbolo original. Ahora bien, **¿cuál es el valor de ''result'' en este código?**
Línea 287: Línea 285:
 </code> </code>
  
-Los símbolos nos dan otro mecanismo para definir propiedades privadas. +Los símbolos nos dan otro mecanismo para definir propiedades privadas, pero esto no impide que alguien utlizando ''Object.getOwnPropertySymbols(obj)'' pueda obtener los símbolos que se han utilizado para esas propiedades y acceder directamente a ellas. 
 + 
 +Si quisiéramos ocultar realmente una propiedad, no podemos usar símbolos. Deberíamos usar el revealing module pattern o utilizar el concepto de función constructora.
 ===== DEMO: Símbolos en valores ===== ===== DEMO: Símbolos en valores =====
  
 +<code javascript>
 +var handle = function(name) {
 + 
 +    var _name = name;
 +    var _status = "C"; // 'C' cerrado
 +    
 +    return {
 +        // getter para devolver la propiedad privada
 +        get name() { return _name; },
 +        get status() { return _status; },
 +        open() {
 +            if (_status == "C") {
 +                console.log("Abriendo " + _name);
 +                _status = "A";
 +            } else {
 +                console.log("Ya está abierto");
 +            }
 +        }
 +    }   
 +}
 +</code>
 +
 +Tras ejecutarlo:
 +
 +<code javascript>
 +var h = handle("test");
 +
 +h.name; // -> 'test'
 +h.status; // -> 'C'
 +
 +h.open(); 
 +// -> Abriendo test
 +h.open();
 +// -> Ya está abierto
 +</code>
 +
 +Para evitar colisiones con otros posibles valores, usaremos símbolos porque de esa manera tendremos valores únicos para nuestras propiedades y aumentamos la seguridad de nuestro código:
 +
 +<code javascript>
 +
 +var handle_status = {
 +    Abierto: Symbol("A"),
 +    Cerrado: Symbol("C")
 +}
 +
 +var handle = function(name) {
 + 
 +    var _name = name;
 +    var _status = handle_status.Cerrado;
 +    
 +    return {
 +        // getter para devolver la propiedad privada
 +        get name() { return _name; },
 +        get status() { return _status; },
 +        open() {
 +            if (_status === handle_status.Cerrado;) {
 +                console.log("Abriendo " + _name);
 +                _status = handle_status.Abierto;
 +            } else {
 +                console.log("Ya está abierto");
 +            }
 +        }
 +    }   
 +}
 +</code>
 +
 +Tras ejecutarlo:
 +
 +<code javascript>
 +var h = handle("edu");
 +
 +h; // -> Object { name: Getter, status: Getter, open: open() }
 +
 +h.name; // -> 'edu'h
 +
 +h.status; // -> Symbol(C)
 +
 +h.open(); 
 +// -> Abriendo edu
 +h.open();
 +// -> Ya está abierto
 +
 +h.status === handle_status.Abierto; // -> true
 +</code>
 ===== DEMO: Símbolos en nombres de métodos ===== ===== DEMO: Símbolos en nombres de métodos =====
  
 +Queremos hacer un objeto que sirva para mostrar información de otros objetos:
 +
 +<code javascript>
 +var Dumper = function() {
 +    this.dumpObject = function(obj) {
 +        console.log("Dumping object");
 +        if (typeof(obj["dump"]) == "function") {
 +            obj["dump"]();
 +        } else {
 +            for (var k in obj) {
 +                console.log(k, obj[k]);
 +            }
 +        }
 +    }
 +}
 +</code>
 +
 +Creamos un objeto:
 +
 +<code javascript>
 +var a = {v: 42, ov: 69, foo() {} };
 +
 +var b = {v: 42, ov: 69, foo() {}, dump() { console.log("dumping b"); } };
 +
 +var myDumper = new Dumper();
 +
 +myDumper.dumpObject(a);
 +
 +myDumper.dumpObject(b);
 +</code>
 +
 +Para evitar colisiones con otros métodos ''dump'':
 +
 +<code javascript>
 +var Dumper = function() {
 +    this.dumpObject = function(obj) {
 +        console.log("Dumping object");
 +        if (typeof(obj[Dumper.dump]) == "function") {
 +            obj[Dumper.dump]();
 +        } else {
 +            for (var k in obj) {
 +                console.log(k, obj[k]);
 +            }
 +        }
 +    }
 +}
 +
 +Dumper.dump = Symbol("dump");
 +
 +var a = {v: 42, ov: 69, foo() {}, [Dumper.dump]() { console.log("dumping a"); } };
 +
 +var myDumper = new Dumper();
 +
 +myDumper.dumpObject(a);
 +</code>
 +
 +Ahora este código no tendrá colisiones con ningún otro objeto.
 ===== Símbolos globales ===== ===== Símbolos globales =====
 +
 +A pesar de que el objetivo básico de los símbolos es proporcionar nombres únicos y evitar las colisiones, de forma que solo quien tenga acceso al símbolo original podrá reproducir este nombre, **ECMAScript 2015 da la posibilidad de crear símbolos globales**. Un símbolo global es un símbolo pero que cualquiera que conozca la cadena identificativa de este símbolo puede recrear:
 +
 +<code javascript>
 +var s1 = Symbol.for("s");
 +var s2 = Symbol.for("s");
 +s1 === s2;  // true
 +s1 == s2;   // true
 +var s3 = Symbol("s");
 +s1 === s3;  // false
 +var s4 = Symbol.for("s4");
 +s1 === s4;  // false
 +</code>
 +
 +Los símbolos globales se crean con ''Symbol.for()'' y se le pasa la cadena a usar como identificador. Cualquiera que conozca esta cadena puede usar de nuevo ''Symbol.for()'' para obtener el símbolo. En el código anterior se ve como ''s1'' y ''s2'' son iguales (ambas están creadas con ''Symbol.for'' y la misma cadena identificativa). Por otro lado ''s3'' no es igual a ''s1'' (o ''s2'') ya que, a pesar de usar la misma cadena identificativa, no se trata de un símbolo global. Por último, ''s4'' también es distinto de ''s1'' y ''s2'' ya que, a pesar de ser un símbolo global, se ha usado otra cadena identificativa para crearlo.
 +
 +Los símbolos globales permiten seguir usando símbolos para métodos o valores concretos, pero evitan el tener que exponer este símbolo para quien necesite usarlo.
 +
 +En el vídeo anterior, teníamos que exponer el símbolo a través de la variable ''Dumper.dump'', para que los usuarios de nuestro objeto ''Dumper'' pudiesen usar este símbolo para crear el método específico. Usando un símbolo global, no es necesario exponer el símbolo (basta con que los usuarios sepan el identificador y luego usen ''Symbol.for''). La contrapartida es que podemos volver a tener colisiones si dos objetos distintos esperan métodos (o propiedades) cuyo nombre sea el mismo símbolo global. Pero dado que el identificador es una cadena, la probabilidad de colisiones (si cada librería elige bien sus identificadores) es menor que usando simplemente nombres de métodos (que al tener que cumplir ciertas reglas sintácticas son más limitados).
 +
informatica/programacion/cursos/programacion_avanzada_javascript/simbolos.1729151023.txt.gz · Última modificación: por tempwin