diff --git a/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md b/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md index d2738b9e9..a92e17900 100644 --- a/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md +++ b/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md @@ -1,31 +1,31 @@ -El método puede tomar todas las claves enumerables usando `Object.keys` y generar su lista. +The method can take all enumerable keys using `Object.keys` and output their list. -Para hacer que `toString` no sea enumerable, definámoslo usando un descriptor de propiedad. La sintaxis de `Object.create` nos permite proporcionar un objeto con descriptores de propiedad como segundo argumento. +To make `toString` non-enumerable, let's define it using a property descriptor. The syntax of `Object.create` allows us to provide an object with property descriptors as the second argument. ```js run *!* let dictionary = Object.create(null, { - toString: { // define la propiedad toString - value() { // el valor es una funcion + toString: { // define toString property + value() { // the value is a function return Object.keys(this).join(); } } }); */!* -dictionary.apple = "Manzana"; -dictionary.__proto__ = "prueba"; +dictionary.apple = "Apple"; +dictionary.__proto__ = "test"; -// manzana y __proto__ están en el ciclo +// apple and __proto__ is in the loop for(let key in dictionary) { - alert(key); // "manzana", despues "__proto__" + alert(key); // "apple", then "__proto__" } -// lista de propiedades separadas por comas por toString -alert(dictionary); // "manzana,__proto__" +// comma-separated list of properties by toString +alert(dictionary); // "apple,__proto__" ``` -Cuando creamos una propiedad usando un descriptor, sus banderas son `false` por defecto. Entonces, en el código anterior, `dictionary.toString` no es enumerable. +When we create a property using a descriptor, its flags are `false` by default. So in the code above, `dictionary.toString` is non-enumerable. -Consulte el capítulo [](info:property-descriptors) para su revisión. +See the the chapter [](info:property-descriptors) for review. diff --git a/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/task.md b/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/task.md index cdd70ce82..0d831f2cc 100644 --- a/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/task.md +++ b/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/task.md @@ -2,30 +2,30 @@ importance: 5 --- -# Añadir toString al diccionario +# Add toString to the dictionary -Hay un objeto `dictionary`, creado como `Object.create(null)`, para almacenar cualquier par `clave/valor`. +There's an object `dictionary`, created as `Object.create(null)`, to store any `key/value` pairs. -Agrega el método `dictionary.toString()`, que debería devolver una lista de claves delimitadas por comas. Tu `toString` no debe aparecer al iterar un `for..in` sobre el objeto. +Add method `dictionary.toString()` into it, that should return a comma-delimited list of keys. Your `toString` should not show up in `for..in` over the object. -Así es como debería funcionar: +Here's how it should work: ```js let dictionary = Object.create(null); *!* -// tu código para agregar el método dictionary.toString +// your code to add dictionary.toString method */!* -// agregar algunos datos -dictionary.apple = "Manzana"; -dictionary.__proto__ = "prueba"; // // aquí proto es una propiedad clave común +// add some data +dictionary.apple = "Apple"; +dictionary.__proto__ = "test"; // __proto__ is a regular property key here -// solo manzana y __proto__ están en el ciclo +// only apple and __proto__ are in the loop for(let key in dictionary) { - alert(key); // "manzana", despues "__proto__" + alert(key); // "apple", then "__proto__" } -// tu toString en accion -alert(dictionary); // "manzana,__proto__" +// your toString in action +alert(dictionary); // "apple,__proto__" ``` diff --git a/1-js/08-prototypes/04-prototype-methods/3-compare-calls/solution.md b/1-js/08-prototypes/04-prototype-methods/3-compare-calls/solution.md index 83658fbd6..90d3118bf 100644 --- a/1-js/08-prototypes/04-prototype-methods/3-compare-calls/solution.md +++ b/1-js/08-prototypes/04-prototype-methods/3-compare-calls/solution.md @@ -1,7 +1,7 @@ -La primera llamada tiene `this == rabbit`, las otras tienen `this` igual a `Rabbit.prototype`, porque en realidad es el objeto antes del punto. +The first call has `this == rabbit`, the other ones have `this` equal to `Rabbit.prototype`, because it's actually the object before the dot. -Entonces, solo la primera llamada muestra `Rabbit`, las otras muestran `undefined`: +So only the first call shows `Rabbit`, other ones show `undefined`: ```js run function Rabbit(name) { @@ -11,9 +11,9 @@ Rabbit.prototype.sayHi = function() { alert( this.name ); } -let rabbit = new Rabbit("Conejo"); +let rabbit = new Rabbit("Rabbit"); -rabbit.sayHi(); // Conejo +rabbit.sayHi(); // Rabbit Rabbit.prototype.sayHi(); // undefined Object.getPrototypeOf(rabbit).sayHi(); // undefined rabbit.__proto__.sayHi(); // undefined diff --git a/1-js/08-prototypes/04-prototype-methods/3-compare-calls/task.md b/1-js/08-prototypes/04-prototype-methods/3-compare-calls/task.md index 4fd666fb9..09bb7f1ed 100644 --- a/1-js/08-prototypes/04-prototype-methods/3-compare-calls/task.md +++ b/1-js/08-prototypes/04-prototype-methods/3-compare-calls/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# La diferencia entre llamadas +# The difference between calls -Creemos un nuevo objeto `rabbit`: +Let's create a new `rabbit` object: ```js function Rabbit(name) { @@ -14,10 +14,10 @@ Rabbit.prototype.sayHi = function() { alert(this.name); }; -let rabbit = new Rabbit("Conejo"); +let rabbit = new Rabbit("Rabbit"); ``` -Estas llamadas hacen lo mismo o no? +These calls do the same thing or not? ```js rabbit.sayHi(); diff --git a/1-js/08-prototypes/04-prototype-methods/article.md b/1-js/08-prototypes/04-prototype-methods/article.md index ba110375b..f86f2604e 100644 --- a/1-js/08-prototypes/04-prototype-methods/article.md +++ b/1-js/08-prototypes/04-prototype-methods/article.md @@ -1,28 +1,26 @@ -# Métodos prototipo, objetos sin __proto__ +# Prototype methods, objects without __proto__ -En el primer capítulo de esta sección, mencionamos que existen métodos modernos para configurar un prototipo. +In the first chapter of this section, we mentioned that there are modern methods to setup a prototype. +The `__proto__` is considered outdated and somewhat deprecated (in browser-only part of the JavaScript standard). -`__proto__` se considera desactualizado y algo obsoleto (en la parte propia del navegador dentro del estándar JavaScript). +The modern methods are: +- [Object.create(proto[, descriptors])](mdn:js/Object/create) -- creates an empty object with given `proto` as `[[Prototype]]` and optional property descriptors. +- [Object.getPrototypeOf(obj)](mdn:js/Object/getPrototypeOf) -- returns the `[[Prototype]]` of `obj`. +- [Object.setPrototypeOf(obj, proto)](mdn:js/Object/setPrototypeOf) -- sets the `[[Prototype]]` of `obj` to `proto`. -Los métodos modernos son: +These should be used instead of `__proto__`. -- [Object.create(proto[, descriptors])] (mdn:js/Object/create): crea un objeto vacío con el "proto" dado como `[[Prototype]]` y descriptores de propiedad opcionales. -- [Object.getPrototypeOf(obj)](mdn:js/Object/getPrototypeOf) - devuelve el `[[Prototype]]` de `obj`. -- [Object.setPrototypeOf(obj, proto)](mdn:js/Object/setPrototypeOf) - establece el `[[Prototype]]` de `obj` en `proto`. - -Estos deben usarse en lugar de `__proto__`. - -Por ejemplo: +For instance: ```js run let animal = { eats: true }; -// crear un nuevo objeto con animal como prototipo +// create a new object with animal as a prototype *!* let rabbit = Object.create(animal); */!* @@ -34,11 +32,11 @@ alert(Object.getPrototypeOf(rabbit) === animal); // true */!* *!* -Object.setPrototypeOf(rabbit, {}); // cambia el prototipo de rabbit a {} +Object.setPrototypeOf(rabbit, {}); // change the prototype of rabbit to {} */!* ``` -`Object.create` tiene un segundo argumento opcional: descriptores de propiedad. Podemos proporcionar propiedades adicionales al nuevo objeto allí, así: +`Object.create` has an optional second argument: property descriptors. We can provide additional properties to the new object there, like this: ```js run let animal = { @@ -54,130 +52,116 @@ let rabbit = Object.create(animal, { alert(rabbit.jumps); // true ``` -Los descriptores están en el mismo formato que se describe en el capítulo . +The descriptors are in the same format as described in the chapter . -Podemos usar `Object.create` para realizar una clonación de objetos más poderosa que copiar propiedades en el ciclo `for..in`: +We can use `Object.create` to perform an object cloning more powerful than copying properties in `for..in`: ```js -// // clon superficial de obj totalmente idéntico +// fully identical shallow clone of obj let clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj)); ``` -Esta llamada hace una copia verdaderamente exacta de `obj`, que incluye todas las propiedades: enumerables y no enumerables, propiedades de datos y setters/getters, todo, y con el `[[Prototype]]` correcto. - -## Breve historia - -Si contamos todas las formas de administrar `[[Prototype]]`, ¡hay muchas! ¡Muchas maneras de hacer lo mismo! - -¿Por qué? +This call makes a truly exact copy of `obj`, including all properties: enumerable and non-enumerable, data properties and setters/getters -- everything, and with the right `[[Prototype]]`. +## Brief history -Eso es por razones históricas. +If we count all the ways to manage `[[Prototype]]`, there are a lot! Many ways to do the same thing! +Why? -- La propiedad "prototipo" de una función de constructor ha funcionado desde tiempos muy antiguos. -- Más tarde, en el año 2012, apareció `Object.create` en el estándar. Le dio la capacidad de crear objetos con un prototipo dado, pero no proporcionó la capacidad de obtenerlo/configurarlo. Entonces, los navegadores implementaron el acceso no estándar `__proto__` que permitió al usuario obtener/configurar un prototipo en cualquier momento. -- Más tarde, en el año 2015, `Object.setPrototypeOf` y `Object.getPrototypeOf` se agregaron al estándar, para realizar la misma funcionalidad que `__proto__`. Como `__proto__` se implementó de facto en todas partes, fue desaprobado y llegó al Anexo B de la norma, es decir: opcional para entornos que no son del navegador. +That's for historical reasons. +- The `"prototype"` property of a constructor function has worked since very ancient times. +- Later, in the year 2012, `Object.create` appeared in the standard. It gave the ability to create objects with a given prototype, but did not provide the ability to get/set it. So browsers implemented the non-standard `__proto__` accessor that allowed the user to get/set a prototype at any time. +- Later, in the year 2015, `Object.setPrototypeOf` and `Object.getPrototypeOf` were added to the standard, to perform the same functionality as `__proto__`. As `__proto__` was de-facto implemented everywhere, it was kind-of deprecated and made its way to the Annex B of the standard, that is: optional for non-browser environments. -A partir de ahora tenemos todas estas formas a nuestra disposición. +As of now we have all these ways at our disposal. +Why was `__proto__` replaced by the functions `getPrototypeOf/setPrototypeOf`? That's an interesting question, requiring us to understand why `__proto__` is bad. Read on to get the answer. -¿Por qué se reemplazó `__proto__` por las funciones `getPrototypeOf/setPrototypeOf`? Esa es una pregunta interesante, que requiere que comprendamos por qué `__proto__` es malo. Sigue leyendo para obtener la respuesta. +```warn header="Don't change `[[Prototype]]` on existing objects if speed matters" +Technically, we can get/set `[[Prototype]]` at any time. But usually we only set it once at the object creation time and don't modify it anymore: `rabbit` inherits from `animal`, and that is not going to change. -```warn header="No cambie `[[Prototype]]` en objetos existentes si la velocidad es importante" -Técnicamente, podemos obtener/configurar `[[Prototype]]` en cualquier momento. Pero generalmente solo lo configuramos una vez en el momento de creación del objeto y ya no lo modificamos: `rabbit` hereda de `animal`, y eso no va a cambiar. - -Y los motores de JavaScript están altamente optimizados para esto. Cambiar un prototipo "sobre la marcha" con `Object.setPrototypeOf` u `obj.__ proto __=` es una operación muy lenta ya que rompe las optimizaciones internas para las operaciones de acceso a la propiedad del objeto. Por lo tanto, evítelo a menos que sepa lo que está haciendo, o no le importe la velocidad de JavaScript . +And JavaScript engines are highly optimized for this. Changing a prototype "on-the-fly" with `Object.setPrototypeOf` or `obj.__proto__=` is a very slow operation as it breaks internal optimizations for object property access operations. So avoid it unless you know what you're doing, or JavaScript speed totally doesn't matter for you. ``` -## Objetos "muy simples" [#very-plain] - +## "Very plain" objects [#very-plain] -Como sabemos, los objetos se pueden usar como arreglos asociativas para almacenar pares clave/valor. +As we know, objects can be used as associative arrays to store key/value pairs. -...Pero si tratamos de almacenar claves *proporcionadas por el usuario* en él (por ejemplo, un diccionario ingresado por el usuario), podemos ver una falla interesante: todas las claves funcionan bien excepto `"__proto __ "`. +...But if we try to store *user-provided* keys in it (for instance, a user-entered dictionary), we can see an interesting glitch: all keys work fine except `"__proto__"`. -Mira el ejemplo: +Check out the example: ```js run let obj = {}; -let key = prompt("Cual es la clave?", "__proto__"); -obj[key] = "algún valor"; +let key = prompt("What's the key?", "__proto__"); +obj[key] = "some value"; -alert(obj[key]); // [object Object], no es "algún valor"! +alert(obj[key]); // [object Object], not "some value"! ``` +Here, if the user types in `__proto__`, the assignment is ignored! -Aquí, si el usuario escribe en `__proto__`, ¡la asignación se ignora! - -Eso no debería sorprendernos. La propiedad `__proto__` es especial: debe ser un objeto o `null`. Una cadena no puede convertirse en un prototipo. - - -Pero no *intentamos* implementar tal comportamiento, ¿verdad? Queremos almacenar pares clave/valor, y la clave llamada `"__proto__"` no se guardó correctamente. ¡Entonces eso es un error! +That shouldn't surprise us. The `__proto__` property is special: it must be either an object or `null`. A string can not become a prototype. +But we didn't *intend* to implement such behavior, right? We want to store key/value pairs, and the key named `"__proto__"` was not properly saved. So that's a bug! -Aquí las consecuencias no son terribles. Pero en otros casos podemos estar asignando valores de objeto, y luego el prototipo puede ser cambiado. Como resultado, la ejecución irá mal de maneras totalmente inesperadas. +Here the consequences are not terrible. But in other cases we may be assigning object values, and then the prototype may indeed be changed. As a result, the execution will go wrong in totally unexpected ways. -Lo que es peor: generalmente los desarrolladores no piensan en tal posibilidad en absoluto. Eso hace que tales errores sean difíciles de notar e incluso los convierta en vulnerabilidades, especialmente cuando se usa JavaScript en el lado del servidor. +What's worse -- usually developers do not think about such possibility at all. That makes such bugs hard to notice and even turn them into vulnerabilities, especially when JavaScript is used on server-side. -También pueden ocurrir cosas inesperadas al asignar a `toString`, que es una función por defecto, y a otros métodos integrados. +Unexpected things also may happen when assigning to `toString`, which is a function by default, and to other built-in methods. -¿Cómo podemos evitar este problema? +How can we avoid this problem? -Primero, podemos elegir usar `Map` para almacenamiento en lugar de objetos simples, luego todo queda bien. +First, we can just switch to using `Map` for storage instead of plain objects, then everything's fine. -Pero 'Objeto' también puede servirnos bien aquí, porque los creadores del lenguaje pensaron en ese problema hace mucho tiempo. - -`__proto__` no es una propiedad de un objeto, sino una propiedad de acceso de `Object.prototype`: +But `Object` can also serve us well here, because language creators gave thought to that problem long ago. +`__proto__` is not a property of an object, but an accessor property of `Object.prototype`: ![](object-prototype-2.svg) -Entonces, si se lee o establece `obj.__ proto__`, el getter/setter correspondiente se llama desde su prototipo y obtiene/establece `[[Prototype]]`. - -Como se dijo al comienzo de esta sección del tutorial: `__proto__` es una forma de acceder a `[[Prototype]]`, no es `[[Prototype]]` en sí. +So, if `obj.__proto__` is read or set, the corresponding getter/setter is called from its prototype, and it gets/sets `[[Prototype]]`. +As it was said in the beginning of this tutorial section: `__proto__` is a way to access `[[Prototype]]`, it is not `[[Prototype]]` itself. -Ahora, si pretendemos usar un objeto como una arreglo asociativa y no tener tales problemas, podemos hacerlo con un pequeño truco: +Now, if we intend to use an object as an associative array and be free of such problems, we can do it with a little trick: ```js run *!* let obj = Object.create(null); */!* -let key = prompt("Cual es la clave", "__proto__"); -obj[key] = "algún valor"; +let key = prompt("What's the key?", "__proto__"); +obj[key] = "some value"; -alert(obj[key]); // "algún valor" +alert(obj[key]); // "some value" ``` -`Object.create(null)` crea un objeto vacío sin un prototipo (`[[Prototype]]` es `null`): +`Object.create(null)` creates an empty object without a prototype (`[[Prototype]]` is `null`): ![](object-prototype-null.svg) -Entonces, no hay getter/setter heredado para `__proto__`. Ahora se procesa como una propiedad de datos normal, por lo que el ejemplo anterior funciona correctamente. - +So, there is no inherited getter/setter for `__proto__`. Now it is processed as a regular data property, so the example above works right. -Podemos llamar a estos objetos: objetos "muy simples" o "de diccionario puro", porque son aún más simples que el objeto simple normal `{...}`. +We can call such objects "very plain" or "pure dictionary" objects, because they are even simpler than the regular plain object `{...}`. - -Una desventaja es que dichos objetos carecen de métodos de objetos integrados, p.ej. `toString`: +A downside is that such objects lack any built-in object methods, e.g. `toString`: ```js run *!* let obj = Object.create(null); */!* -alert(obj); // Error (no hay toString) +alert(obj); // Error (no toString) ``` -...Pero eso generalmente está bien para arreglos asociativas. - - -Tenga en cuenta que la mayoría de los métodos relacionados con objetos son `Object.algo(...)`, como `Object.keys(obj)` y no están en el prototipo, por lo que seguirán trabajando en dichos objetos: +...But that's usually fine for associative arrays. +Note that most object-related methods are `Object.something(...)`, like `Object.keys(obj)` -- they are not in the prototype, so they will keep working on such objects: ```js run @@ -185,41 +169,37 @@ let chineseDictionary = Object.create(null); chineseDictionary.hello = "你好"; chineseDictionary.bye = "再见"; -alert(Object.keys(chineseDictionary)); // hola,adios +alert(Object.keys(chineseDictionary)); // hello,bye ``` -## Resumen - - -Los métodos modernos para configurar y acceder directamente al prototipo son: +## Summary -- [Object.create(proto[, descriptores])](mdn:js/Object/create) - crea un objeto vacío con un `proto` dado como `[[Prototype]]` (puede ser `nulo`) y descriptores de propiedad opcionales. -- [Object.getPrototypeOf(obj)](mdn:js/Object.getPrototypeOf) - devuelve el `[[Prototype]]` de `obj` (igual que el getter de `__proto__`). -- [Object.setPrototypeOf(obj, proto)](mdn:js/Object.setPrototypeOf) - establece el `[[Prototype]]` de `obj` en `proto` (igual que el setter de `__proto__`). +Modern methods to set up and directly access the prototype are: -El getter/setter incorporado de `__proto__` no es seguro si queremos poner claves generadas por el usuario en un objeto. Aunque un usuario puede ingresar `"__proto __"` como clave, y habrá un error, con consecuencias levemente dañinas, pero generalmente impredecibles. +- [Object.create(proto[, descriptors])](mdn:js/Object/create) -- creates an empty object with a given `proto` as `[[Prototype]]` (can be `null`) and optional property descriptors. +- [Object.getPrototypeOf(obj)](mdn:js/Object.getPrototypeOf) -- returns the `[[Prototype]]` of `obj` (same as `__proto__` getter). +- [Object.setPrototypeOf(obj, proto)](mdn:js/Object.setPrototypeOf) -- sets the `[[Prototype]]` of `obj` to `proto` (same as `__proto__` setter). +The built-in `__proto__` getter/setter is unsafe if we'd want to put user-generated keys into an object. Just because a user may enter `"__proto__"` as the key, and there'll be an error, with hopefully light, but generally unpredictable consequences. -Entonces podemos usar `Object.create(null)` para crear un objeto "muy simple" sin `__proto__`, o apegarnos a los objetos `Map` para eso. +So we can either use `Object.create(null)` to create a "very plain" object without `__proto__`, or stick to `Map` objects for that. -Además, `Object.create` proporciona una manera fácil de copiar llanamente un objeto con todos los descriptores: +Also, `Object.create` provides an easy way to shallow-copy an object with all descriptors: ```js let clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj)); ``` +We also made it clear that `__proto__` is a getter/setter for `[[Prototype]]` and resides in `Object.prototype`, just like other methods. -También dejamos en claro que `__proto__` es un getter/setter para `[[Prototype]]` y reside en `Object.prototype`, al igual que otros métodos. - -Podemos crear un objeto sin prototipo mediante `Object.create(null)`. Dichos objetos se utilizan como "diccionarios puros", no tienen problemas con `"__proto __"` como clave. - -Otros métodos: +We can create an object without a prototype by `Object.create(null)`. Such objects are used as "pure dictionaries", they have no issues with `"__proto__"` as the key. -- [Object.keys(obj)](mdn:js/Object/keys) / [Object.values(obj)](mdn:js/Object/values) / [Object.entries(obj)](mdn:js/Object/entries): devuelve una arreglo de pares clave-valor: nombres/valores, de propiedades de cadena propios enumerables. -- [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols): devuelve un arreglo de todas las claves simbólicas propias. -- [Object.getOwnPropertyNames(obj)](mdn:js/Object/getOwnPropertyNames): devuelve un arreglo de todas las claves de cadena propias. -- [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys): devuelve un arreglo de todas las claves propias. -- [obj.hasOwnProperty(key)](mdn:js/Object/hasOwnProperty): devuelve `true` si `obj` tiene su propia clave (no heredada) llamada `key`. +Other methods: -Todos los métodos que devuelven propiedades de objeto (como `Object.keys` y otros) - devuelven propiedades "propias". Si queremos heredados, podemos usar `for..in`. +- [Object.keys(obj)](mdn:js/Object/keys) / [Object.values(obj)](mdn:js/Object/values) / [Object.entries(obj)](mdn:js/Object/entries) -- returns an array of enumerable own string property names/values/key-value pairs. +- [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) -- returns an array of all own symbolic keys. +- [Object.getOwnPropertyNames(obj)](mdn:js/Object/getOwnPropertyNames) -- returns an array of all own string keys. +- [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) -- returns an array of all own keys. +- [obj.hasOwnProperty(key)](mdn:js/Object/hasOwnProperty): returns `true` if `obj` has its own (not inherited) key named `key`. +All methods that return object properties (like `Object.keys` and others) -- return "own" properties. If we want inherited ones, we can use `for..in`. diff --git a/1-js/08-prototypes/index.md b/1-js/08-prototypes/index.md index 443804008..8554a0e30 100644 --- a/1-js/08-prototypes/index.md +++ b/1-js/08-prototypes/index.md @@ -1 +1 @@ -# Prototipos, herencia +# Prototypes, inheritance