informatica:programacion:cursos:programacion_avanzada_javascript:simbolos
Diferencias
Muestra las diferencias entre dos versiones de la página.
| Ambos lados, revisión anteriorRevisión previaPróxima revisión | Revisión previa | ||
| informatica:programacion:cursos:programacion_avanzada_javascript:simbolos [2024/10/16 17:24] – [DEMO: Revealing Module Pattern] tempwin | informatica:programacion:cursos:programacion_avanzada_javascript:simbolos [2024/10/30 13:03] (actual) – [Variables privadas usando símbolos] tempwin | ||
|---|---|---|---|
| Línea 154: | Línea 154: | ||
| <code javascript> | <code javascript> | ||
| - | (function() { | + | var miModulo = (function() { |
| var value = 42; | var value = 42; | ||
| var foo = function(i) { | var foo = function(i) { | ||
| - | return i + 42; | + | return i + value * bar(); |
| } | } | ||
| + | | ||
| + | var bar = function() { return 10;} | ||
| | | ||
| return { | return { | ||
| - | | + | |
| + | foo: foo | ||
| } | } | ||
| })(); | })(); | ||
| </ | </ | ||
| + | |||
| + | La función '' | ||
| + | |||
| + | Al ejecutar el código anterior: | ||
| <code javascript> | <code javascript> | ||
| + | miModulo; // -> Object { foo: foo() } | ||
| + | |||
| + | miModulo.pFoo(10); | ||
| + | |||
| + | // Comprobamos que no podemos acceder a variables y funciones privadas: | ||
| + | miModulo.value; | ||
| + | miModulo.bar(); | ||
| + | miModulo.foo(); | ||
| </ | </ | ||
| + | ===== Variables privadas usando símbolos ===== | ||
| + | |||
| + | Los símbolos ofrecen un nuevo mecanismo para declarar variables privadas en un objeto. Para ello **podemos usar un símbolo como nombre de propiedad de un objeto**. Eso garantiza que solo quien tenga acceso al símbolo original podrá acceder a dicha propiedad, ya que no hay otro modo de obtener el nombre de la propiedad. | ||
| + | |||
| + | Las propiedades cuyo nombre es un símbolo no aparecen ni al usar '' | ||
| <code javascript> | <code javascript> | ||
| + | var obj={ | ||
| + | v1: 42, | ||
| + | | ||
| + | }; | ||
| </ | </ | ||
| + | |||
| + | 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: | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | Se puede ver que la propiedad '' | ||
| <code javascript> | <code javascript> | ||
| + | var obj={ | ||
| + | v1: 42, | ||
| + | [Symbol(" | ||
| + | }; | ||
| + | var result = obj[Symbol(" | ||
| </ | </ | ||
| - | ===== Variables privadas | + | Al finalizar este código el valor de '' |
| + | |||
| + | Por la misma razón el siguiente código no modifica el valor de la propiedad de 100 a 200, sino que crea otra propiedad con el valor 200 (distinta de la propiedad con el valor de 100). | ||
| + | |||
| + | <code javascript> | ||
| + | var obj={ | ||
| + | v1: 42, | ||
| + | [Symbol(" | ||
| + | }; | ||
| + | obj[Symbol(" | ||
| + | </ | ||
| + | |||
| + | Para acceder a la propiedad cuyo nombre es un símbolo necesitamos el símbolo original: | ||
| + | |||
| + | <code javascript> | ||
| + | var s = Symbol(" | ||
| + | var obj={ | ||
| + | v1: 42, | ||
| + | [s]: 100 | ||
| + | }; | ||
| + | var result | ||
| + | </ | ||
| + | |||
| + | Observa que colocamos la variable símbolo entre corchetes para acceder a la propiedad. Si no usásemos los corchetes simplemente estaríamos creando (o accediendo a) una propiedad llamada " | ||
| ===== DEMO: Símbolos como nombres de propiedades ===== | ===== DEMO: Símbolos como nombres de propiedades ===== | ||
| + | Un símbolo nos permite obtener un nombre único. | ||
| + | |||
| + | <code javascript> | ||
| + | var obj = { | ||
| + | [Symbol(" | ||
| + | v: 60 | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <code javascript> | ||
| + | obj; // -> Object { v: 60} | ||
| + | </ | ||
| + | |||
| + | No nos muestra la otra propiedad, la creada con el símbolo. Solo podemos acceder a ella utilizando el símbolo: | ||
| + | |||
| + | <code javascript> | ||
| + | obj[Symbol(" | ||
| + | |||
| + | Symbol(" | ||
| + | </ | ||
| + | |||
| + | Así que tendríamos que haber guardado el símbolo: | ||
| + | |||
| + | <code javascript> | ||
| + | var s = Symbol(" | ||
| + | |||
| + | var obj = { | ||
| + | [s]: 42, | ||
| + | v: 60 | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Tras ejecutarlo: | ||
| + | |||
| + | <code javascript> | ||
| + | obj[s]; // -> 42 | ||
| + | </ | ||
| + | |||
| + | Podríamos ver todos los símbolos usados como propiedad en un objeto con '' | ||
| + | |||
| + | <code javascript> | ||
| + | var sy = Object.getOwnPropertySymbols(obj); | ||
| + | |||
| + | sy; // -> Array[ Symbol(v) ] | ||
| + | |||
| + | obj[sy[0]]; // -> 42 | ||
| + | </ | ||
| + | |||
| + | Los símbolos nos dan otro mecanismo para definir propiedades privadas, pero esto no impide que alguien utlizando '' | ||
| + | |||
| + | 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 = " | ||
| + | | ||
| + | return { | ||
| + | // getter para devolver la propiedad privada | ||
| + | get name() { return _name; }, | ||
| + | get status() { return _status; }, | ||
| + | open() { | ||
| + | if (_status == " | ||
| + | console.log(" | ||
| + | _status = " | ||
| + | } else { | ||
| + | console.log(" | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Tras ejecutarlo: | ||
| + | |||
| + | <code javascript> | ||
| + | var h = handle(" | ||
| + | |||
| + | h.name; // -> ' | ||
| + | h.status; // -> ' | ||
| + | |||
| + | h.open(); | ||
| + | // -> Abriendo test | ||
| + | h.open(); | ||
| + | // -> Ya está abierto | ||
| + | </ | ||
| + | |||
| + | 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(" | ||
| + | Cerrado: Symbol(" | ||
| + | } | ||
| + | |||
| + | 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(" | ||
| + | _status = handle_status.Abierto; | ||
| + | } else { | ||
| + | console.log(" | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Tras ejecutarlo: | ||
| + | |||
| + | <code javascript> | ||
| + | var h = handle(" | ||
| + | |||
| + | h; // -> Object { name: Getter, status: Getter, open: open() } | ||
| + | |||
| + | h.name; // -> ' | ||
| + | |||
| + | h.status; // -> Symbol(C) | ||
| + | |||
| + | h.open(); | ||
| + | // -> Abriendo edu | ||
| + | h.open(); | ||
| + | // -> Ya está abierto | ||
| + | |||
| + | h.status === handle_status.Abierto; | ||
| + | </ | ||
| ===== 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(" | ||
| + | if (typeof(obj[" | ||
| + | obj[" | ||
| + | } else { | ||
| + | for (var k in obj) { | ||
| + | console.log(k, | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Creamos un objeto: | ||
| + | |||
| + | <code javascript> | ||
| + | var a = {v: 42, ov: 69, foo() {} }; | ||
| + | |||
| + | var b = {v: 42, ov: 69, foo() {}, dump() { console.log(" | ||
| + | |||
| + | var myDumper = new Dumper(); | ||
| + | |||
| + | myDumper.dumpObject(a); | ||
| + | |||
| + | myDumper.dumpObject(b); | ||
| + | </ | ||
| + | |||
| + | Para evitar colisiones con otros métodos '' | ||
| + | |||
| + | <code javascript> | ||
| + | var Dumper = function() { | ||
| + | this.dumpObject = function(obj) { | ||
| + | console.log(" | ||
| + | if (typeof(obj[Dumper.dump]) == " | ||
| + | obj[Dumper.dump](); | ||
| + | } else { | ||
| + | for (var k in obj) { | ||
| + | console.log(k, | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | Dumper.dump = Symbol(" | ||
| + | |||
| + | var a = {v: 42, ov: 69, foo() {}, [Dumper.dump]() { console.log(" | ||
| + | |||
| + | var myDumper = new Dumper(); | ||
| + | |||
| + | myDumper.dumpObject(a); | ||
| + | </ | ||
| + | |||
| + | 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(" | ||
| + | var s2 = Symbol.for(" | ||
| + | s1 === s2; // true | ||
| + | s1 == s2; // true | ||
| + | var s3 = Symbol(" | ||
| + | s1 === s3; // false | ||
| + | var s4 = Symbol.for(" | ||
| + | s1 === s4; // false | ||
| + | </ | ||
| + | |||
| + | Los símbolos globales se crean con '' | ||
| + | |||
| + | 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 '' | ||
| + | |||
informatica/programacion/cursos/programacion_avanzada_javascript/simbolos.1729092262.txt.gz · Última modificación: por tempwin
