Skip to content

Reference Type #304

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Jul 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions 1-js/99-js-misc/04-reference-type/2-check-syntax/solution.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
**Error**!
¡**Error**!

Try it:
Inténtalo:

```js run
let user = {
name: "John",
go: function() { alert(this.name) }
}

(user.go)() // error!
(user.go)() // ¡Error!
```

The error message in most browsers does not give us much of a clue about what went wrong.
El mensaje de error en la mayoría de los navegadores no nos da una pista sobre lo que salió mal.

**The error appears because a semicolon is missing after `user = {...}`.**
**El error aparece porque falta un punto y coma después de `user = {...}`.**

JavaScript does not auto-insert a semicolon before a bracket `(user.go)()`, so it reads the code like:
JavaScript no inserta automáticamente un punto y coma antes de un paréntesis `(user.go)()`, por lo que lee el código así:

```js no-beautify
let user = { go:... }(user.go)()
```

Then we can also see that such a joint expression is syntactically a call of the object `{ go: ... }` as a function with the argument `(user.go)`. And that also happens on the same line with `let user`, so the `user` object has not yet even been defined, hence the error.
Entonces también podemos ver que tal expresión conjunta es sintácticamente una llamada del objeto `{ go: ... }` como una función con el argumento `(user.go)`. Y eso también ocurre en la misma línea con `let user`, por lo que el objeto `user` aún no se ha definido y de ahí el error.

If we insert the semicolon, all is fine:
Si insertamos el punto y coma todo está bien:

```js run
let user = {
Expand All @@ -34,4 +34,4 @@ let user = {
(user.go)() // John
```

Please note that parentheses around `(user.go)` do nothing here. Usually they setup the order of operations, but here the dot `.` works first anyway, so there's no effect. Only the semicolon thing matters.
Tenga en cuenta que los paréntesis alrededor de `(user.go)` no hacen nada aquí. Usualmente son configurados para ordenar las operaciones, pero aquí el punto `.` funciona primero de todas formas, por lo que no tienen ningún efecto en él. Solamente el punto y coma importa.
6 changes: 3 additions & 3 deletions 1-js/99-js-misc/04-reference-type/2-check-syntax/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ importance: 2

---

# Syntax check
# Verificación de sintaxis

What is the result of this code?
¿Cuál es el resultado de este código?


```js no-beautify
Expand All @@ -16,4 +16,4 @@ let user = {
(user.go)()
```

P.S. There's a pitfall :)
P.D. Hay una trampa :)
22 changes: 10 additions & 12 deletions 1-js/99-js-misc/04-reference-type/3-why-this/solution.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@

Here's the explanations.
Aquí está la explicación.

1. That's a regular object method call.
1. Esta es una llamada común al método del objeto
2. Lo mismo, aquí los paréntesis no cambian el orden de las operaciones, el punto es el primero de todos modos.

2. The same, parentheses do not change the order of operations here, the dot is first anyway.

3. Here we have a more complex call `(expression).method()`. The call works as if it were split into two lines:
3. Aquí tenemos una llamada más compleja `(expression).method()`. La llamada funciona como si se dividiera en dos líneas:

```js no-beautify
f = obj.go; // calculate the expression
f(); // call what we have
f = obj.go; // Calcula la expresión
f(); // Llama a lo que tenemos
```

Here `f()` is executed as a function, without `this`.

4. The similar thing as `(3)`, to the left of the dot `.` we have an expression.
Aquí `f()` se ejecuta como una función, sin `this`.

To explain the behavior of `(3)` and `(4)` we need to recall that property accessors (dot or square brackets) return a value of the Reference Type.
4. Lo mismo que `(3)`, a la izquierda del punto `.` tenemos una expresión.

Any operation on it except a method call (like assignment `=` or `||`) turns it into an ordinary value, which does not carry the information allowing to set `this`.
Para explicar el funcionamiento de `(3)` y `(4)` necesitamos recordar que los accesores de propiedad (punto o corchetes) devuelven un valor del Tipo de Referencia.

Cualquier operación en él excepto una llamada al método (como asignación `=` o `||`) lo convierte en un valor ordinario que no transporta la información que permite establecer `this`.
6 changes: 3 additions & 3 deletions 1-js/99-js-misc/04-reference-type/3-why-this/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ importance: 3

---

