diff --git a/1-js/06-advanced-functions/10-bind/2-write-to-object-after-bind/solution.md b/1-js/06-advanced-functions/10-bind/2-write-to-object-after-bind/solution.md index 737a14481..7b786e286 100644 --- a/1-js/06-advanced-functions/10-bind/2-write-to-object-after-bind/solution.md +++ b/1-js/06-advanced-functions/10-bind/2-write-to-object-after-bind/solution.md @@ -1,4 +1,4 @@ -The answer: `null`. +Respuesta: `null`. ```js run @@ -13,6 +13,6 @@ let user = { user.g(); ``` -The context of a bound function is hard-fixed. There's just no way to further change it. +El contexto de una función enlazada es fijo. Simplemente no hay forma de cambiarlo más. -So even while we run `user.g()`, the original function is called with `this=null`. +Entonces, incluso mientras ejecutamos `user.g()`, la función original se llama con `this = null`. diff --git a/1-js/06-advanced-functions/10-bind/2-write-to-object-after-bind/task.md b/1-js/06-advanced-functions/10-bind/2-write-to-object-after-bind/task.md index 6d7e1fb24..c9bb09d58 100644 --- a/1-js/06-advanced-functions/10-bind/2-write-to-object-after-bind/task.md +++ b/1-js/06-advanced-functions/10-bind/2-write-to-object-after-bind/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# Bound function as a method +# Función enlazada como método -What will be the output? +¿Cuál será el resultado? ```js function f() { diff --git a/1-js/06-advanced-functions/10-bind/3-second-bind/solution.md b/1-js/06-advanced-functions/10-bind/3-second-bind/solution.md index 97e1c2809..aa3d2f20b 100644 --- a/1-js/06-advanced-functions/10-bind/3-second-bind/solution.md +++ b/1-js/06-advanced-functions/10-bind/3-second-bind/solution.md @@ -1,4 +1,4 @@ -The answer: **John**. +Respuesta: **John**. ```js run no-beautify function f() { @@ -10,6 +10,6 @@ f = f.bind( {name: "John"} ).bind( {name: "Pete"} ); f(); // John ``` -The exotic [bound function](https://tc39.github.io/ecma262/#sec-bound-function-exotic-objects) object returned by `f.bind(...)` remembers the context (and arguments if provided) only at creation time. +El objeto exótico [bound function](https://tc39.github.io/ecma262/#sec-bound-function-exotic-objects) devuelto por `f.bind(...)` recuerda el contexto (y los argumentos si se proporcionan) solo en el momento de la creación. -A function cannot be re-bound. +Una función no se puede volver a vincular. diff --git a/1-js/06-advanced-functions/10-bind/3-second-bind/task.md b/1-js/06-advanced-functions/10-bind/3-second-bind/task.md index 5daf053c6..dd6821223 100644 --- a/1-js/06-advanced-functions/10-bind/3-second-bind/task.md +++ b/1-js/06-advanced-functions/10-bind/3-second-bind/task.md @@ -2,11 +2,11 @@ importance: 5 --- -# Second bind +# Segundo enlace -Can we change `this` by additional binding? +¿Podemos cambiar `this` por un enlace adicional? -What will be the output? +¿Cuál será el resultado? ```js no-beautify function f() { diff --git a/1-js/06-advanced-functions/10-bind/4-function-property-after-bind/solution.md b/1-js/06-advanced-functions/10-bind/4-function-property-after-bind/solution.md index 181555d95..b5cfc3c6f 100644 --- a/1-js/06-advanced-functions/10-bind/4-function-property-after-bind/solution.md +++ b/1-js/06-advanced-functions/10-bind/4-function-property-after-bind/solution.md @@ -1,4 +1,4 @@ -The answer: `undefined`. +Respuesta: `undefined`. -The result of `bind` is another object. It does not have the `test` property. +El resultado de `bind` es otro objeto. No tiene la propiedad `test`. diff --git a/1-js/06-advanced-functions/10-bind/4-function-property-after-bind/task.md b/1-js/06-advanced-functions/10-bind/4-function-property-after-bind/task.md index d6cfb44bf..c82938452 100644 --- a/1-js/06-advanced-functions/10-bind/4-function-property-after-bind/task.md +++ b/1-js/06-advanced-functions/10-bind/4-function-property-after-bind/task.md @@ -2,9 +2,10 @@ importance: 5 --- -# Function property after bind +# Propiedad de función después del enlace -There's a value in the property of a function. Will it change after `bind`? Why, or why not? + +Hay un valor en la propiedad de una función. ¿Cambiará después de `bind`? ¿Por qué sí o por qué no? ```js run function sayHi() { @@ -17,7 +18,7 @@ let bound = sayHi.bind({ name: "John" }); -alert( bound.test ); // what will be the output? why? +alert( bound.test ); // ¿Cuál será la salida? ¿por qué? */!* ``` diff --git a/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md b/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md index 403107ca6..bf079db40 100644 --- a/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md +++ b/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md @@ -1,9 +1,9 @@ -The error occurs because `ask` gets functions `loginOk/loginFail` without the object. +El error se produce porque `ask` obtiene las funciones `loginOk/loginFail` sin el objeto. -When it calls them, they naturally assume `this=undefined`. +Cuando los llama, asumen naturalmente `this = undefined`. -Let's `bind` the context: +Vamos a usar `bind` para enlazar el contexto: ```js run function askPassword(ok, fail) { @@ -30,14 +30,18 @@ askPassword(user.loginOk.bind(user), user.loginFail.bind(user)); */!* ``` -Now it works. +Ahora funciona. -An alternative solution could be: +Una solución alternativa podría ser: ```js //... askPassword(() => user.loginOk(), () => user.loginFail()); ``` -Usually that also works and looks good. + +Por lo general, eso también funciona y se ve bien. + +Aunque es un poco menos confiable en situaciones más complejas donde la variable `user` podría cambiar *después* de que se llama a `askPassword`, *antes* de que el visitante responde y llame a `() => user.loginOk ()`. + It's a bit less reliable though in more complex situations where `user` variable might change *after* `askPassword` is called, but *before* the visitor answers and calls `() => user.loginOk()`. diff --git a/1-js/06-advanced-functions/10-bind/5-question-use-bind/task.md b/1-js/06-advanced-functions/10-bind/5-question-use-bind/task.md index fe6a9b4eb..e641341b4 100644 --- a/1-js/06-advanced-functions/10-bind/5-question-use-bind/task.md +++ b/1-js/06-advanced-functions/10-bind/5-question-use-bind/task.md @@ -2,13 +2,14 @@ importance: 5 --- -# Fix a function that loses "this" -The call to `askPassword()` in the code below should check the password and then call `user.loginOk/loginFail` depending on the answer. +# Arreglar una función que perdió "this" -But it leads to an error. Why? +La llamada a `askPassword()` en el código a continuación debe verificar la contraseña y luego llamar a `user.loginOk/loginFail` dependiendo de la respuesta. -Fix the highlighted line for everything to start working right (other lines are not to be changed). +Pero lleva a un error. ¿Por qué? + +Arregle la línea resaltada para que todo comience a funcionar correctamente (no se deben cambiar otras líneas). ```js run function askPassword(ok, fail) { diff --git a/1-js/06-advanced-functions/10-bind/6-ask-partial/solution.md b/1-js/06-advanced-functions/10-bind/6-ask-partial/solution.md index 3284c943b..b6f4f60dd 100644 --- a/1-js/06-advanced-functions/10-bind/6-ask-partial/solution.md +++ b/1-js/06-advanced-functions/10-bind/6-ask-partial/solution.md @@ -1,14 +1,17 @@ -1. Either use a wrapper function, an arrow to be concise: + +1. Utilice una función wrapper (envoltura), de tipo arrow (flecha) para ser conciso: ```js askPassword(() => user.login(true), () => user.login(false)); ``` - Now it gets `user` from outer variables and runs it the normal way. -2. Or create a partial function from `user.login` that uses `user` as the context and has the correct first argument: + Ahora obtiene `user` de variables externas y lo ejecuta de la manera normal. + +2. O cree una función parcial desde `user.login` que use `user` como contexto y tenga el primer argumento correcto: + ```js diff --git a/1-js/06-advanced-functions/10-bind/6-ask-partial/task.md b/1-js/06-advanced-functions/10-bind/6-ask-partial/task.md index c90851c2b..48a949b8c 100644 --- a/1-js/06-advanced-functions/10-bind/6-ask-partial/task.md +++ b/1-js/06-advanced-functions/10-bind/6-ask-partial/task.md @@ -2,13 +2,15 @@ importance: 5 --- -# Partial application for login -The task is a little more complex variant of . +# Aplicación parcial para inicio de sesión -The `user` object was modified. Now instead of two functions `loginOk/loginFail`, it has a single function `user.login(true/false)`. +La tarea es una variante un poco más compleja de . + +El objeto `user` fue modificado. Ahora, en lugar de dos funciones `loginOk/loginFail`, tiene una sola función `user.login(true/false) `. + +¿Qué deberíamos pasar a `askPassword` en el código a continuación, para que llame a `user.login(true)` como `ok` y `user.login(false)` como `fail`? -What should we pass `askPassword` in the code below, so that it calls `user.login(true)` as `ok` and `user.login(false)` as `fail`? ```js function askPassword(ok, fail) { @@ -30,5 +32,7 @@ askPassword(?, ?); // ? */!* ``` -Your changes should only modify the highlighted fragment. + +Sus cambios solo deberían modificar el fragmento resaltado. + diff --git a/1-js/06-advanced-functions/10-bind/article.md b/1-js/06-advanced-functions/10-bind/article.md index 787c7d68e..6df39ce9f 100644 --- a/1-js/06-advanced-functions/10-bind/article.md +++ b/1-js/06-advanced-functions/10-bind/article.md @@ -3,17 +3,21 @@ libs: --- -# Function binding +# Función binding (vinculadora) -When passing object methods as callbacks, for instance to `setTimeout`, there's a known problem: "losing `this`". -In this chapter we'll see the ways to fix it. +Al pasar métodos de objeto como devoluciones de llamada, por ejemplo a `setTimeout`, se genera un problema conocido: "pérdida de `this`". -## Losing "this" +En este capítulo veremos las formas de solucionarlo. -We've already seen examples of losing `this`. Once a method is passed somewhere separately from the object -- `this` is lost. -Here's how it may happen with `setTimeout`: +## Pérdida de "this" + + +Ya hemos visto ejemplos de pérdida de `this`. Una vez que se pasa un método en algún lugar separado del objeto -- `this` se pierde. + + +Así es como puede suceder con `setTimeout`: ```js run let user = { @@ -28,22 +32,24 @@ setTimeout(user.sayHi, 1000); // Hello, undefined! */!* ``` -As we can see, the output shows not "John" as `this.firstName`, but `undefined`! +Como podemos ver, el resultado no muestra "John" como `this.firstName`, ¡sino como `undefined`! -That's because `setTimeout` got the function `user.sayHi`, separately from the object. The last line can be rewritten as: +Esto se debe a que `setTimeout` tiene la función `user.sayHi`, separada del objeto. La última línea se puede reescribir como: ```js let f = user.sayHi; -setTimeout(f, 1000); // lost user context +setTimeout(f, 1000); // user pierde el contexto ``` -The method `setTimeout` in-browser is a little special: it sets `this=window` for the function call (for Node.js, `this` becomes the timer object, but doesn't really matter here). So for `this.firstName` it tries to get `window.firstName`, which does not exist. In other similar cases, usually `this` just becomes `undefined`. -The task is quite typical -- we want to pass an object method somewhere else (here -- to the scheduler) where it will be called. How to make sure that it will be called in the right context? +El método `setTimeout` en el navegador es un poco especial: establece `this = window` para la llamada a la función (para Node.js, `this` se convierte en el objeto temporizador (timer), pero realmente no importa aquí). Entonces, en `this.firstName` intenta obtener `window.firstName`, que no existe. En otros casos similares, `this` simplemente se vuelve `undefined`. -## Solution 1: a wrapper -The simplest solution is to use a wrapping function: +La tarea es bastante típica --queremos pasar un método de objeto a otro lugar (aquí --al planificador) donde se llamará. ¿Cómo asegurarse de que se llamará en el contexto correcto? + +## Solución 1: un wrapper (envoltura) + +La solución más simple es usar una función wrapper (envoltura): ```js run let user = { @@ -60,17 +66,17 @@ setTimeout(function() { */!* ``` -Now it works, because it receives `user` from the outer lexical environment, and then calls the method normally. +Ahora funciona, porque recibe a `user` del entorno léxico externo, y luego llama al método normalmente. -The same, but shorter: +Aquí hacemos lo mismo, pero de otra manera: ```js setTimeout(() => user.sayHi(), 1000); // Hello, John! ``` -Looks fine, but a slight vulnerability appears in our code structure. +Se ve bien, pero aparece una ligera vulnerabilidad en nuestra estructura de código.. -What if before `setTimeout` triggers (there's one second delay!) `user` changes value? Then, suddenly, it will call the wrong object! +¿Qué pasa si antes de que `setTimeout` se active (¡hay un segundo retraso!) `user` cambia el valor? Entonces, de repente, ¡llamará al objeto equivocado! ```js run @@ -83,32 +89,38 @@ let user = { setTimeout(() => user.sayHi(), 1000); -// ...the value of user changes within 1 second + +// ...el valor de user cambia en 1 segundo + user = { sayHi() { alert("Another user in setTimeout!"); } }; -// Another user in setTimeout! + +// Otro user en setTimeout! + ``` -The next solution guarantees that such thing won't happen. +La siguiente solución garantiza que tal cosa no sucederá. -## Solution 2: bind +## Solución 2: bind -Functions provide a built-in method [bind](mdn:js/Function/bind) that allows to fix `this`. +Las funciones proporcionan un método incorporado [bind](mdn:js/Function/bind) que permite encontrar a `this`. -The basic syntax is: +La sintaxis básica es: ```js -// more complex syntax will come a little later + +// la sintaxis más compleja vendrá un poco más tarde + let boundFunc = func.bind(context); ``` -The result of `func.bind(context)` is a special function-like "exotic object", that is callable as function and transparently passes the call to `func` setting `this=context`. +El resultado de `func.bind(context)` es un "objeto exótico", una función similar a una función regular, que se puede llamar como función y pasa la llamada de forma transparente a `func` estableciendo `this = context`. -In other words, calling `boundFunc` is like `func` with fixed `this`. +En otras palabras, llamar a `boundFunc` es como `func` con un `this` fijo. -For instance, here `funcUser` passes a call to `func` with `this=user`: +Por ejemplo, aquí `funcUser` pasa una llamada a `func` con `this = user`: ```js run let user = { @@ -125,9 +137,9 @@ funcUser(); // John */!* ``` -Here `func.bind(user)` as a "bound variant" of `func`, with fixed `this=user`. +Aquí `func.bind(user)` es como una "variante ligada" de `func`, con `this = user` fijo en ella. -All arguments are passed to the original `func` "as is", for instance: +Todos los argumentos se pasan al `func` original "tal cual", por ejemplo: ```js run let user = { @@ -138,15 +150,15 @@ function func(phrase) { alert(phrase + ', ' + this.firstName); } -// bind this to user +// vincula this a user let funcUser = func.bind(user); *!* -funcUser("Hello"); // Hello, John (argument "Hello" is passed, and this=user) +funcUser("Hello"); // Hello, John (argumento "Hello" se pasa, y this=user) */!* ``` -Now let's try with an object method: +Ahora intentemos con un método de objeto: ```js run @@ -161,21 +173,23 @@ let user = { let sayHi = user.sayHi.bind(user); // (*) */!* -// can run it without an object +// puede ejecutarlo sin un objeto + sayHi(); // Hello, John! setTimeout(sayHi, 1000); // Hello, John! -// even if the value of user changes within 1 second -// sayHi uses the pre-bound value +// incluso si el valor del usuario cambia en 1 segundo +// sayHi usa el valor pre-enlazado + user = { sayHi() { alert("Another user in setTimeout!"); } }; ``` -In the line `(*)` we take the method `user.sayHi` and bind it to `user`. The `sayHi` is a "bound" function, that can be called alone or passed to `setTimeout` -- doesn't matter, the context will be right. +En la línea `(*)` tomamos el método `user.sayHi` y lo vinculamos a `user`. `sayHi` es una función "bound" (enlazada). Si se llama sola o se pasa en `setTimeout` no importa, el contexto será el correcto. -Here we can see that arguments are passed "as is", only `this` is fixed by `bind`: +Aquí podemos ver que los argumentos se pasan "tal cual", solo que `this` se fija mediante` bind`: ```js run let user = { @@ -187,12 +201,12 @@ let user = { let say = user.say.bind(user); -say("Hello"); // Hello, John ("Hello" argument is passed to say) +say("Hello"); // Hello, John ("Hello" se pasa a say) say("Bye"); // Bye, John ("Bye" is passed to say) ``` -````smart header="Convenience method: `bindAll`" -If an object has many methods and we plan to actively pass it around, then we could bind them all in a loop: +````smart header="Convenience method:bindAll" +Si un objeto tiene muchos métodos y planeamos pasarlo activamente, podríamos vincularlos a todos en un bucle: ```js for (let key in user) { @@ -202,24 +216,27 @@ for (let key in user) { } ``` -JavaScript libraries also provide functions for convenient mass binding , e.g. [_.bindAll(obj)](http://lodash.com/docs#bindAll) in lodash. +Las bibliotecas de JavaScript también proporcionan funciones para un enlace masivo, e.j. [_.bindAll(obj)](http://lodash.com/docs#bindAll) en lodash. ```` -## Partial functions +## Funciones parciales -Until now we have only been talking about binding `this`. Let's take it a step further. +Hasta ahora solo hemos estado hablando de vincular `this`. Vamos un paso más allá. -We can bind not only `this`, but also arguments. That's rarely done, but sometimes can be handy. +Podemos vincular no solo `this`, sino también argumentos. Es algo que no suele hacerse, pero a veces puede ser útil. + +Sintáxis completa de `bind`: -The full syntax of `bind`: ```js let bound = func.bind(context, [arg1], [arg2], ...); ``` -It allows to bind context as `this` and starting arguments of the function. -For instance, we have a multiplication function `mul(a, b)`: +Permite vincular el contexto como `this` y los argumentos iniciales de la función. + +Por ejemplo, tenemos una función de multiplicación `mul(a, b)`: + ```js function mul(a, b) { @@ -227,7 +244,9 @@ function mul(a, b) { } ``` -Let's use `bind` to create a function `double` on its base: + +Usemos `bind` para crear una función` double` en su base: + ```js run function mul(a, b) { @@ -243,13 +262,15 @@ alert( double(4) ); // = mul(2, 4) = 8 alert( double(5) ); // = mul(2, 5) = 10 ``` -The call to `mul.bind(null, 2)` creates a new function `double` that passes calls to `mul`, fixing `null` as the context and `2` as the first argument. Further arguments are passed "as is". -That's called [partial function application](https://en.wikipedia.org/wiki/Partial_application) -- we create a new function by fixing some parameters of the existing one. +La llamada a `mul.bind(null, 2)` crea una nueva función `double` que pasa las llamadas a `mul`, fijando `null` como contexto y `2` como primer argumento. Otros argumentos se pasan "tal cual". + +Eso se llama [aplicación parcial de una función](https://en.wikipedia.org/wiki/Partial_application) -- creamos una nueva función arreglando algunos parámetros de la existente. + +Tenga en cuenta que aquí en realidad no usamos `this`. Pero `bind` lo requiere, por lo que debemos poner algo como `null`. -Please note that here we actually don't use `this` here. But `bind` requires it, so we must put in something like `null`. +La función `triple` en el siguiente código triplica el valor: -The function `triple` in the code below triples the value: ```js run function mul(a, b) { @@ -265,23 +286,23 @@ alert( triple(4) ); // = mul(3, 4) = 12 alert( triple(5) ); // = mul(3, 5) = 15 ``` -Why do we usually make a partial function? +¿Por qué solemos hacer una función parcial? -The benefit is that we can create an independent function with a readable name (`double`, `triple`). We can use it and not provide the first argument every time as it's fixed with `bind`. +El beneficio es que podemos crear una función independiente con un nombre legible (`double`,`triple`). Podemos usarlo y no proporcionar el primer argumento cada vez, ya que se fija con `bind`. -In other cases, partial application is useful when we have a very generic function and want a less universal variant of it for convenience. +En otros casos, la aplicación parcial es útil cuando tenemos una función muy genérica y queremos una variante menos universal para mayor comodidad. -For instance, we have a function `send(from, to, text)`. Then, inside a `user` object we may want to use a partial variant of it: `sendTo(to, text)` that sends from the current user. +Por ejemplo, tenemos una función `send(from, to, text)`. Luego, dentro de un objeto `user` podemos querer usar una variante parcial del mismo: `sendTo(to, text)` que envía desde el usuario actual. -## Going partial without context +## Parcial sin contexto -What if we'd like to fix some arguments, but not the context `this`? For example, for an object method. +¿Qué pasa si nos gustaría fijar algunos argumentos, pero no el contexto `this`? Por ejemplo, para un método de objeto. -The native `bind` does not allow that. We can't just omit the context and jump to arguments. +El método `bind` nativo no permite eso. No podemos simplemente omitir el contexto y saltar a los argumentos. -Fortunately, a function `partial` for binding only arguments can be easily implemented. +Afortunadamente, se puede implementar fácilmente una función `parcial` para vincular solo argumentos. -Like this: +Como esto: ```js run *!* @@ -292,7 +313,9 @@ function partial(func, ...argsBound) { } */!* -// Usage: + +// Uso: + let user = { firstName: "John", say(time, phrase) { @@ -300,29 +323,33 @@ let user = { } }; -// add a partial method with fixed time + +// agregar un método parcial con tiempo fijo user.sayNow = partial(user.say, new Date().getHours() + ':' + new Date().getMinutes()); user.sayNow("Hello"); -// Something like: +// Algo como: // [10:00] John: Hello! ``` -The result of `partial(func[, arg1, arg2...])` call is a wrapper `(*)` that calls `func` with: -- Same `this` as it gets (for `user.sayNow` call it's `user`) -- Then gives it `...argsBound` -- arguments from the `partial` call (`"10:00"`) -- Then gives it `...args` -- arguments given to the wrapper (`"Hello"`) +El resultado de la llamada `parcial(func [, arg1, arg2 ...])` es un contenedor `(*)` que llama a `func` con: +- El mismo `this` (para la llamada a `user.sayNow` es `user`) +- Luego le da `...argsBound` -- argumentos desde la llamada a `partial` (`"10:00"`) +- Luego le da `...args` -- argumentos dados desde la envoltura (`"Hello"`) + +Muy fácil de hacer con la sintaxis de propagación, ¿verdad? + +También hay una implementación preparada [_.partial](https://lodash.com/docs#partial) desde la librería lodash. + +## Resumen -So easy to do it with the spread syntax, right? +El método `func.bind(context, ... args)` devuelve una "variante ligada" de la función `func` que fija el contexto `this` y los primeros argumentos si se dan. -Also there's a ready [_.partial](https://lodash.com/docs#partial) implementation from lodash library. +Por lo general, aplicamos `bind` para fijar `this` a un método de objeto, de modo que podamos pasarlo en otro lugar. Por ejemplo, en `setTimeout`. -## Summary -Method `func.bind(context, ...args)` returns a "bound variant" of function `func` that fixes the context `this` and first arguments if given. +Cuando fijamos algunos argumentos de una función existente, la función resultante (menos universal) se llama *aplicación parcial* o *parcial*. -Usually we apply `bind` to fix `this` for an object method, so that we can pass it somewhere. For example, to `setTimeout`. -When we fix some arguments of an existing function, the resulting (less universal) function is called *partially applied* or *partial*. +Los parciales son convenientes cuando no queremos repetir el mismo argumento una y otra vez. Al igual que si tenemos una función `send(from, to)`, y `from` siempre debe ser igual para nuestra tarea, entonces, podemos obtener un parcial y continuar la tarea con él. -Partials are convenient when we don't want to repeat the same argument over and over again. Like if we have a `send(from, to)` function, and `from` should always be the same for our task, we can get a partial and go on with it.