You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 1-js/09-classes/02-class-inheritance/article.md
+31-31Lines changed: 31 additions & 31 deletions
Original file line number
Diff line number
Diff line change
@@ -1,9 +1,9 @@
1
1
2
2
# Herencia de clase
3
3
4
-
La herencia de clase es un método para que una clase extienda a otra.
4
+
La herencia de clase es el modo para que una clase extienda a otra.
5
5
6
-
Entonces podemos crear una nueva funcionalidad además de la existente.
6
+
De esta manera podemos añadir nueva funcionalidad a la ya existente.
7
7
8
8
## La palabra clave "extends"
9
9
@@ -34,9 +34,9 @@ Así es como podemos representar gráficamente el objeto `animal` y la clase `An
34
34
35
35
...Y nos gustaría crear otra clase `Rabbit`.
36
36
37
-
Como los conejos son animales, la clase 'Rabbit' debe basarse en 'Animal', tener acceso a métodos animales, para que los conejos puedan hacer lo que los animales "genéricos" pueden hacer.
37
+
Como los conejos son animales, la clase 'Rabbit' debería basarse en 'Animal' y así tener acceso a métodos animales, para que los conejos puedan hacer lo que los animales "genéricos" pueden hacer.
38
38
39
-
La sintaxis para extender otra clase es: `class Child extends Parent`.
39
+
La sintaxis para extender otra clase es: `class Hijo extends Padre`.
40
40
41
41
Construyamos la clase `Rabbit` que herede de `Animal`:
42
42
@@ -61,12 +61,12 @@ Internamente, la palabra clave `extends` funciona con la buena mecánica de prot
61
61
62
62

63
63
64
-
Por ejemplo, para encontrar el método `rabbit.run`, el motor verifica (en la imagen, de abajo hacia arriba):
65
-
1. El objeto `rabbit` (no tiene el método `run`).
66
-
2. Su prototipo, que es `Rabbit.prototype` (tiene el método `hide`, pero no el método `run`).
67
-
3. Su prototipo, que es `Animal.prototype` (debido a `extends`). Este finalmente tiene el método `run`.
64
+
Por ejemplo, para encontrar el método `rabbit.run`, el motor revisa (en la imagen, de abajo hacia arriba):
65
+
1. El objeto `rabbit`: no tiene el método `run`.
66
+
2. Su prototipo, que es `Rabbit.prototype`: tiene el método `hide`, pero no el método `run`.
67
+
3. Su prototipo, que es `Animal.prototype` (debido a `extends`): Este finalmente tiene el método `run`.
68
68
69
-
Como podemos recordar del capítulo <info:native-prototypes>, JavaScript usa la misma herencia prototípica para los objetos incorporados. Por ejemplo `Date.prototype.[[Prototype]]` es `Object.prototype`, por lo que "Date" tiene acceso a métodos de objeto genéricos.
69
+
Como podemos recordar del capítulo <info:native-prototypes>, JavaScript usa la misma herencia prototípica para los objetos incorporados. Por ejemplo,`Date.prototype.[[Prototype]]` es `Object.prototype`. Es por esto que "Date" tiene acceso a métodos de objeto genéricos.
70
70
71
71
````smart header="Cualquier expresión está permitida después de `extends`"
72
72
La sintaxis de clase permite especificar no solo una clase, sino cualquier expresión después de `extends`.
@@ -86,7 +86,7 @@ class User extends f("Hola") {}
86
86
87
87
newUser().sayHi(); // Hola
88
88
```
89
-
Observa:`class User` hereda del resultado de `f("Hola")`.
89
+
Observa que`class User` hereda del resultado de `f("Hola")`.
90
90
91
91
Eso puede ser útil para patrones de programación avanzados cuando usamos funciones para generar clases dependiendo de muchas condiciones y podamos heredar de ellas.
92
92
````
@@ -95,7 +95,7 @@ Eso puede ser útil para patrones de programación avanzados cuando usamos funci
95
95
96
96
Ahora avancemos y sobrescribamos un método. Por defecto, todos los métodos que no están especificados en la clase `Rabbit` se toman directamente "tal cual" de la clase `Animal`.
97
97
98
-
Pero Si especificamos nuestro propio método `stop()` en `Rabbit`, este se utilizará en su lugar:
98
+
Pero Si especificamos nuestro propio método `stop()` en `Rabbit`, es el que se utilizará en su lugar:
99
99
100
100
```js
101
101
class Rabbit extends Animal {
@@ -106,11 +106,11 @@ class Rabbit extends Animal {
106
106
}
107
107
```
108
108
109
-
Usualmente no queremos reemplazar totalmente un método padre, sino más bien construir sobre él, modificar o ampliar su funcionalidad. Hacemos algo en nuestro método, pero llamamos al método padre antes, después o durante el proceso.
109
+
Usualmente, no queremos reemplazar totalmente un método padre, sino más bien construir sobre él, modificarlo o ampliar su funcionalidad. Hacemos algo con nuestro método, pero queremos llamar al método padre antes, después o durante el proceso.
110
110
111
111
Las clases proporcionan la palabra clave `"super"` para eso.
112
112
113
-
- `super.method(...)` llama un método padre.
113
+
- `super.metodo(...)` llama un método padre.
114
114
- `super(...)` llama un constructor padre (solo dentro de nuestro constructor).
115
115
116
116
Por ejemplo, hagamos que nuestro conejo se oculte automáticamente cuando se detenga:
@@ -159,7 +159,7 @@ Ahora `Rabbit` tiene el método `stop` que llama al padre `super.stop()` en el p
159
159
````smart header="Las funciones de flecha no tienen `super`"
160
160
Como se mencionó en el capítulo <info:arrow-functions>, las funciones de flecha no tienen `super`.
161
161
162
-
Si se accede, se toma de la función externa. Por ejemplo:
162
+
Si se lo accede, lo toma de la función externa. Por ejemplo:
163
163
```js
164
164
class Rabbit extends Animal {
165
165
stop() {
@@ -168,7 +168,7 @@ class Rabbit extends Animal {
168
168
}
169
169
```
170
170
171
-
El método `super` en la función de flecha es el mismo que en `stop()`, y funciona según lo previsto. Si aquí especificamos una función "regular", habría un error:
171
+
El método `super` en la función de flecha es el mismo que en `stop()`, y funciona según lo previsto. Si aquí especificáramos una función "regular", habría un error:
172
172
173
173
```js
174
174
// super inesperado
@@ -187,7 +187,7 @@ De acuerdo con la [especificación](https://tc39.github.io/ecma262/#sec-runtime-
187
187
188
188
```js
189
189
classRabbitextendsAnimal {
190
-
// generado para extender clases sin constructores propios
190
+
//es generado por extender la clase sin constructor propio
191
191
*!*
192
192
constructor(...args) {
193
193
super(...args);
@@ -196,7 +196,7 @@ class Rabbit extends Animal {
196
196
}
197
197
```
198
198
199
-
Como podemos ver, básicamente llama al padre `constructor` pasándole todos los argumentos. Eso sucede si no escribimos un constructor propio.
199
+
Como podemos ver, básicamente llama al `constructor`padre pasándole todos los argumentos. Esto sucede si no escribimos un constructor propio.
200
200
201
201
Ahora agreguemos un constructor personalizado a `Rabbit`. Especificará `earLength` además de `name`:
202
202
@@ -273,7 +273,7 @@ class Rabbit extends Animal {
273
273
}
274
274
275
275
*!*
276
-
//now fine
276
+
//todo bien ahora
277
277
let rabbit =newRabbit("Conejo Blanco", 10);
278
278
alert(rabbit.name); // Conejo Blanco
279
279
alert(rabbit.earLength); // 10
@@ -323,11 +323,11 @@ Aquí, la clase `Rabbit` extiende `Animal` y sobrescribe el campo `name` con un
323
323
324
324
Lo interesante es que en ambos casos: `new Animal()` y `new Rabbit()`, el `alert` en la línea `(*)` muestra `animal`.
325
325
326
-
**En otras palabras, el constructor padre siempre usa el valor de su propios campo de clase, no el sobrescrito.**
326
+
**En otras palabras, el constructor padre siempre usa el valor de su propio campo de clase, no el sobrescrito.**
327
327
328
328
¿Qué es lo extraño de esto?
329
329
330
-
Si esto aún no está claro, compara con métodos.
330
+
Si esto aún no está claro, compara lo que ocurre con los métodos.
331
331
332
332
Aquí está el mismo código, pero en lugar del campo `this.name` llamamos el método `this.showName()`:
333
333
@@ -368,11 +368,11 @@ Bien, la razón está en el orden de inicialización, El campo de clase es inici
368
368
369
369
En nuestro caso, `Rabbit` es la clase derivada. No hay `constructor()` en ella. Como establecimos previamente, es lo mismo que si hubiera un constructor vacío con solamente `super(...args)`.
370
370
371
-
Entonces, `new Rabbit()` llama a `super()` y se ejecuta el constructor padre, y (por la regla de la clase derivada) solamente después de que sus campos de clase sean inicializados. En el momento de la ejecución del constructor padre, todavía no existen los campos de clase de `Rabbit`, por ello los campos de `Animal` son los usado.
371
+
Entonces, `new Rabbit()` llama a `super()` y se ejecuta el constructor padre, y (por la regla de la clase derivada) solamente después de que sus campos de clase sean inicializados. En el momento de la ejecución del constructor padre, todavía no existen los campos de clase de `Rabbit`, por ello los campos de `Animal` son los usados.
372
372
373
373
Esta sutil diferencia entre campos y métodos es particular de JavaScript
374
374
375
-
Afortunadamente este comportamiento solo se revela si los campos sobrescritos son usados en el constructor padre. Entonces puede ser difícil entender qué es lo que está pasando, por ello lo explicamos aquí.
375
+
Afortunadamente este comportamiento solo se revela si los campos sobrescritos son usados en el constructor padre. En tal caso puede ser difícil entender qué es lo que está pasando, por ello lo explicamos aquí.
376
376
377
377
Si esto e vuelve un problema, uno puede corregirlo usando métodos o getters/setters en lugar de campos.
378
378
@@ -389,9 +389,9 @@ Vamos a profundizar un poco más el tema de `super`. Veremos algunas cosas inter
389
389
390
390
En primer lugar, de todo lo que hemos aprendido hasta ahora, ¡es imposible que `super` funcione en absoluto!
391
391
392
-
Sí, de hecho, preguntémonos, ¿cómo debería funcionar técnicamente? Cuando se ejecuta un método de objeto, obtiene el objeto actual como `this`. Si llamamos a `super.method()` entonces, el motor necesita obtener el `method` del prototipo del objeto actual. ¿Pero cómo?
392
+
Entonces, preguntémonos: ¿cómo debería funcionar técnicamente? Cuando se ejecuta un método de objeto, obtiene el objeto actual como `this`. Si llamamos a `super.method()` entonces, el motor necesita obtener el `method` del prototipo del objeto actual. ¿Pero cómo?
393
393
394
-
La tarea puede parecer simple, pero no lo es. El motor conoce el objeto actual `this`, por lo que podría obtener el `method`padre como `this.__proto __.method`. Desafortunadamente, una solución tan "ingenua" no funcionará.
394
+
La tarea puede parecer simple, pero no lo es. El motor conoce el objeto actual `this`, por lo que podría obtener el `method` padre como `this.__proto __.method`. Desafortunadamente, una solución tan "ingenua" no funcionará.
395
395
396
396
Demostremos el problema. Sin clases, usando objetos puros por simplicidad.
397
397
@@ -475,7 +475,7 @@ Aquí está la imagen de lo que sucede:
475
475
// es decir
476
476
rabbit.eat.call(this);
477
477
```
478
-
2. Luego, en la línea `(*)` de `rabbit.eat`, nos gustaría pasar la llamada aún más arriba en la cadena, evitando `this=longEar`, entonces `this.__ proto__.eat` es nuevamente `rabbit.eat`!
478
+
2. Luego, en la línea `(*)` de `rabbit.eat`, queremos pasar la llamada aún más arriba en la cadena; pero como `this=longEar`, entonces `this.__ proto__.eat`¡es nuevamente `rabbit.eat`!
479
479
480
480
```js
481
481
// dentro de rabbit.eat () también tenemos this = longEar
@@ -488,7 +488,7 @@ Aquí está la imagen de lo que sucede:
488
488
489
489
3....Entonces `rabbit.eat` se llama a sí mismo en el bucle sin fin, porque no puede ascender más.
490
490
491
-
El problema no se puede resolver usando solo`this`.
491
+
El problema no se puede resolver usando solamente`this`.
492
492
493
493
### `[[HomeObject]]`
494
494
@@ -534,7 +534,7 @@ Funciona según lo previsto, debido a la mecánica de `[[HomeObject]]`. Un méto
534
534
535
535
### Los métodos no son "libres"
536
536
537
-
Como hemos sabido antes, generalmente las funciones son "libres", es decir no están vinculadas a objetos en JavaScript. Para que puedan copiarse entre objetos y llamarse con otro 'this`.
537
+
Como aprendimos antes, generalmente las funciones son "libres", es decir que no están vinculadas a objetos en JavaScript. Esto es para que puedan copiarse entre objetos y llamarse con otro 'this`.
538
538
539
539
La existencia misma de `[[HomeObject]]` viola ese principio, porque los métodos recuerdan sus objetos. `[[HomeObject]]` no se puede cambiar, por lo que este vínculo es para siempre.
540
540
@@ -616,12 +616,12 @@ rabbit.eat(); // Error al llamar a super (porque no hay [[HomeObject]])
616
616
617
617
## Resumen
618
618
619
-
1. Para extender una clase: `class Child extends Parent`:
620
-
- Eso significa que `Child.prototype.__proto__` será `Parent.prototype`, por lo que los métodos se heredan.
619
+
1. Para extender una clase: `class Hijo extends Padre`:
620
+
- Eso significa que `Hijo.prototype.__proto__` será `Padre.prototype`, por lo que los métodos se heredan.
621
621
2. Al sobrescribir un constructor:
622
-
- Debemos llamar al constructor padre como `super()` en el constructor `Child` antes de usar `this`.
622
+
- Debemos llamar al constructor del padre `super()` en el constructor de `Hijo` antes de usar `this`.
623
623
3. Al sobrescribir otro método:
624
-
- Podemos usar `super.method()` en un método `Child` para llamar al método `Parent`.
624
+
- Podemos usar `super.method()` en un método `Hijo` para llamar al método `Padre`.
625
625
4. Características internas:
626
626
- Los métodos recuerdan su clase/objeto en la propiedad interna `[[HomeObject]]`. Así es como `super` resuelve los métodos padres.
627
627
- Por lo tanto, no es seguro copiar un método con `super` de un objeto a otro.
0 commit comments