# Explain the value of "this"
# Explica el valor de "this"

In the code below we intend to call `obj.go()` method 4 times in a row.
En el código siguiente intentamos llamar al método `obj.go()` 4 veces seguidas.

But calls `(1)` and `(2)` works differently from `(3)` and `(4)`. Why?
Pero las llamadas `(1)` y `(2)` funcionan diferente a `(3)` y `(4)`. ¿Por qué?

```js run no-beautify
let obj, method;
Expand Down
88 changes: 44 additions & 44 deletions 1-js/99-js-misc/04-reference-type/article.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@

# Reference Type
# Tipo de Referencia

```warn header="In-depth language feature"
This article covers an advanced topic, to understand certain edge-cases better.
```warn header="Característica del lenguaje en profundidad"
Este artículo cubre un tema avanzado para comprender mejor ciertos casos límite.

It's not important. Many experienced developers live fine without knowing it. Read on if you're want to know how things work under the hood.
Esto no es importante. Muchos desarrolladores experimentados viven bien sin saberlo. Sigue leyendo si quieres saber cómo funcionan las cosas por debajo de la tapa.
```

A dynamically evaluated method call can lose `this`.
Una llamada al método evaluado dinámicamente puede perder `this`.

For instance:
Por ejemplo:

```js run
let user = {
Expand All @@ -18,42 +18,42 @@ let user = {
bye() { alert("Bye"); }
};

user.hi(); // works
user.hi(); // Funciona

// now let's call user.hi or user.bye depending on the name
// Ahora llamemos a user.hi o user.bye dependiendo del nombre ingresado
*!*
(user.name == "John" ? user.hi : user.bye)(); // Error!
(user.name == "John" ? user.hi : user.bye)(); // ¡Error!
*/!*
```

On the last line there is a conditional operator that chooses either `user.hi` or `user.bye`. In this case the result is `user.hi`.
En la última linea hay un operador condicional que elije entre `user.hi` o `user.bye`. En este caso el resultado es `user.hi`.

Then the method is immediately called with parentheses `()`. But it doesn't work correctly!
Entonces el método es llamado con paréntesis `()`. ¡Pero esto no funciona correctamente!

As you can see, the call results in an error, because the value of `"this"` inside the call becomes `undefined`.
Como puedes ver, la llamada resulta en un error porque el valor de `"this"` dentro de la llamada se convierte en `undefined`.

This works (object dot method):
Esto funciona (objeto, punto, método):
```js
user.hi();
```

This doesn't (evaluated method):
Esto no funciona (método evaluado):
```js
(user.name == "John" ? user.hi : user.bye)(); // Error!
(user.name == "John" ? user.hi : user.bye)(); // ¡Error!
```

Why? If we want to understand why it happens, let's get under the hood of how `obj.method()` call works.
¿Por qué? Si queremos entender por qué pasa esto vayamos bajo la tapa de cómo funciona la llamada `obj.method()`.

## Reference type explained
## Tipo de Referencia explicado

Looking closely, we may notice two operations in `obj.method()` statement:
Mirando de cerca podemos notar dos operaciones en la declaración `obj.method()`:

1. First, the dot `'.'` retrieves the property `obj.method`.
2. Then parentheses `()` execute it.
1. Primero, el punto '.'recupera la propiedad de `obj.method`.
2. Luego el paréntesis `()` lo ejecuta.

So, how does the information about `this` get passed from the first part to the second one?
Entonces ¿cómo es trasladada la información de `this` de la primera parte a la segunda?

If we put these operations on separate lines, then `this` will be lost for sure:
Si ponemos estas operaciones en líneas separadas, entonces `this` se perderá con seguridad:

```js run
let user = {
Expand All @@ -62,53 +62,53 @@ let user = {
}

*!*
// split getting and calling the method in two lines
// Se divide la obtención y se llama al método en dos lineas
let hi = user.hi;
hi(); // Error, because this is undefined
hi(); // Error porque this es indefinido
*/!*
```

Here `hi = user.hi` puts the function into the variable, and then on the last line it is completely standalone, and so there's no `this`.
Aquí `hi = user.hi` coloca la función dentro de una variable y luego la última linea es completamente independiente, por lo tanto no hay `this`.

