Domar thisJavaScript con el operador Bind

 

 

 

  • Patrones de diseño de interfaces inteligentes, vídeo de 10h + formación UX
  • Implemente rápidamente. Implementar inteligentemente

  • Índice
    1. thisEn el ámbito global
    2. thisEn el ámbito de la función
      1. ¿ Cuál es el valor de thisaquí?
      2. Establecer un valor en this:
    3. Esta palabra clave en modo estricto
    4. Hacer que thislas variables sean predecibles
      1. Llamar a una función conocida thispara proporcionar contexto:
      2. Extrayendo un método
    5. El operador de enlace::
    6. Cómo desarrollar utilizando el operador Bind
    7. Ventajas y desventajas del operador de enlace
    8. Conclusión

    Tratar con thisJavaScript puede ser complicado. Pero, ¿qué pasaría si en lugar de luchar contra él pudiéramos aprovecharlo para lograr cosas interesantes como la composición de funciones con métodos virtuales? Esto es lo que vamos a explorar en este artículo sobre una de las posibles funciones futuras de JavaScript: el operador Bind.

     

    ¿Quiere descubrir las próximas funciones interesantes de JavaScript que ni siquiera sabía que necesitaba? En este artículo, presentaré una de estas propuestas que, si se acepta, puede cambiar la forma en que se escribe el código de la misma manera que lo hizo el operador de extensión .

    Sin embargo, aquí hay un pequeño descargo de responsabilidad: esta característica está en desarrollo y discusión . El objetivo aquí es agregar algo de publicidad a su alrededor y crear conciencia sobre el arduo trabajo que está haciendo TC39 para encontrar consenso, solucionar todos los problemas de sintaxis y semántica y enviarlo con las próximas versiones de ECMAScript. Si tiene alguna inquietud, comentario o desea expresar su apoyo, vaya al repositorio de propuestas del TC39 , agregue una estrella a esta función para mostrar su apoyo, abra un problema para expresar sus inquietudes y participe.

     

    Pero antes, quiero hacer una pregunta sencilla (pero complicada):

    Qué es this ?

    En ECMAScript, thistiene una semántica diferente a la thisde muchos otros lenguajes de programación, donde thisa menudo se hace referencia al alcance léxico. En general, esto se comporta de manera diferente en el ámbito global, dentro de una función, en modo no estricto y en modo estricto. Dividamos este comportamiento en pequeños ejemplos.

    thisEn el ámbito global

    ¿Cuál es el valor de thisen este ejemplo?

    console.info(this);

    En el ámbito global, thisse refiere al objeto global, como la ventana del navegador, los trabajadores web self y el objeto module.exports en NodeJS.

    thisEn el ámbito de la función

    En el ámbito de la función, thisse comporta dependiendo de cómo se llama la función, y este aspecto dificulta la predicción de su valor. Podemos entenderlo mejor comprobando los siguientes ejemplos:

    ¿ Cuál es el valor de thisaquí?

    function foo() { return this;}console.info(this);

    Dentro de una función, thisempieza a tener un comportamiento interesante ya que su valor depende de cómo se llame a la función. En el ejemplo anterior, thistodavía se refiere al ámbito global, con una diferencia. En NodeJs, esto apuntará al objeto global en lugar de module.exports.

    Establecer un valor en this:

    function foo() { this.bar = 'baz'; return this;}console.info(foo());console.info(new foo());

    Establecer un valor en thisestablece el valor en el contexto actual. El ejemplo anterior registra el alcance global con la propiedad barcon el valor bazen el primero console.info, pero registra sólo { bar: ‘baz’ }en el segundo console.info. Sucede porque el newoperador, entre otras cosas, vincula el valor de thisal objeto recién creado.

    Esta palabra clave en modo estricto

    En modo estricto, la thisvariable no lleva el valor del contexto implícitamente, esto significa que si su contexto no está establecido, el valor predeterminado es undefinedcomo se muestra en el siguiente fragmento.

    function foo() { "use strict"; return this;}console.info(foo()); //undefined

    Para establecer el contexto thisen modo estricto, puede configurar la función como miembro de un objeto, usar newoperador, Function.prototype.call()o Function.prototype.apply()métodos Function.prototype.bind(), por ejemplo.

     

    function foo() { "use strict"; return this;}var a = { foo };foo(); // undefineda.foo(); // { foo: ƒunction }new foo(); // Object foo {}foo.call(this); // Window / Global Objectfoo.apply(this); // Window / Global Objectfoo.bind(this)(); // Window / Global Object

    Hacer que thislas variables sean predecibles

    En este punto, puede que te des cuenta de que el valor de thisen ECMAScript es bastante complicado de predecir. Para demostrar las técnicas disponibles para hacerlo predecible, me gustaría presentar el siguiente ejemplo que imita un caso de uso común de this.

    button /buttonscript class MeowctComponent { constructor() { this.paw = document.getElementById('button'); } meow() { console.info(' on this: ', this.paw); } } const cat = new MeowctComponent(); cat.paw.addEventListener('click', cat.meow);/script

    En el ejemplo anterior, creé un MeowctComponent, que tiene solo una propiedad pawque apunta al elemento del botón y un método llamado meowque debería imprimir la propiedad de la instancia de la pata en la consola.

    La parte complicada es que el método maullido se ejecuta solo cuando se hace clic en el botón y, debido a eso, thistiene la etiqueta del botón como contexto y, dado que la etiqueta del botón no tiene ninguna propiedad de pata, registra el valor indefinido en la consola. Complicado, ¿no?

    Para corregir este comportamiento específico, podemos aprovechar el Function.prototype.bind()método para vincularlo explícitamente a la instancia cat, como en el siguiente ejemplo:

    buttonMeow/buttonscript class MeowctComponent { constructor() { this.paw = document.getElementById('button'); } meow() { console.info(' on this: ', this.paw); } } const cat = new MeowctComponent(); cat.paw.addEventListener('click', cat.meow.bind(cat));/script

    El método .bind()devuelve una nueva función vinculada permanentemente al primer parámetro dado, que es el contexto. Ahora, debido a que vinculamos el cat.meowmétodo a la catinstancia, this.pawdentro del método meow apunta correctamente al elemento del botón .

    Como alternativa al Function.prototype.bind()método, podemos usar la función de flecha para lograr el mismo resultado. Mantiene el valor del léxico thisdel contexto circundante y elimina la necesidad de vincular el contexto explícitamente, como en el siguiente ejemplo:

    button Meow/buttonscript class MeowctComponent { constructor() { this.paw = document.getElementById('button'); } meow() { console.info(' on this: ', this.paw); } } const cat = new MeowctComponent(); cat.paw.addEventListener('click', () = cat.meow());/script

    Aunque las funciones de flecha resuelven la mayoría de los casos de uso en los que necesitamos vincular el léxico thisexplícitamente, todavía tenemos dos casos de uso para los que se necesita el uso de la vinculación explícita. Recetas faciles y rápidas

     

    Llamar a una función conocida thispara proporcionar contexto:

    let hasOwnProp = Object.prototype.hasOwnProperty;let obj = Object.create(null);obj.hasOwnProperty('x') // Type Error...hasOwnProp.call(obj, "x"); //falseobj.x = 100;hasOwnProp.call(obj, "x"); // true

    Supongamos que por alguna razón tenemos este objobjeto que no se extiende Object.prototypepero necesitamos verificar si objtiene una xpropiedad usando el hasOwnPropertymétodo from Object.prototype. Para lograr eso, tenemos que usar el método call y pasarlo explícitamente objcomo primer parámetro para que funcione como se esperaba, lo que parece no ser tan idiomático.

    Extrayendo un método

    El segundo caso se puede detectar cuando necesitamos extraer un método de un objeto como en nuestro MeowctComponentejemplo:

    button /buttonscript class MeowctComponent { constructor() { this.paw = document.getElementById('button'); } meow() { console.info(' on this: ', this.paw); } } const cat = new MeowctComponent(); cat.paw.addEventListener('click', cat.meow.bind(cat));/script

    Estos casos de uso son el problema básico que el operador de vinculación intenta resolver.

    El operador de enlace::

    El operador Bind consiste en la introducción de un nuevo operador ::(dos dos puntos), que actúa como azúcar de sintaxis para los dos casos de uso anteriores. Viene en dos formatos: binario y unario .

    En su forma binaria, el operador de vinculación crea una función con su lado izquierdo vinculado thisal lado derecho, como en el siguiente ejemplo:

    let hasOwnProp = Object.prototype.hasOwnProperty;let obj = Object.create(null);obj.hasOwnProperty('x') // Type Error...obj::hasOwnProp("x"); //falseobj.x = 100;obj::hasOwnProp("x"); // true

    Eso parece más natural, ¿no?

    En su forma unaria, el operador crea una función vinculada a la base de la referencia proporcionada como un valor para thisla variable, como en el siguiente ejemplo:

    ...cat.paw.addEventListener('click', ::cat.meow);// which desugars tocat.paw.addEventListener('click', cat.meow.bind(cat));...

    Lo interesante del operador de vinculación es el hecho de que abre nuevas oportunidades para crear métodos virtuales, como en este ejemplo de lib para iterable.

    import { map, takeWhile, forEach } from "iterlib";getPlayers() ::map(x = x.character()) ::takeWhile(x = x.strength 100) ::forEach(x = console.log(x));

    Es muy útil porque el desarrollador no necesita descargar toda la biblioteca para hacer cosas pequeñas, lo que reduce la cantidad de JavaScript importado. Además, hace que ese tipo de bibliotecas sea más fácil de ampliar.

    Cómo desarrollar utilizando el operador Bind

    Para mantener el ejemplo simple, supongamos que necesitamos crear un módulo matemático en el que el desarrollador pueda encadenar las operaciones para formar una expresión matemática que, dado un número como entrada, pueda realizar todos los cálculos en una tubería. El código para lograr esto es simple y podría escribirse de la siguiente manera.

     

    function plus(x) { return this + x;}function minus(x) { return this - x;}function times(x) { return this * x;}function div(x) { return this / x;}

    Como puede ver en el ejemplo anterior, esperamos tener el valor como contexto y lo usamos para hacer el cálculo, por lo que luego, usando el operador de vinculación, podríamos hacer una expresión como la siguiente:

    1::plus(2)::times(4)::div(3)::minus(1); // returns 3

    Lo que equivale a:

    minus.call(div.call(times.call(plus.call(1, 2), 4), 3), 1);

    El primer fragmento parece más idiomático, ¿no?

    Yendo un poco más allá, podemos usarlo para convertir una temperatura de Celsius a Fahrenheit, esto se puede lograr mediante la siguiente expresión de función:

    const toFahrenheit = x = x::times(9)::div(5)::plus(32);console.info(toFahrenheit(20)); // 68

    Hasta ahora, hemos demostrado cómo crear funciones para interactuar con los valores, pero ¿qué pasa con la extensión del objeto con métodos virtuales? Podemos crear nuevas composiciones de transmisiones combinando métodos integrados con métodos personalizados. Para demostrarlo, podemos componer métodos de cadena con métodos personalizados. Primero, verifiquemos el módulo con los métodos personalizados con su implementación.

    function capitalize() { return this.replace(/(?:^|s)S/g, a = a.toUpperCase());}function doubleSay() { return `${this} ${this}`;}function exclamation() { return `${this}!`;}

    Con este módulo implementado podemos hacer cosas interesantes como las siguientes:

    const { trim, padEnd } = String.prototype;console.info( ' hello world ' ::trim() ::capitalize() ::doubleSay() ::exclamation() ::padEnd(30));// "Hello World Hello World! "

    En el ejemplo anterior, puedes ver que extraje dos métodos de String.prototype, trim()y padEnd(). Dado que estos métodos se extraen, puedo usarlos para componer mi flujo de métodos junto con mis métodos virtuales capitalize()y doubleSay(). exclamation()Este aspecto es lo que hace que el operador de enlace sea tan interesante y prometedor.

    Ventajas y desventajas del operador de enlace

    Como te habrás dado cuenta llegados a este punto, hay algunos aspectos en los que Bind Operador destaca. Esos son los siguientes:

    • Cubre los dos únicos casos de uso que faltan en los que es necesaria una vinculación explícita;
    • Hace que sea fácil hacer que thislas variables sean predecibles;
    • Agrega una nueva forma de ampliar la funcionalidad mediante el uso de métodos virtuales;
    • Ayuda a ampliar los objetos integrados sin ampliar la cadena del prototipo. ¿Recuerdas Smoosh Gate ?

    Por otro lado, para componer funciones con el operador de vinculación, debe confiar en esto para vincularse, lo que puede generar algunos problemas como en este ejemplo:

    const plus = (x) = this + x;console.info(1::plus(1));// "[object Window]1"

    Como queda claro en el ejemplo anterior, no es posible componer una función de flecha con el operador de vinculación, ya que no es posible vincularse thisa una función de flecha. A veces los usuarios no quieren depender thisde estar obligados a componer su comportamiento a través de una cadena de funciones, lo que podría ser un problema si solo se utiliza el operador de enlace para lograrlo.

    Otro problema que se menciona a menudo es la posible sobrecarga de sintaxis que puede generar el operador de enlace, lo que puede ser un problema para los recién llegados al idioma. También es complicado darse cuenta de que un operador específico funciona en forma binaria y unaria. Una posible solución para esto es introducir la forma binaria en el lenguaje por separado de la forma unaria. Entonces, una vez que la forma binaria se integra al lenguaje, el comité puede reevaluar si la forma unaria aún es necesaria. Mientras tanto, los usuarios pueden acostumbrarse a la forma binaria y la sobrecarga de sintaxis podría mitigarse.

    Conclusión

    Predecir el valor de thisen JavaScript es un truco. El lenguaje tiene algunas reglas para explicar cómo se asigna el contexto a esto, pero en el día a día queremos que este valor sea predecible. El Function.prototype.bind()método y las funciones de flecha nos ayudan a hacer thispredecible el valor de. El operador de vinculación entra en juego para cubrir los dos casos de uso que aún necesitamos vincular explícitamente this.

    La llegada del operador de enlace abre una oportunidad para crear un nuevo conjunto de composición de funciones a través de métodos virtuales, pero puede agregar una sobrecarga de sintaxis que dificulta la incorporación de recién llegados al lenguaje.

    El autor del operador de enlace es Kevin Smith y esta propuesta se encuentra en la Etapa 0 . El TC39 está abierto a recibir comentarios. Si le gusta esta función y cree que es útil, agregue una estrella en el repositorio, si tiene una idea para resolver los problemas presentados aquí, si tiene otra forma de dar forma a la sintaxis o semántica de estas funciones o si detecta otra. Si tiene algún problema, abra un problema en el repositorio y comparta sus pensamientos/ideas con el comité.

    (dm, ra, yk, il)Explora más en

    • javascript





    Tal vez te puede interesar:

    1. ¿Deberían abrirse los enlaces en ventanas nuevas?
    2. 24 excelentes tutoriales de AJAX
    3. 70 técnicas nuevas y útiles de AJAX y JavaScript
    4. Más de 45 excelentes recursos y repositorios de fragmentos de código

    Domar thisJavaScript con el operador Bind

    Domar thisJavaScript con el operador Bind

    Patrones de diseño de interfaces inteligentes, vídeo de 10h + formación UX Implemente rápidamente. Implementar inteligentemente Índice

    programar

    es

    https://aprendeprogramando.es/static/images/programar-domar-thisjavascript-con-el-operador-bind-937-0.jpg

    2024-05-20

     

    Domar thisJavaScript con el operador Bind
    Domar thisJavaScript con el operador Bind

    Si crees que alguno de los contenidos (texto, imagenes o multimedia) en esta página infringe tus derechos relativos a propiedad intelectual, marcas registradas o cualquier otro de tus derechos, por favor ponte en contacto con nosotros en el mail [email protected] y retiraremos este contenido inmediatamente

     

     

    Top 20