diff --git a/1-js/09-classes/02-class-inheritance/1-class-constructor-error/solution.md b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/solution.md index 4711e4827..16a66ec95 100644 --- a/1-js/09-classes/02-class-inheritance/1-class-constructor-error/solution.md +++ b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/solution.md @@ -1,6 +1,6 @@ -That's because the child constructor must call `super()`. +Eso es porque el constructor hijo debe llamar a `super()`. -Here's the corrected code: +Aqui está el código corregido: ```js run class Animal { @@ -21,7 +21,7 @@ class Rabbit extends Animal { } *!* -let rabbit = new Rabbit("White Rabbit"); // ok now +let rabbit = new Rabbit("Conejo Blanco"); // bueno ahora */!* -alert(rabbit.name); // White Rabbit +alert(rabbit.name); // Conejo Blanco ``` diff --git a/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md index 380a4720b..cb582ac20 100644 --- a/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md +++ b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md @@ -2,11 +2,11 @@ importance: 5 --- -# Error creating an instance +# Error al crear una instancia -Here's the code with `Rabbit` extending `Animal`. +Aquí está el código de la clase `Rabbit` que extiende a`Animal`. -Unfortunately, `Rabbit` objects can't be created. What's wrong? Fix it. +Desafortunadamente, los objetos `Rabbit` no se pueden crear. ¿Que pasa? Arréglalo. ```js run class Animal { @@ -24,7 +24,7 @@ class Rabbit extends Animal { } *!* -let rabbit = new Rabbit("White Rabbit"); // Error: this is not defined +let rabbit = new Rabbit("Conejo Blanco"); // Error: esto no está definido */!* alert(rabbit.name); ``` diff --git a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/extended-clock.js b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/extended-clock.js index ca613ca5e..be2053cfc 100644 --- a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/extended-clock.js +++ b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/extended-clock.js @@ -1,7 +1,7 @@ class ExtendedClock extends Clock { constructor(options) { super(options); - let { precision=1000 } = options; + let { precision = 1000 } = options; this.precision = precision; } diff --git a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/index.html b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/index.html index c0609858b..31c0df90f 100644 --- a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/index.html +++ b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/index.html @@ -7,7 +7,7 @@ clock.start(); - /* Your class should work like this: */ + /* Tu clase debería funcionar así: */ /* diff --git a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/task.md b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/task.md index bbc2c6a43..2a49a45df 100644 --- a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/task.md +++ b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/task.md @@ -2,14 +2,14 @@ importance: 5 --- -# Extended clock +# Reloj extendido -We've got a `Clock` class. As of now, it prints the time every second. +Tenemos una clase de 'Clock'. A partir de ahora, imprime la hora cada segundo. [js src="source.view/clock.js"] -Create a new class `ExtendedClock` that inherits from `Clock` and adds the parameter `precision` -- the number of `ms` between "ticks". Should be `1000` (1 second) by default. +Crea una nueva clase `ExtendedClock` que herede de `Clock` y agrega el parámetro `precision`: este es el número de `milisegundos` entre "tics". Debe ser `1000` (1 segundo) por defecto. -- Your code should be in the file `extended-clock.js` -- Don't modify the original `clock.js`. Extend it. +- Tu código debe estar en el archivo `extended-clock.js` +- No modifiques el `clock.js` original. Extiéndelo. diff --git a/1-js/09-classes/02-class-inheritance/3-class-extend-object/rabbit-extends-object.svg b/1-js/09-classes/02-class-inheritance/3-class-extend-object/rabbit-extends-object.svg index 8ab568291..34d783b4d 100644 --- a/1-js/09-classes/02-class-inheritance/3-class-extend-object/rabbit-extends-object.svg +++ b/1-js/09-classes/02-class-inheritance/3-class-extend-object/rabbit-extends-object.svg @@ -1,67 +1 @@ - - - - rabbit-extends-object.svg - Created with sketchtool. - - - - - call: function - bind: function - ... - - - - Function.prototype - - - - constructor - - - Object - - - Rabbit - - - - [[Prototype]] - - - - [[Prototype]] - - - constructor - - - - call: function - bind: function - ... - - - - Function.prototype - - - Rabbit - - - - [[Prototype]] - - - constructor - - - class Rabbit - - - class Rabbit extends Object - - - - \ No newline at end of file +call: function bind: function ...Function.prototypeconstructorObjectRabbit[[Prototype]][[Prototype]]constructorcall: function bind: function ...Function.prototypeRabbit[[Prototype]]constructorclass Rabbitclass Rabbit extends Object \ No newline at end of file diff --git a/1-js/09-classes/02-class-inheritance/3-class-extend-object/solution.md b/1-js/09-classes/02-class-inheritance/3-class-extend-object/solution.md index fa26ec834..0f70aebc4 100644 --- a/1-js/09-classes/02-class-inheritance/3-class-extend-object/solution.md +++ b/1-js/09-classes/02-class-inheritance/3-class-extend-object/solution.md @@ -1,14 +1,14 @@ -First, let's see why the latter code doesn't work. +Primero, veamos por qué el último código no funciona. -The reason becomes obvious if we try to run it. An inheriting class constructor must call `super()`. Otherwise `"this"` won't be "defined". +La razón se vuelve obvia si tratamos de ejecutarlo. Un constructor de clase heredado debe llamar a `super()`. De lo contrario, `"this"` no se "definirá". -So here's the fix: +Así que aquí está la solución: ```js run class Rabbit extends Object { constructor(name) { *!* - super(); // need to call the parent constructor when inheriting + super(); // necesita llamar al constructor padre al heredar */!* this.name = name; } @@ -16,66 +16,66 @@ class Rabbit extends Object { let rabbit = new Rabbit("Rab"); -alert( rabbit.hasOwnProperty('name') ); // true +alert( rabbit.hasOwnProperty('name') ); // verdadero ``` -But that's not all yet. +Pero eso no es todo aún. -Even after the fix, there's still important difference in `"class Rabbit extends Object"` versus `class Rabbit`. +Incluso después de la solución, todavía hay una diferencia importante en `"class Rabbit extends Objetc"` versus `class Rabbit`. -As we know, the "extends" syntax sets up two prototypes: +Como sabemos, la sintaxis "extends" configura dos prototipos: -1. Between `"prototype"` of the constructor functions (for methods). -2. Between the constructor functions itself (for static methods). +1. Entre el `"prototype"` de las funcionalidades del constructor (para métodos). +2. Entre las funcionalidades propias del constructor (para métodos estáticos). -In our case, for `class Rabbit extends Object` it means: +En nuestro caso, para `class Rabbit extends Object` significa:: ```js run class Rabbit extends Object {} -alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true -alert( Rabbit.__proto__ === Object ); // (2) true +alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) verdadero +alert( Rabbit.__proto__ === Object ); // (2) verdadero ``` -So `Rabbit` now provides access to static methods of `Object` via `Rabbit`, like this: +Entonces `Rabbit` ahora proporciona acceso a métodos estáticos de `Object` a través de `Rabbit`, como esto: ```js run class Rabbit extends Object {} *!* -// normally we call Object.getOwnPropertyNames +// normalmente llamamos Object.getOwnPropertyNames alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // a,b */!* ``` -But if we don't have `extends Object`, then `Rabbit.__proto__` is not set to `Object`. +Pero si no tenemos `extend Object', entonces `Rabbit.__ proto__` no está configurado como `Object`. -Here's the demo: +Aqui la demostración: ```js run class Rabbit {} -alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true -alert( Rabbit.__proto__ === Object ); // (2) false (!) -alert( Rabbit.__proto__ === Function.prototype ); // as any function by default +alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) verdadero +alert( Rabbit.__proto__ === Object ); // (2) falso (!) +alert( Rabbit.__proto__ === Function.prototype ); // como cualquier función por defecto *!* -// error, no such function in Rabbit +// error, no hay tal función en Rabbit alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // Error */!* ``` -So `Rabbit` doesn't provide access to static methods of `Object` in that case. +Entonces `Rabbit` no proporciona acceso a métodos estáticos de 'Objeto' en ese caso. -By the way, `Function.prototype` has "generic" function methods, like `call`, `bind` etc. They are ultimately available in both cases, because for the built-in `Object` constructor, `Object.__proto__ === Function.prototype`. +Por cierto, `Function.prototype` tiene métodos de función "genéricos", como `call`, `bind` etc. En última instancia, están disponibles en ambos casos, porque para el constructor incorporado `Object`, `Object.__ proto__ === Function.prototype`. -Here's the picture: +Aqui está el gráfico: ![](rabbit-extends-object.svg) -So, to put it short, there are two differences: +Entonces, para resumir, hay dos diferencias: | class Rabbit | class Rabbit extends Object | |--------------|------------------------------| -| -- | needs to call `super()` in constructor | +| -- | necesita llamar a `super()` en el constructor | | `Rabbit.__proto__ === Function.prototype` | `Rabbit.__proto__ === Object` | diff --git a/1-js/09-classes/02-class-inheritance/3-class-extend-object/task.md b/1-js/09-classes/02-class-inheritance/3-class-extend-object/task.md index ca6628edf..764aa9a84 100644 --- a/1-js/09-classes/02-class-inheritance/3-class-extend-object/task.md +++ b/1-js/09-classes/02-class-inheritance/3-class-extend-object/task.md @@ -1,12 +1,12 @@ -importance: 5 +importance: 3 --- -# Class extends Object? +# Clase extiende objeto? -As we know, all objects normally inherit from `Object.prototype` and get access to "generic" object methods like `hasOwnProperty` etc. +Como sabemos, todos los objetos normalmente heredan de `Object.prototype` y obtienen acceso a métodos de objetos "genéricos" como `hasOwnProperty`, etc.. -For instance: +Por ejemplo: ```js run class Rabbit { @@ -18,17 +18,16 @@ class Rabbit { let rabbit = new Rabbit("Rab"); *!* -// hasOwnProperty method is from Object.prototype -// rabbit.__proto__ === Object.prototype -alert( rabbit.hasOwnProperty('name') ); // true +// el método hasOwnProperty es de Object.prototype +alert( rabbit.hasOwnProperty('name') ); // verdadero */!* ``` -But if we spell it out explicitly like `"class Rabbit extends Object"`, then the result would be different from a simple `"class Rabbit"`? +Pero si lo deletreamos explícitamente como `"clase Rabbit extends Objetc"`, entonces ¿el resultado sería diferente de un simple `"class Rabbit"`? -What's the difference? +¿Cual es la diferencia? -Here's an example of such code (it doesn't work -- why? fix it?): +Aquí hay un ejemplo de dicho código (no funciona, ¿por qué? ¿Solucionarlo?): ```js class Rabbit extends Object { @@ -39,5 +38,5 @@ class Rabbit extends Object { let rabbit = new Rabbit("Rab"); -alert( rabbit.hasOwnProperty('name') ); // true +alert( rabbit.hasOwnProperty('name') ); // Error ``` diff --git a/1-js/09-classes/02-class-inheritance/animal-rabbit-extends.svg b/1-js/09-classes/02-class-inheritance/animal-rabbit-extends.svg index 7a55a5043..3471904ab 100644 --- a/1-js/09-classes/02-class-inheritance/animal-rabbit-extends.svg +++ b/1-js/09-classes/02-class-inheritance/animal-rabbit-extends.svg @@ -1,64 +1 @@ - - - - animal-rabbit-extends.svg - Created with sketchtool. - - - - - constructor: Animal - run: function - stop: function - - - - Animal.prototype - - - - constructor: Rabbit - hide: function - - - Rabbit.prototype - - - - Animal - - - - Rabbit - - - new Rabbit - - - - - [[Prototype]] - - - - [[Prototype]] - - - prototype - - - - prototype - - - name: "White Rabbit" - - - constructor - - - constructor - - - - \ No newline at end of file +constructor: Animal run: function stop: functionAnimal.prototypeconstructor: Rabbit hide: functionRabbit.prototypeAnimalRabbitnew Rabbit[[Prototype]][[Prototype]]prototypeprototypename: "White Rabbit"constructorconstructorextends \ No newline at end of file diff --git a/1-js/09-classes/02-class-inheritance/article.md b/1-js/09-classes/02-class-inheritance/article.md index d6174b195..497a57e47 100644 --- a/1-js/09-classes/02-class-inheritance/article.md +++ b/1-js/09-classes/02-class-inheritance/article.md @@ -1,9 +1,13 @@ -# Class inheritance +# Herencia de clase -Let's say we have two classes. +La herencia de clase es un método para que una clase extienda a otra clase. -`Animal`: +Entonces podemos crear una nueva funcionalidad además de la existente. + +## La palabra clave "extends" + +Digamos que tenemos la clase `Animal`: ```js class Animal { @@ -12,92 +16,62 @@ class Animal { this.name = name; } run(speed) { - this.speed += speed; - alert(`${this.name} runs with speed ${this.speed}.`); + this.speed = speed; + alert(`${this.name} corre a una velocidad de ${this.speed}.`); } stop() { this.speed = 0; - alert(`${this.name} stopped.`); + alert(`${this.name} se queda quieto.`); } } -let animal = new Animal("My animal"); +let animal = new Animal("Mi animal"); ``` -![](rabbit-animal-independent-animal.svg) - - -...And `Rabbit`: +Así es como podemos representar gráficamente el objeto `animal` y la clase `Animal`: -```js -class Rabbit extends Animal { - constructor(name) { - this.name = name; - } - hide() { - alert(`${this.name} hides!`); - } -} - -let rabbit = new Rabbit("My rabbit"); -``` - -![](rabbit-animal-independent-rabbit.svg) - - -Right now they are fully independent. +![](rabbit-animal-independent-animal.svg) -But we'd want `Rabbit` to extend `Animal`. In other words, rabbits should be based on animals, have access to methods of `Animal` and extend them with its own methods. +...Y nos gustaría crear otra clase `Rabbit`. -To inherit from another class, we should specify `"extends"` and the parent class before the brackets `{..}`. +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. -Here `Rabbit` inherits from `Animal`: +La sintaxis para extender otra clase es: `class Child extends Parent`. -```js run -class Animal { - constructor(name) { - this.speed = 0; - this.name = name; - } - run(speed) { - this.speed += speed; - alert(`${this.name} runs with speed ${this.speed}.`); - } - stop() { - this.speed = 0; - alert(`${this.name} stopped.`); - } -} +Construyamos la clase `Rabbit` que herede de `Animal`: +```js *!* -// Inherit from Animal class Rabbit extends Animal { +*/!* hide() { - alert(`${this.name} hides!`); + alert(`${this.name} se esconde!`); } } -*/!* -let rabbit = new Rabbit("White Rabbit"); +let rabbit = new Rabbit("Conejo Blanco"); -rabbit.run(5); // White Rabbit runs with speed 5. -rabbit.hide(); // White Rabbit hides! +rabbit.run(5); // Conejo Blanco corre a una velocidad de 5. +rabbit.hide(); // Conejo Blanco se esconde! ``` -Now the `Rabbit` code became a bit shorter, as it uses `Animal` constructor by default, and it also can `run`, as animals do. +Los objetos de la clase `Rabbit` tienen acceso a los métodos de `Rabbit`, como `rabbit.hide()`, y también a los métodos `Animal`, como `rabbit.run()`. -Internally, `extends` keyword adds `[[Prototype]]` reference from `Rabbit.prototype` to `Animal.prototype`: +Internamente, la palabra clave `extends` funciona con la buena mecánica de prototipo. Establece `Rabbit.prototype. [[Prototype]]` a `Animal.prototype`. Entonces, si no se encuentra un método en `Rabbit.prototype`, JavaScript lo toma de` Animal.prototype`. ![](animal-rabbit-extends.svg) -So, if a method is not found in `Rabbit.prototype`, JavaScript takes it from `Animal.prototype`. +Por ejemplo, para encontrar el método `rabbit.run`, el motor verifica (de abajo hacia arriba en la imagen) que: +1. El objeto `rabbit` (no tiene el método `run`). +2. Su prototipo, que es `Rabbit.prototype` (tiene el método `hide`, pero no el método `run`). +3. Su prototipo, es decir (debido a `extends`) `Animal.prototype`, este finalmente tiene el método `run`. -As we can recall from the chapter , JavaScript uses the same prototypal inheritance for build-in objects. E.g. `Date.prototype.[[Prototype]]` is `Object.prototype`, so dates have generic object methods. +Como podemos recordar del capítulo , JavaScript usa la misma herencia prototípica para los objetos incorporados. P.ej. `Date.prototype.[[Prototype]]` es `Object.prototype`, por lo que "Date" tiene métodos de objeto genéricos. -````smart header="Any expression is allowed after `extends`" -Class syntax allows to specify not just a class, but any expression after `extends`. +````smart header="Cualquier expresión está permitida después de `extends`" +La sintaxis de clase permite especificar no solo una clase, sino cualquier expresión después de `extends`. -For instance, a function call that generates the parent class: +Por ejemplo, una llamada a función que genera la clase padre: ```js run function f(phrase) { @@ -107,39 +81,39 @@ function f(phrase) { } *!* -class User extends f("Hello") {} +class User extends f("Hola") {} */!* -new User().sayHi(); // Hello +new User().sayHi(); // Hola ``` -Here `class User` inherits from the result of `f("Hello")`. +Aquí `class User` hereda del resultado de `f("Hola")`. -That may be useful for advanced programming patterns when we use functions to generate classes depending on many conditions and can inherit from them. +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. ```` -## Overriding a method +## Anular un método -Now let's move forward and override a method. As of now, `Rabbit` inherits the `stop` method that sets `this.speed = 0` from `Animal`. +Ahora avancemos y anulemos 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`. -If we specify our own `stop` in `Rabbit`, then it will be used instead: +Si especificamos nuestro propio método `stop()` en `Rabbit`, se utilizará en su lugar: ```js class Rabbit extends Animal { stop() { - // ...this will be used for rabbit.stop() + // ...esto se usará para rabbit.stop() + // en lugar de stop () de la clase Animal } } ``` +...Pero, por lo general, 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 en el proceso. -...But usually we don't want to totally replace a parent method, but rather to build on top of it, tweak or extend its functionality. We do something in our method, but call the parent method before/after it or in the process. +Las clases proporcionan la palabra clave `"super"` para eso. -Classes provide `"super"` keyword for that. +- `super.method(...)` llamar a un método padre. +- `super(...)` llamar a un constructor padre (solo dentro de nuestro constructor). -- `super.method(...)` to call a parent method. -- `super(...)` to call a parent constructor (inside our constructor only). - -For instance, let our rabbit autohide when stopped: +Por ejemplo, dejemos que nuestro conejo se oculte automáticamente cuando se detenga: ```js run class Animal { @@ -150,70 +124,70 @@ class Animal { } run(speed) { - this.speed += speed; - alert(`${this.name} runs with speed ${this.speed}.`); + this.speed = speed; + alert(`${this.name} corre a una velocidad de ${this.speed}.`); } stop() { this.speed = 0; - alert(`${this.name} stopped.`); + alert(`${this.name} se queda quieto.`); } } class Rabbit extends Animal { hide() { - alert(`${this.name} hides!`); + alert(`${this.name} se esconde!`); } *!* stop() { - super.stop(); // call parent stop - this.hide(); // and then hide + super.stop(); // llama el stop padre + this.hide(); // y luego hide } */!* } -let rabbit = new Rabbit("White Rabbit"); +let rabbit = new Rabbit("Conejo Blanco"); -rabbit.run(5); // White Rabbit runs with speed 5. -rabbit.stop(); // White Rabbit stopped. White rabbit hides! +rabbit.run(5); // Conejo Blanco corre a una velocidad de 5. +rabbit.stop(); // Conejo Blanco se queda quieto. Conejo Blanco se esconde! ``` -Now `Rabbit` has the `stop` method that calls the parent `super.stop()` in the process. +Ahora `Rabbit` tiene el método `stop` que llama al padre `super.stop()` en el proceso. -````smart header="Arrow functions have no `super`" -As was mentioned in the chapter , arrow functions do not have `super`. +````smart header="Las funciones de flecha no tienen `super`" +Como se mencionó en el capítulo , las funciones de flecha no tienen `super`. -If accessed, it's taken from the outer function. For instance: +Si se accede, se toma de la función externa. Por ejemplo: ```js class Rabbit extends Animal { stop() { - setTimeout(() => super.stop(), 1000); // call parent stop after 1sec + setTimeout(() => super.stop(), 1000); // llama al padre stop despues de 1seg } } ``` -The `super` in the arrow function is the same as in `stop()`, so it works as intended. If we specified a "regular" function here, there would be an error: +El método `super` en la función de flecha es el mismo que en `stop()`, por lo que funciona según lo previsto. Si especificamos una función "regular" aquí, habría un error: ```js -// Unexpected super +// super inesperado setTimeout(function() { super.stop() }, 1000); ``` ```` -## Overriding constructor +## Anular un constructor -With constructors it gets a little bit tricky. +Con los constructores se pone un poco complicado. -Till now, `Rabbit` did not have its own `constructor`. +Hasta ahora, `Rabbit` no tenía su propio `constructor`. -According to the [specification](https://tc39.github.io/ecma262/#sec-runtime-semantics-classdefinitionevaluation), if a class extends another class and has no `constructor`, then the following `constructor` is generated: +De acuerdo con la [especificación] (https://tc39.github.io/ecma262/#sec-runtime-semantics-classdefinitionevaluation), si una clase extiende otra clase y no tiene `constructor`, se genera el siguiente `constructor` "vacío": ```js class Rabbit extends Animal { - // generated for extending classes without own constructors + // generado para extender clases sin constructores propios *!* constructor(...args) { super(...args); @@ -222,9 +196,9 @@ class Rabbit extends Animal { } ``` -As we can see, it basically calls the parent `constructor` passing it all the arguments. That happens if we don't write a constructor of our own. +Como podemos ver, básicamente llama al padre `constructor` pasándole todos los argumentos. Eso sucede si no escribimos un constructor propio. -Now let's add a custom constructor to `Rabbit`. It will specify the `earLength` in addition to `name`: +Ahora agreguemos un constructor personalizado a `Rabbit`. Especificará `earLength` además de `name`: ```js run class Animal { @@ -249,29 +223,29 @@ class Rabbit extends Animal { } *!* -// Doesn't work! -let rabbit = new Rabbit("White Rabbit", 10); // Error: this is not defined. +// No funciona! +let rabbit = new Rabbit("Conejo Blanco", 10); // Error: esto no está definido. */!* ``` -Whoops! We've got an error. Now we can't create rabbits. What went wrong? +Whoops! Tenemos un error. Ahora no podemos crear conejos. ¿Qué salió mal? -The short answer is: constructors in inheriting classes must call `super(...)`, and (!) do it before using `this`. +La respuesta corta es: los constructores en las clases heredadas deben llamar a `super(...)`, y (!) Hacerlo antes de usar `this`. -...But why? What's going on here? Indeed, the requirement seems strange. +...¿Pero por qué? ¿Que está pasando aqui? De hecho, el requisito parece extraño. -Of course, there's an explanation. Let's get into details, so you'd really understand what's going on. +Por supuesto, hay una explicación. Vamos a entrar en detalles, para que realmente entiendas lo que está pasando. -In JavaScript, there's a distinction between a "constructor function of an inheriting class" and all others. In an inheriting class, the corresponding constructor function is labelled with a special internal property `[[ConstructorKind]]:"derived"`. +En JavaScript, hay una distinción entre una función constructora de una clase heredera (llamada "constructor derivado") y otras funciones. Un constructor derivado tiene una propiedad interna especial `[[ConstructorKind]]:"derived"`. Esa es una etiqueta interna especial. -The difference is: +Esa etiqueta afecta su comportamiento con `new`. -- When a normal constructor runs, it creates an empty object as `this` and continues with it. -- But when a derived constructor runs, it doesn't do it. It expects the parent constructor to do this job. +- Cuando una función regular se ejecuta con `new`, crea un objeto vacío y lo asigna a `this`. +- Pero cuando se ejecuta un constructor derivado, no hace esto. Espera que el constructor padre haga este trabajo. -So if we're making a constructor of our own, then we must call `super`, because otherwise the object with `this` reference to it won't be created. And we'll get an error. +Por lo tanto, un constructor derivado debe llamar a `super` para ejecutar su constructor padre (no derivado), de lo contrario no se creará el objeto para `this`. Y obtendremos un error. -For `Rabbit` to work, we need to call `super()` before using `this`, like here: +Para que el constructor `Rabbit` funcione, necesita llamar a `super()` antes de usar `this`, como aquí: ```js run class Animal { @@ -298,32 +272,40 @@ class Rabbit extends Animal { *!* // now fine -let rabbit = new Rabbit("White Rabbit", 10); -alert(rabbit.name); // White Rabbit +let rabbit = new Rabbit("Conejo Blanco", 10); +alert(rabbit.name); // Conejo Blanco alert(rabbit.earLength); // 10 */!* ``` -## Super: internals, [[HomeObject]] +## [[HomeObject]]: el `super` interno + +```warn header="Información avanzada" +Si está leyendo el tutorial por primera vez, esta sección puede omitirse. + +Esta sección trata de los mecanismos internos detrás de la herencia y el método `super`. +``` -Let's get a little deeper under the hood of `super`. We'll see some interesting things by the way. +Vamos a profundizar un poco más bajo la sombra de `super`. Veremos algunas cosas interesantes en el camino. -First to say, from all that we've learned till now, it's impossible for `super` to work. +En primer lugar, de todo lo que hemos aprendido hasta ahora, ¡es imposible que `super` funcione en absoluto! -Yeah, indeed, let's ask ourselves, how it could technically work? When an object method runs, it gets the current object as `this`. If we call `super.method()` then, how to retrieve the `method`? Naturally, we need to take the `method` from the prototype of the current object. How, technically, we (or a JavaScript engine) can do it? +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? -Maybe we can get the method from `[[Prototype]]` of `this`, as `this.__proto__.method`? Unfortunately, that doesn't work. +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á. -Let's try to do it. Without classes, using plain objects for the sake of simplicity. +Demostremos el problema. Sin clases, usando objetos simples en aras de la simplicidad. -Here, `rabbit.eat()` should call `animal.eat()` method of the parent object: +Puedes omitir esta parte e ir a la subsección `[[HomeObject]]` si no deseas conocer los detalles. Eso no hará daño. O sigue leyendo si estás interesado en comprender las cosas en profundidad. + +En el siguiente ejemplo, `rabbit.__ proto__ = animal`. Ahora intentemos: en `rabbit.eat()` llamaremos a `animal.eat()`, usando `this.__ proto__`: ```js run let animal = { name: "Animal", eat() { - alert(`${this.name} eats.`); + alert(`${this.name} come.`); } }; @@ -332,33 +314,33 @@ let rabbit = { name: "Rabbit", eat() { *!* - // that's how super.eat() could presumably work + // así es como supuestamente podría funcionar super.eat() this.__proto__.eat.call(this); // (*) */!* } }; -rabbit.eat(); // Rabbit eats. +rabbit.eat(); // Rabbit come. ``` -At the line `(*)` we take `eat` from the prototype (`animal`) and call it in the context of the current object. Please note that `.call(this)` is important here, because a simple `this.__proto__.eat()` would execute parent `eat` in the context of the prototype, not the current object. +En la línea `(*)` tomamos `eat` del prototipo (`animal`) y lo llamamos en el contexto del objeto actual. Tenga en cuenta que `.call(this)` es importante aquí, porque un simple `this.__ proto __.eat()` ejecutaría al padre `eat` en el contexto del prototipo, no del objeto actual. -And in the code above it actually works as intended: we have the correct `alert`. +Y en el código anterior, en realidad funciona según lo previsto: tenemos el `alert` correcto. -Now let's add one more object to the chain. We'll see how things break: +Ahora agreguemos un objeto más a la cadena. Veremos cómo se rompen las cosas: ```js run let animal = { name: "Animal", eat() { - alert(`${this.name} eats.`); + alert(`${this.name} come.`); } }; let rabbit = { __proto__: animal, eat() { - // ...bounce around rabbit-style and call parent (animal) method + // ...rebota alrededor al estilo de conejo y llama al método padre (animal) this.__proto__.eat.call(this); // (*) } }; @@ -366,100 +348,158 @@ let rabbit = { let longEar = { __proto__: rabbit, eat() { - // ...do something with long ears and call parent (rabbit) method + // ...haz algo con orejas largas y llama al método padre (rabbit) this.__proto__.eat.call(this); // (**) } }; *!* -longEar.eat(); // Error: Maximum call stack size exceeded +longEar.eat(); // Error: Se excedió el número máximo de llamadas a la pila */!* ``` -The code doesn't work anymore! We can see the error trying to call `longEar.eat()`. +¡El código ya no funciona! Podemos ver el error al intentar llamar a `longEar.eat()`. -It may be not that obvious, but if we trace `longEar.eat()` call, then we can see why. In both lines `(*)` and `(**)` the value of `this` is the current object (`longEar`). That's essential: all object methods get the current object as `this`, not a prototype or something. +Puede que no sea tan obvio, pero si rastreamos la llamada `longEar.eat()`, entonces podemos ver por qué. En ambas líneas `(*)` y `(**)` el valor de `this` es el objeto actual (`longEar`). Eso es esencial: todos los métodos de objeto obtienen el objeto actual como `this`, no un prototipo o algo así. -So, in both lines `(*)` and `(**)` the value of `this.__proto__` is exactly the same: `rabbit`. They both call `rabbit.eat` without going up the chain in the endless loop. +Entonces, en ambas líneas `(*)` y `(**)` el valor de `this.__ proto__` es exactamente el mismo: `rabbit`. Ambos llaman a `rabbit.eat` sin subir la cadena en el bucle sin fin. -Here's the picture of what happens: +Aquí está la imagen de lo que sucede: ![](this-super-loop.svg) -1. Inside `longEar.eat()`, the line `(**)` calls `rabbit.eat` providing it with `this=longEar`. +1. Dentro de `longEar.eat()`, la línea `(**)` llama a `rabbit.eat` proporcionándole `this=longEar`. ```js - // inside longEar.eat() we have this = longEar + // dentro de longEar.eat() tenemos this = longEar this.__proto__.eat.call(this) // (**) - // becomes + // se convierte en longEar.__proto__.eat.call(this) - // that is + // es decir rabbit.eat.call(this); ``` -2. Then in the line `(*)` of `rabbit.eat`, we'd like to pass the call even higher in the chain, but `this=longEar`, so `this.__proto__.eat` is again `rabbit.eat`! +2. Luego, en la línea `(*)` de `rabbit.eat`, nos gustaría pasar la llamada aún más arriba en la cadena, pero `this=longEar`, entonces `this.__ proto __.eat` es nuevamente `rabbit.eat`! ```js - // inside rabbit.eat() we also have this = longEar + // dentro de rabbit.eat () también tenemos this = longEar this.__proto__.eat.call(this) // (*) - // becomes + // se convierte en longEar.__proto__.eat.call(this) - // or (again) + // o (de nuevo) rabbit.eat.call(this); ``` -3. ...So `rabbit.eat` calls itself in the endless loop, because it can't ascend any further. +3. ...Entonces `rabbit.eat` se llama a sí mismo en el bucle sin fin, porque no puede ascender más. -The problem can't be solved by using `this` alone. +El problema no se puede resolver usando solo `this`. ### `[[HomeObject]]` -To provide the solution, JavaScript adds one more special internal property for functions: `[[HomeObject]]`. - -**When a function is specified as a class or object method, its `[[HomeObject]]` property becomes that object.** +Para proporcionar la solución, JavaScript agrega una propiedad interna especial más para las funciones: `[[HomeObject]]`. -This actually violates the idea of "unbound" functions, because methods remember their objects. And `[[HomeObject]]` can't be changed, so this bound is forever. So that's a very important change in the language. +Cuando una función se especifica como un método de clase u objeto, su propiedad `[[HomeObject]]` se convierte en ese objeto. -But this change is safe. `[[HomeObject]]` is used only for calling parent methods in `super`, to resolve the prototype. So it doesn't break compatibility. +Entonces `super` lo usa para resolver el problema del prototipo padre y sus métodos. -Let's see how it works for `super` -- again, using plain objects: +Veamos cómo funciona, primero con objetos simples: ```js run let animal = { name: "Animal", - eat() { // [[HomeObject]] == animal - alert(`${this.name} eats.`); + eat() { // animal.eat.[[HomeObject]] == animal + alert(`${this.name} come.`); } }; let rabbit = { __proto__: animal, name: "Rabbit", - eat() { // [[HomeObject]] == rabbit + eat() { // rabbit.eat.[[HomeObject]] == rabbit super.eat(); } }; let longEar = { __proto__: rabbit, - name: "Long Ear", - eat() { // [[HomeObject]] == longEar + name: "Oreja Larga", + eat() { // longEar.eat.[[HomeObject]] == longEar super.eat(); } }; *!* -longEar.eat(); // Long Ear eats. +// funciona correctamente +longEar.eat(); // Oreja Larga come. */!* ``` -Every method remembers its object in the internal `[[HomeObject]]` property. Then `super` uses it to resolve the parent prototype. +Funciona según lo previsto, debido a la mecánica de `[[HomeObject]]`. Un método, como `longEar.eat`, conoce su `[[HomeObject]]` y toma el método padre de su prototipo. Sin el uso de `this`. + +### Los métodos no son "libres" + +Como hemos sabido antes, generalmente las funciones son "libres", no vinculadas a objetos en JavaScript. Para que puedan copiarse entre objetos y llamarse con otro 'this`. + +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. -`[[HomeObject]]` is defined for methods defined both in classes and in plain objects. But for objects, methods must be specified exactly the given way: as `method()`, not as `"method: function()"`. +El único lugar en el lenguaje donde se usa `[[HomeObject]]` es en `super`. Si un método no usa `super`, entonces todavía podemos considerarlo "libre" y copiarlo entre objetos. Pero con `super` las cosas pueden salir mal. -In the example below a non-method syntax is used for comparison. `[[HomeObject]]` property is not set and the inheritance doesn't work: +Aquí está la demostración de un resultado `super` incorrecto después de copiar: ```js run let animal = { - eat: function() { // should be the short syntax: eat() {...} + sayHi() { + console.log(`Soy un animal`); + } +}; + +// conejo hereda de animal +let rabbit = { + __proto__: animal, + sayHi() { + super.sayHi(); + } +}; + +let plant = { + sayHi() { + console.log("Soy una planta"); + } +}; + +// arbol hereda de planta +let tree = { + __proto__: plant, +*!* + sayHi: rabbit.sayHi // (*) +*/!* +}; + +*!* +tree.sayHi(); // Soy un animal (?!?) +*/!* +``` + +Una llamada a `tree.sayHi()` muestra "Soy un animal". Definitivamente mal. + +La razón es simple: +- En la línea `(*)`, el método `tree.sayHi` se copió de `rabbit`. ¿Quizás solo queríamos evitar la duplicación de código? +- Su `[[HomeObject]]` es `rabbit`, ya que fue creado en `rabbit`. No hay forma de cambiar `[[HomeObject]]`. +- El código de `tree.sayHi()` tiene dentro a `super.sayHi()`. Sube de 'rabbit' y toma el método de 'animal'. + +Aquí está el diagrama de lo que sucede: + +![](super-homeobject-wrong.svg) + +### Métodos, no propiedades de función + +`[[HomeObject]]` se define para métodos tanto en clases como en objetos simples. Pero para los objetos, los métodos deben especificarse exactamente como `method()`, no como `"method: function()"`. + +La diferencia puede no ser esencial para nosotros, pero es importante para JavaScript. + +En el siguiente ejemplo, se utiliza una sintaxis que no es de método para la comparación. La propiedad `[[HomeObject]]` no está establecida y la herencia no funciona: + +```js run +let animal = { + eat: function() { // escribiendo intencionalmente así en lugar de eat() {... // ... } }; @@ -472,6 +512,21 @@ let rabbit = { }; *!* -rabbit.eat(); // Error calling super (because there's no [[HomeObject]]) +rabbit.eat(); // Error al llamar a super (porque no hay [[HomeObject]]) */!* ``` + +## Resumen + +1. Para extender una clase: `class Child extends Parent`: +     - Eso significa que `Child.prototype.__proto__` será `Parent.prototype`, por lo que los métodos se heredan. +2. Al anular un constructor: +     - Debemos llamar al constructor padre como `super()` en el constructor `Child` antes de usar `this`. +3. Al anular otro método: +     - Podemos usar `super.method()` en un método `Child` para llamar al método `Parent`. +4. Partes internas: +     - Los métodos recuerdan su clase/objeto en la propiedad interna `[[HomeObject]]`. Así es como `super` resuelve los métodos padres. +     - Por lo tanto, no es seguro copiar un método con `super` de un objeto a otro. + +También: +- Las funciones de flecha no tienen su propio `this` o` super`, por lo que se ajustan de manera transparente al contexto circundante. diff --git a/1-js/09-classes/02-class-inheritance/class-inheritance-array-object.svg b/1-js/09-classes/02-class-inheritance/class-inheritance-array-object.svg index 6f2124ebb..10af6c4c2 100644 --- a/1-js/09-classes/02-class-inheritance/class-inheritance-array-object.svg +++ b/1-js/09-classes/02-class-inheritance/class-inheritance-array-object.svg @@ -1,41 +1 @@ - - - - class-inheritance-array-object.svg - Created with sketchtool. - - - - - slice: function - ... - - - Array.prototype - - - arr - - - - hasOwnProperty: function - ... - - - Object.prototype - - - - - - [1, 2, 3] - - - [[Prototype]] - - - [[Prototype]] - - - - \ No newline at end of file +slice: function ...Array.prototypearrhasOwnProperty: function ...Object.prototype[1, 2, 3][[Prototype]][[Prototype]] \ No newline at end of file diff --git a/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal-2.svg b/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal-2.svg index 9714d6708..a81676e25 100644 --- a/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal-2.svg +++ b/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal-2.svg @@ -1,62 +1 @@ - - - - class-inheritance-rabbit-animal-2.svg - Created with sketchtool. - - - - - jump: function - - - Rabbit.prototype - - - rabbit - - - - eat: function - - - Animal.prototype - - - - - - name: "White Rabbit" - - - [[Prototype]] - - - [[Prototype]] - - - Rabbit.prototype.__proto__ = Animal.prototype sets this - - - - toString: function - hasOwnProperty: function - ... - - - Object.prototype - - - - [[Prototype]] - - - - [[Prototype]] - - - null - - - - \ No newline at end of file +jump: functionRabbit.prototyperabbiteat: functionAnimal.prototypename: "White Rabbit"[[Prototype]][[Prototype]]Rabbit.prototype.__proto__ = Animal.prototype sets thistoString: function hasOwnProperty: function ...Object.prototype[[Prototype]][[Prototype]]null \ No newline at end of file diff --git a/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal.svg b/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal.svg index 249bfa4c9..35529aa43 100644 --- a/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal.svg +++ b/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal.svg @@ -1,39 +1 @@ - - - - class-inheritance-rabbit-animal.svg - Created with sketchtool. - - - - - methods of Rabbit - - - Rabbit.prototype - - - rabbit - - - - methods of Animal - - - Animal.prototype - - - - - - [[Prototype]] - - - [[Prototype]] - - - properties of rabbit - - - - \ No newline at end of file +methods of RabbitRabbit.prototyperabbitmethods of AnimalAnimal.prototype[[Prototype]][[Prototype]]properties of rabbit \ No newline at end of file diff --git a/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-animal.svg b/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-animal.svg index 7a16b7855..905efe37a 100644 --- a/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-animal.svg +++ b/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-animal.svg @@ -1,42 +1 @@ - - - - rabbit-animal-independent-animal.svg - Created with sketchtool. - - - - - - constructor: Animal - run: function - stop: function - - - Animal.prototype - - - - Animal - - - - new Animal - - - - - [[Prototype]] - - - prototype - - - name: "My animal" - - - constructor - - - - \ No newline at end of file + constructor: Animal run: function stop: functionAnimal.prototypeAnimalnew Animal[[Prototype]]prototypename: "My animal" \ No newline at end of file diff --git a/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-rabbit.svg b/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-rabbit.svg index ab936c151..81bf1850b 100644 --- a/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-rabbit.svg +++ b/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-rabbit.svg @@ -1,41 +1 @@ - - - - rabbit-animal-independent-rabbit.svg - Created with sketchtool. - - - - - - constructor: Rabbit - hide: function - - - Rabbit.prototype - - - - Rabbit - - - - new Rabbit - - - - - [[Prototype]] - - - prototype - - - name: "My rabbit" - - - constructor - - - - \ No newline at end of file + constructor: Rabbit hide: functionRabbit.prototypeRabbitnew Rabbit[[Prototype]]prototypename: "My rabbit" \ No newline at end of file diff --git a/1-js/09-classes/02-class-inheritance/super-homeobject-wrong.svg b/1-js/09-classes/02-class-inheritance/super-homeobject-wrong.svg new file mode 100644 index 000000000..f13d441c9 --- /dev/null +++ b/1-js/09-classes/02-class-inheritance/super-homeobject-wrong.svg @@ -0,0 +1 @@ +sayHiplantsayHitreesayHianimalrabbit[[HomeObject]]sayHi \ No newline at end of file diff --git a/1-js/09-classes/02-class-inheritance/this-super-loop.svg b/1-js/09-classes/02-class-inheritance/this-super-loop.svg index 7862b41c0..bc200fab3 100644 --- a/1-js/09-classes/02-class-inheritance/this-super-loop.svg +++ b/1-js/09-classes/02-class-inheritance/this-super-loop.svg @@ -1,72 +1 @@ - - - - this-super-loop.svg - Created with sketchtool. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - rabbit - - - longEar - - - rabbit - - - longEar - - - - - - - - \ No newline at end of file +rabbitlongEarrabbitlongEar \ No newline at end of file diff --git a/1-js/09-classes/05-extend-natives/article.md b/1-js/09-classes/05-extend-natives/article.md index 4cf1c2bdd..c2195c510 100644 --- a/1-js/09-classes/05-extend-natives/article.md +++ b/1-js/09-classes/05-extend-natives/article.md @@ -1,12 +1,12 @@ -# Extending built-in classes +# Ampliación de clases integradas -Built-in classes like Array, Map and others are extendable also. +Las clases integradas como Array, Map y otras también son extensibles. -For instance, here `PowerArray` inherits from the native `Array`: +Por ejemplo, aquí `PowerArray` hereda del nativo `Array`: ```js run -// add one more method to it (can do more) +// se agrega un método más (puedes hacer más) class PowerArray extends Array { isEmpty() { return this.length === 0; @@ -14,28 +14,27 @@ class PowerArray extends Array { } let arr = new PowerArray(1, 2, 5, 10, 50); -alert(arr.isEmpty()); // false +alert(arr.isEmpty()); // falso let filteredArr = arr.filter(item => item >= 10); alert(filteredArr); // 10, 50 -alert(filteredArr.isEmpty()); // false +alert(filteredArr.isEmpty()); // falso ``` -Please note a very interesting thing. Built-in methods like `filter`, `map` and others -- return new objects of exactly the inherited type. They rely on the `constructor` property to do so. +Tenga en cuenta una cosa muy interesante. Métodos incorporados como `filter`, `map` y otros: devuelven nuevos objetos exactamente del tipo heredado `PowerArray`. Su implementación interna utiliza la propiedad `constructor` del objeto para eso. -In the example above, +En el ejemplo anterior, ```js arr.constructor === PowerArray ``` -So when `arr.filter()` is called, it internally creates the new array of results exactly as `new PowerArray`. -That's actually very cool, because we can keep using `PowerArray` methods further on the result. +Cuando se llama a `arr.filter()`, crea internamente la nueva matriz de resultados usando exactamente `arr.constructor`, no el básico `Array`. En realidad, eso es muy bueno, porque podemos seguir usando métodos `PowerArray` más adelante en el resultado. -Even more, we can customize that behavior. +Aún más, podemos personalizar ese comportamiento. -There's a special static getter `Symbol.species`, if exists, it returns the constructor to use in such cases. +Podemos agregar un `getter` estático especial `Symbol.species` a la clase. Si existe, debería devolver el constructor que JavaScript usará internamente para crear nuevas entidades en `map`, `filter` y así sucesivamente. -If we'd like built-in methods like `map`, `filter` will return regular arrays, we can return `Array` in `Symbol.species`, like here: +Si queremos que los métodos incorporados como `map` o `filter` devuelvan matrices regulares, podemos devolver `Array` en `Symbol.species`, como aquí: ```js run class PowerArray extends Array { @@ -44,7 +43,7 @@ class PowerArray extends Array { } *!* - // built-in methods will use this as the constructor + // los métodos incorporados usarán esto como el constructor static get [Symbol.species]() { return Array; } @@ -52,31 +51,39 @@ class PowerArray extends Array { } let arr = new PowerArray(1, 2, 5, 10, 50); -alert(arr.isEmpty()); // false +alert(arr.isEmpty()); // falso -// filter creates new array using arr.constructor[Symbol.species] as constructor +// filter crea una nueva matriz usando arr.constructor[Symbol.species] como constructor let filteredArr = arr.filter(item => item >= 10); *!* -// filteredArr is not PowerArray, but Array +// filterArr no es PowerArray, sino Array */!* -alert(filteredArr.isEmpty()); // Error: filteredArr.isEmpty is not a function +alert(filteredArr.isEmpty()); // Error: filterArr.isEmpty no es una función ``` -As you can see, now `.filter` returns `Array`. So the extended functionality is not passed any further. +Como puede ver, ahora `.filter` devuelve `Array`. Por lo tanto, la funcionalidad extendida ya no se pasa. -## No static inheritance in built-ins +```smart header="Other collections trabaja similarmente" +Otras colecciones, como `Map` y `Set`, funcionan igual. También usan `Symbol.species`. +``` + +## Sin herencia estática en incorporados -Built-in objects have their own static methods, for instance `Object.keys`, `Array.isArray` etc. +Los objetos incorporados tienen sus propios métodos estáticos, por ejemplo, `Object.keys`, `Array.isArray`, etc. -And we've already been talking about native classes extending each other: `Array.[[Prototype]] = Object`. +Como ya sabemos, las clases nativas se extienden entre sí. Por ejemplo, `Array` extiende `Object`. -But statics are an exception. Built-in classes don't inherit static properties from each other. +Normalmente, cuando una clase extiende a otra, se heredan los métodos estáticos y no estáticos. Eso se explicó a fondo en el artículo [](info:static-properties-methods#statics-and-inheritance). -In other words, the prototype of built-in constructor `Array` does not point to `Object`. This way `Array` and `Date` do not have `Array.keys` or `Date.keys`. And that feels natural. +Pero las clases integradas son una excepción. No heredan estáticos el uno del otro. -Here's the picture structure for `Date` and `Object`: +Por ejemplo, tanto `Array` como `Date` heredan de `Object`, por lo que sus instancias tienen métodos de `Object.prototype`. Pero `Array.[[Prototype]]` no hace referencia a `Object`, por lo que no existe, por ejemplo, el método estático `Array.keys()` (o `Date.keys()`). + +Aquí está la imagen, estructura para `Date` y `Object`: ![](object-date-inheritance.svg) -Note, there's no link between `Date` and `Object`. Both `Object` and `Date` exist independently. `Date.prototype` inherits from `Object.prototype`, but that's all. +Como puede ver, no hay un vínculo entre `Date` y `Object`. Son independientes, solo `Date.prototype` hereda de `Object.prototype`. + +Esa es una diferencia importante de herencia entre los objetos integrados en comparación con lo que obtenemos con 'extends`. diff --git a/1-js/09-classes/05-extend-natives/object-date-inheritance.svg b/1-js/09-classes/05-extend-natives/object-date-inheritance.svg index f46577f14..470aabf7f 100644 --- a/1-js/09-classes/05-extend-natives/object-date-inheritance.svg +++ b/1-js/09-classes/05-extend-natives/object-date-inheritance.svg @@ -1,71 +1 @@ - - - - object-date-inheritance.svg - Created with sketchtool. - - - - - constructor: Object - toString: function - hasOwnProperty: function - ... - - - - Object.prototype - - - - constructor: Date - toString: function - getDate: function - ... - - - Date.prototype - - - - Object - - - - Date - - - new Date() - - - - - [[Prototype]] - - - - [[Prototype]] - - - prototype - - - - prototype - - - defineProperty - keys - ... - - - now - parse - ... - - - 1 Jan 2019 - - - - \ No newline at end of file +constructor: Object toString: function hasOwnProperty: function ...Object.prototypeconstructor: Date toString: function getDate: function ...Date.prototypeObjectDatenew Date()[[Prototype]][[Prototype]]prototypeprototypedefineProperty keys ...now parse ...1 Jan 2019 \ No newline at end of file