**To make `user.hi()` calls work, JavaScript uses a trick -- the dot `'.'` returns not a function, but a value of the special [Reference Type](https://tc39.github.io/ecma262/#sec-reference-specification-type).**
**Para hacer que la llamada `user.hi()` funcione, JavaScript usa un truco: el punto `'.'` no devuelve una función, sino un valor especial del [Tipo de referencia](https://tc39.github.io/ecma262/#sec-reference-specification-type).**

The Reference Type is a "specification type". We can't explicitly use it, but it is used internally by the language.
El Tipo de Referencia es un "tipo de especificación". No podemos usarla explícitamente pero es usada internamente por el lenguaje.

The value of Reference Type is a three-value combination `(base, name, strict)`, where:
El valor del Tipo de Referencia es una combinación de triple valor `(base, name, strict)`, donde:

- `base` is the object.
- `name` is the property name.
- `strict` is true if `use strict` is in effect.
- `base` es el objeto.
- `name` es el nombre de la propiedad.
- `strict` es verdadero si `use strict` está en efecto.

The result of a property access `user.hi` is not a function, but a value of Reference Type. For `user.hi` in strict mode it is:
El resultado de un acceso a la propiedad `user.hi` no es una función, sino un valor de Tipo de Referencia. Para `user.hi` en modo estricto esto es:

```js
// Reference Type value
// Valor de Tipo de Referencia
(user, "hi", true)
```

When parentheses `()` are called on the Reference Type, they receive the full information about the object and its method, and can set the right `this` (`=user` in this case).
Cuando son llamados los paréntesis `()` en el tipo de referencia, reciben la información completa sobre el objeto y su método y pueden establecer el `this` correcto (`=user` en este caso).

Reference type is a special "intermediary" internal type, with the purpose to pass information from dot `.` to calling parentheses `()`.
Tipo de Referencia es un tipo interno de "intermediario", con el propósito de pasar información desde el punto `.` hacia los paréntesis de la llamada `()`.

Any other operation like assignment `hi = user.hi` discards the reference type as a whole, takes the value of `user.hi` (a function) and passes it on. So any further operation "loses" `this`.
Cualquier otra operación como la asignación `hi = user.hi` descarta el tipo de referencia como un todo, toma el valor de `user.hi` (una función) y lo pasa. Entonces cualquier operación "pierde" `this`.

So, as the result, the value of `this` is only passed the right way if the function is called directly using a dot `obj.method()` or square brackets `obj['method']()` syntax (they do the same here). Later in this tutorial, we will learn various ways to solve this problem such as [func.bind()](/bind#solution-2-bind).
Entonces, como resultado, el valor de `this` solo se pasa de la manera correcta si la función se llama directamente usando una sintaxis de punto `obj.method()` o corchetes `obj['method']()` (aquí hacen lo mismo). Más adelante en este tutorial, aprenderemos varias formas de resolver este problema así como [func.bind()](/bind#solution-2-bind).

## Summary
## Resumen

Reference Type is an internal type of the language.
El Tipo de Referencia es un tipo interno del lenguaje.

Reading a property, such as with dot `.` in `obj.method()` returns not exactly the property value, but a special "reference type" value that stores both the property value and the object it was taken from.
Leer una propiedad como las que tienen un punto `.` en `obj.method()` no devuelve exactamente el valor de la propiedad, sino un valor especial de "tipo de referencia" que almacena tanto el valor de la propiedad como el objeto del que se tomó.

That's for the subsequent method call `()` to get the object and set `this` to it.
Eso se hace para la llamada `()` al siguiente método para obtener el objeto y establecer `this` en él.

For all other operations, the reference type automatically becomes the property value (a function in our case).
Para todas las demás operaciones, el tipo de referencia se convierte automáticamente en el valor de la propiedad (una función en nuestro caso).

The whole mechanics is hidden from our eyes. It only matters in subtle cases, such as when a method is obtained dynamically from the object, using an expression.
Toda la mecánica está oculta a nuestros ojos. Solo importa en casos sutiles, como cuando un método se obtiene dinámicamente del objeto, usando una expresión.





result of dot `.` isn't actually a method, but a value of `` needs a way to pass the information about `obj`
El resultado del punto `.` no es en realidad un método, pero un valor de `` necesita una manera de pasar la información sobre `obj`.
2 changes: 1 addition & 1 deletion 1-js/99-js-misc/index.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@

# Temas diversos