diff --git a/1-js/02-first-steps/09-comparison/article.md b/1-js/02-first-steps/09-comparison/article.md index 76af2abab..8c73959db 100644 --- a/1-js/02-first-steps/09-comparison/article.md +++ b/1-js/02-first-steps/09-comparison/article.md @@ -2,11 +2,17 @@ Conocemos muchos operadores de comparación de las matemáticas: +En Javascript se escriben así: + - Mayor/menor que: a > b, a < b. - Mayor/menor o igual que: a >= b, a <= b. - Igual: `a == b` (ten en cuenta el doble signo `=`. Un solo símbolo `a = b` significaría una asignación). - Distinto. En matemáticas la notación es , pero en JavaScript se escribe como una asignación con un signo de exclamación delante: a != b. +En este artículo, aprenderemos más sobre los diferentes tipos de comparaciones, cómo las realiza JavaScript, incluidas las peculiaridades importantes. + +Al final, encontrará una buena receta para evitar problemas relacionados con "peculiaridades de JavaScript"("javascript quirks"). + ## Booleano es el resultado Como todos los demás operadores, una comparación retorna un valor. En este caso, el valor es un booleano. @@ -195,7 +201,7 @@ Obtenemos estos resultados porque: - Las comparaciones `(1)` y `(2)` retornan `falso` porque `no definido` se convierte en `NaN` y `NaN` es un valor numérico especial que retorna `falso` para todas las comparaciones. - La comparación de igualdad `(3)` retorna `falso` porque `undefined` sólo equivale a `null` y a ningún otro valor. -### Evita los problemas +### Evitar los problemas ¿Por qué repasamos estos ejemplos? ¿Deberíamos recordar estas peculiaridades todo el tiempo? Bueno, en realidad no. En realidad, estas cosas difíciles se volverán familiares con el tiempo, pero hay una manera sólida de evadir los problemas con ellas: diff --git a/1-js/05-data-types/02-number/article.md b/1-js/05-data-types/02-number/article.md index 575b0cfcf..1c85b6381 100644 --- a/1-js/05-data-types/02-number/article.md +++ b/1-js/05-data-types/02-number/article.md @@ -148,7 +148,7 @@ Hay dos formas de hacerlo: 1. Multiplicar y dividir. - Para redondear el número a dos dígitos tras el decimal, podemos multiplicarlo por `100`, llamar la función de redondeo y volverlo a dividir. + Para redondear el número a dos dígitos tras el decimal, podemos multiplicarlo por `100` (o una potencia mayor de 10), llamar la función de redondeo y volverlo a dividir. ```js run let num = 1.23456; diff --git a/1-js/05-data-types/09-keys-values-entries/article.md b/1-js/05-data-types/09-keys-values-entries/article.md index 4af192515..b633dc274 100644 --- a/1-js/05-data-types/09-keys-values-entries/article.md +++ b/1-js/05-data-types/09-keys-values-entries/article.md @@ -74,7 +74,7 @@ Usually that's convenient. But if we want symbolic keys too, then there's a sepa Objects lack many methods that exist for arrays, e.g. `map`, `filter` and others. -If we'd like to apply them, then we can use `Object.entries` followed `Object.fromEntries`: +If we'd like to apply them, then we can use `Object.entries` followed by `Object.fromEntries`: 1. Use `Object.entries(obj)` to get an array of key/value pairs from `obj`. 2. Use array methods on that array, e.g. `map`. diff --git a/1-js/06-advanced-functions/03-closure/article.md b/1-js/06-advanced-functions/03-closure/article.md index 9d875899b..ff77ca979 100644 --- a/1-js/06-advanced-functions/03-closure/article.md +++ b/1-js/06-advanced-functions/03-closure/article.md @@ -184,7 +184,7 @@ Los rectángulos en el lado derecho demuestran cómo cambia el entorno léxico g 1. Cuando se inicia el script, el entorno léxico se rellena previamente con todas las variables declaradas.      - Inicialmente, están en el estado "No inicializado". Ese es un estado interno especial, significa que el motor conoce la variable, pero no se puede hacer referencia a ella hasta que se haya declarado con `let`. Es casi lo mismo que si la variable no existiera. -2. Luego aparece la definición `let phrase`.Todavía no hay una asignación, por lo que su valor es `undefined`. Podemos usar la variable desde este momento. +2. Luego aparece la definición `let phrase`.Todavía no hay una asignación, por lo que su valor es `undefined`. Podemos usar la variable desde este punto en adelante. 3. `phrase` se le asigna un valor. 4. `phrase` cambia el valor. diff --git a/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/solution.js b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/solution.js new file mode 100644 index 000000000..c7d7d734e --- /dev/null +++ b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/solution.js @@ -0,0 +1,15 @@ +function sum(a) { + + let currentSum = a; + + function f(b) { + currentSum += b; + return f; + } + + f.toString = function() { + return currentSum; + }; + + return f; +} diff --git a/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/source.js b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/source.js new file mode 100644 index 000000000..f10dca5dc --- /dev/null +++ b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/source.js @@ -0,0 +1,12 @@ +function sum(a){ + // Your code goes here. + +} + +/* +sum(1)(2) == 3; // 1 + 2 +sum(1)(2)(3) == 6; // 1 + 2 + 3 +sum(5)(-1)(2) == 6 +sum(6)(-1)(-2)(-3) == 0 +sum(0)(1)(2)(3)(4)(5) == 15 +*/ diff --git a/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/test.js b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/test.js new file mode 100644 index 000000000..ed567d330 --- /dev/null +++ b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/test.js @@ -0,0 +1,19 @@ +describe("sum", function(){ + + it("sum(1)(2) == 3", function(){ + assert.equal(3, sum(1)(2)); + }); + + it("sum(5)(-1)(2) == 6", function(){ + assert.equal(6, sum(5)(-1)(2)); + }); + + it("sum(6)(-1)(-2)(-3) == 0", function(){ + assert.equal(0, sum(6)(-1)(-2)(-3)); + }); + + it("sum(0)(1)(2)(3)(4)(5) == 15", function(){ + assert.equal(15, sum(0)(1)(2)(3)(4)(5)); + }); +}); + diff --git a/1-js/09-classes/01-class/article.md b/1-js/09-classes/01-class/article.md index 672d40215..835143e94 100644 --- a/1-js/09-classes/01-class/article.md +++ b/1-js/09-classes/01-class/article.md @@ -331,7 +331,7 @@ alert(user.name); // John alert(User.prototype.name); // undefined ``` -Technically, they are processed after the constructor has done it's job, and we can use for them complex expressions and function calls: +We can also assign values using more complex expressions and function calls: ```js run class User { @@ -375,30 +375,9 @@ The problem is called "losing `this`". There are two approaches to fixing it, as discussed in the chapter : 1. Pass a wrapper-function, such as `setTimeout(() => button.click(), 1000)`. -2. Bind the method to object, e.g. in the constructor: +2. Bind the method to object, e.g. in the constructor. -```js run -class Button { - constructor(value) { - this.value = value; -*!* - this.click = this.click.bind(this); -*/!* - } - - click() { - alert(this.value); - } -} - -let button = new Button("hello"); - -*!* -setTimeout(button.click, 1000); // hello -*/!* -``` - -Class fields provide a more elegant syntax for the latter solution: +Class fields provide another, quite elegant syntax: ```js run class Button { @@ -417,9 +396,9 @@ let button = new Button("hello"); setTimeout(button.click, 1000); // hello ``` -The class field `click = () => {...}` creates an independent function on each `Button` object, with `this` bound to the object. Then we can pass `button.click` around anywhere, and it will be called with the right `this`. +The class field `click = () => {...}` is created on a per-object basis, there's a separate function for each `Button` object, with `this` inside it referencing that object. We can pass `button.click` around anywhere, and the value of `this` will always be correct. -That's especially useful in browser environment, when we need to setup a method as an event listener. +That's especially useful in browser environment, for event listeners. ## Summary diff --git a/1-js/09-classes/02-class-inheritance/article.md b/1-js/09-classes/02-class-inheritance/article.md index 22b2e65c5..e3278b5f1 100644 --- a/1-js/09-classes/02-class-inheritance/article.md +++ b/1-js/09-classes/02-class-inheritance/article.md @@ -230,7 +230,8 @@ let rabbit = new Rabbit("Conejo Blanco", 10); // Error: esto no está definido. Vaya! Tenemos un error. Ahora no podemos crear conejos. ¿Qué salió mal? -La respuesta corta es: los constructores en las clases heredadas deben llamar a `super(...)`, y (!) Hacerlo antes de usar `this`. +La respuesta corta es: +- **Los constructores en las clases heredadas deben llamar a `super(...)`, y (!) hacerlo antes de usar `this`**. ...¿Pero por qué? ¿Que está pasando aqui? De hecho, el requisito parece extraño. @@ -243,7 +244,7 @@ Esa etiqueta afecta su comportamiento con `new`. - 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. -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. +**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.** Para que el constructor `Rabbit` funcione, necesita llamar a `super()` antes de usar `this`, como aquí: @@ -277,7 +278,91 @@ alert(rabbit.name); // Conejo Blanco alert(rabbit.earLength); // 10 */!* ``` +### Overriding class fields: a tricky note +```warn header="Advanced note" +This note assumes you have a certain experience with classes, maybe in other programming languages. +It provides better insight into the language and also explains the behavior that might be a source of bugs (but not very often). +If you find it difficult to understand, just go on, continue reading, then return to it some time later. +``` + +We can override not only methods, but also class fields. + +Although, there's a tricky behavior when we access an overridden field in parent constructor, quite different from most other programming languages. + +Consider this example: + +```js run +class Animal { + name = 'animal' + constructor() { + alert(this.name); // (*) + } +} +class Rabbit extends Animal { + name = 'rabbit'; +} +new Animal(); // animal +*!* +new Rabbit(); // animal +*/!* +``` + +Here, class `Rabbit` extends `Animal` and overrides `name` field with its own value. + +There's no own constructor in `Rabbit`, so `Animal` constructor is called. + +What's interesting is that in both cases: `new Animal()` and `new Rabbit()`, the `alert` in the line `(*)` shows `animal`. + +**In other words, parent constructor always uses its own field value, not the overridden one.** + +What's odd about it? + +If it's not clear yet, please compare with methods. + +Here's the same code, but instead of `this.name` field we call `this.showName()` method: + +```js run +class Animal { + showName() { // instead of this.name = 'animal' + alert('animal'); + } + constructor() { + this.showName(); // instead of alert(this.name); + } +} +class Rabbit extends Animal { + showName() { + alert('rabbit'); + } +} +new Animal(); // animal +*!* +new Rabbit(); // rabbit +*/!* +``` + +Please note: now the output is different. + +And that's what we naturally expect. When the parent constructor is called in the derived class, it uses the overridden method. + +...But for class fields it's not so. As said, the parent constructor always uses the parent field. + +Why is there the difference? + +Well, the reason is in the field initialization order. The class field is initialized: +- Before constructor for the base class (that doesn't extend anything), +- Imediately after `super()` for the derived class. + +In our case, `Rabbit` is the derived class. There's no `constructor()` in it. As said previously, that's the same as if there was an empty constructor with only `super(...args)`. + +So, `new Rabbit()` calls `super()`, thus executing the parent constructor, and (per the rule for derived classes) only after that its class fields are initialized. At the time of the parent constructor execution, there are no `Rabbit` class fields yet, that's why `Animal` fields are used. + +This subtle difference between fields and methods is specific to JavaScript + +Luckily, this behavior only reveals itself if an overridden field is used in the parent constructor. Then it may be difficult to understand what's going on, so we're explaining it here. + +If it becomes a problem, one can fix it by using methods or getters/setters instead of fields. ## [[HomeObject]]: el `super` interno diff --git a/1-js/11-async/05-promise-api/article.md b/1-js/11-async/05-promise-api/article.md index e6be25008..191f6ed21 100644 --- a/1-js/11-async/05-promise-api/article.md +++ b/1-js/11-async/05-promise-api/article.md @@ -179,10 +179,10 @@ If the browser doesn't support `Promise.allSettled`, it's easy to polyfill: if(!Promise.allSettled) { Promise.allSettled = function(promises) { return Promise.all(promises.map(p => Promise.resolve(p).then(value => ({ - state: 'fulfilled', + status: 'fulfilled', value }), reason => ({ - state: 'rejected', + status: 'rejected', reason })))); }; @@ -191,7 +191,7 @@ if(!Promise.allSettled) { In this code, `promises.map` takes input values, turns them into promises (just in case a non-promise was passed) with `p => Promise.resolve(p)`, and then adds `.then` handler to every one. -That handler turns a successful result `value` into `{state:'fulfilled', value}`, and an error `reason` into `{state:'rejected', reason}`. That's exactly the format of `Promise.allSettled`. +That handler turns a successful result `value` into `{status:'fulfilled', value}`, and an error `reason` into `{status:'rejected', reason}`. That's exactly the format of `Promise.allSettled`. Now we can use `Promise.allSettled` to get the results of *all* given promises, even if some of them reject. @@ -277,7 +277,7 @@ There are 5 static methods of `Promise` class: 1. `Promise.all(promises)` -- waits for all promises to resolve and returns an array of their results. If any of the given promises rejects, it becomes the error of `Promise.all`, and all other results are ignored. 2. `Promise.allSettled(promises)` (recently added method) -- waits for all promises to settle and returns their results as an array of objects with: - - `state`: `"fulfilled"` or `"rejected"` + - `status`: `"fulfilled"` or `"rejected"` - `value` (if fulfilled) or `reason` (if rejected). 3. `Promise.race(promises)` -- waits for the first promise to settle, and its result/error becomes the outcome. 4. `Promise.resolve(value)` -- makes a resolved promise with the given value. diff --git a/1-js/13-modules/01-modules-intro/article.md b/1-js/13-modules/01-modules-intro/article.md index 5534cbb94..f30b1aacd 100644 --- a/1-js/13-modules/01-modules-intro/article.md +++ b/1-js/13-modules/01-modules-intro/article.md @@ -1,13 +1,13 @@ # Módulos, introducción -A medida que nuestra aplicación crece, queremos dividirla en múltiples archivos, llamados "módulos". Un módulo generalmente contiene una clase o una biblioteca de funciones. +A medida que nuestra aplicación crece, queremos dividirla en múltiples archivos, llamados "módulos". Un módulo puede contener una clase o una biblioteca de funciones para un propósito específico. Durante mucho tiempo, JavaScript existió sin una sintaxis de módulo a nivel de lenguaje. Eso no fue un problema, porque inicialmente los scripts eran pequeños y simples, por lo que no era necesario. Pero con el tiempo los scripts se volvieron cada vez más complejos, por lo que la comunidad inventó una variedad de formas de organizar el código en módulos, bibliotecas especiales para cargar módulos a pedido. -Por ejemplo: +Para nombrar algunos (por razones históricas): - [AMD](https://es.wikipedia.org/wiki/Asynchronous_module_definition) -- uno de los sistemas de módulos más antiguos, implementado inicialmente por la biblioteca [require.js](http://requirejs.org/). - [CommonJS](http://wiki.commonjs.org/wiki/Modules/1.1) -- el sistema de módulos creado para el servidor Node.js. @@ -15,11 +15,11 @@ Por ejemplo: Ahora, todo esto se convierte lentamente en una parte de la historia, pero aún podemos encontrarlos en viejos scripts. -El sistema de módulos a nivel de idioma apareció en el estándar en 2015, evolucionó gradualmente desde entonces y ahora es compatible con todos los principales navegadores y en Node.js. Así que lo estudiaremos de ahora en adelante. +El sistema de módulos a nivel de idioma apareció en el estándar en 2015, evolucionó gradualmente desde entonces y ahora es compatible con todos los principales navegadores y en Node.js. Así que estudiaremos los módulos modernos de Javascript de ahora en adelante. ## Qué es un módulo? -Un módulo es solo un archivo. Un script es un módulo. +Un módulo es solo un archivo. Un script es un módulo. Tan sencillo como eso. Los módulos pueden cargarse entre sí y usar directivas especiales `export` e `import` para intercambiar funcionalidad, llamar a funciones de un módulo de otro: @@ -57,6 +57,10 @@ Asi: El navegador busca y evalúa automáticamente el módulo importado (y sus importaciones si es necesario), y luego ejecuta el script. +```warn header="Los módulos funcionan solo a través de HTTP(s), no en archivos locales" +Si intenta abrir una página web localmente a través del protocolo `file://`, encontrará que las directivas `import / export` no funcionan. Use un servidor web local, como [static-server](https://www.npmjs.com/package/static-server#getting-started) o use la capacidad de "servidor en vivo" de su editor, como VS Code [Live Server Extension](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer) para probar los módulos. +``` + ## Características del módulo central ¿Qué hay de diferente en los módulos en comparación con los scripts "normales"? diff --git a/2-ui/1-document/01-browser-environment/article.md b/2-ui/1-document/01-browser-environment/article.md index 02e5fc322..a21773706 100644 --- a/2-ui/1-document/01-browser-environment/article.md +++ b/2-ui/1-document/01-browser-environment/article.md @@ -2,7 +2,7 @@ El lenguaje JavaScript fue creado inicialmente para los navegadores web. Desde entonces, ha evolucionado y se ha convertido en un lenguaje con muchos usos y plataformas. -Una plataforma puede ser un navegador, un servidor web, una lavadora u otro *host (anfitrión)*. Cada uno de ellos proporciona una funcionalidad específica. La especificación de JavaScript lo llama *entorno host*. +Una plataforma puede ser un navegador, un servidor web u otro *host*, incluso una máquina de café "inteligente", si puede ejecutar JavaScript. Cada uno de ellos proporciona una funcionalidad específica de la plataforma. La especificación de JavaScript llama esto como *entorno de host* (host enviroment). Un entorno host proporciona objetos específicos de la plataforma y funciones adicionales al núcleo del lenguaje. Los navegadores web proporcionan un medio para controlar las páginas web. Node.JS proporciona características del lado del servidor, y así sucesivamente. @@ -47,31 +47,18 @@ document.body.style.background = "red"; setTimeout(() => document.body.style.background = "", 1000); ``` -Aquí usamos `document.body.style`, pero hay muchos, muchos más. Las propiedades y métodos se describen en la especificación. Sucede que hay dos grupos de trabajo que lo desarrollan: - -1. [W3C](https://es.wikipedia.org/wiki/World_Wide_Web_Consortium) -- la documentación se encuentra en . -2. [WhatWG](https://es.wikipedia.org/wiki/Web_Hypertext_Application_Technology_Working_Group), publicado en . - -Como es de esperar, los dos grupos no siempre están de acuerdo, así que es como si tuviéramos dos conjuntos de estándares. Pero son muy similares y eventualmente las cosas se fusionan. La documentación que puede encontrar en los recursos dados es muy similar, con aproximadamente un 99% de coincidencia. Hay diferencias muy pequeñas que probablemente no notarás. - -Personalmente, encuentro más agradable de usar. - -En el pasado lejano, no existía ninguna norma en absoluto: cada navegador lo implementaba como quería. Diferentes navegadores tenían diferentes métodos y propiedades para la misma cosa, y los desarrolladores tenían que escribir un código diferente para cada uno de ellos. Tiempos oscuros, desordenados. - -Incluso ahora, podemos encontrarnos con código antiguo que usa propiedades específicas del navegador y soluciona las incompatibilidades. Pero, en este tutorial usaremos cosas modernas: no hay necesidad de aprender cosas antiguas hasta que realmente lo necesites (es muy probable que no lo hagas). - -Luego apareció el estándar DOM, en un intento de llevar a todos a un acuerdo. La primera versión fue "DOM Level 1", luego fue extendida por DOM Level 2, luego DOM Level 3, y ahora llegó a DOM Level 4. La gente del grupo WhatWG se cansó de los números de versión y lo están llamando simplemente "DOM", sin un numero. Así que haremos lo mismo. +Aquí usamos `document.body.style`, pero hay muchos, muchos más. Las propiedades y métodos se describen en la especificación: [DOM Living Standard](https://dom.spec.whatwg.org). ```smart header="DOM no es solo para navegadores" -La especificación DOM explica la estructura de un documento y proporciona objetos para manipularlo. Hay instrumentos que no son del navegador que también lo utilizan. +La especificación DOM explica la estructura de un documento y proporciona objetos para manipularlo. Hay instrumentos que no son del navegador que también usan DOM. -Por ejemplo, las herramientas del lado del servidor que descargan páginas HTML y las procesan utilizan el DOM. Sin embargo, pueden soportar solo una parte de la especificación. +Por ejemplo, los scripts del lado del servidor que descargan páginas HTML y las procesan, también pueden usar DOM. Sin embargo, pueden admitir solo una parte de la especificación. ``` ```smart header="CSSOM para los estilos" -Las reglas CSS y las hojas de estilo no están estructuradas como HTML. Hay una especificación [CSSOM](https://www.w3.org/TR/cssom-1/) separada, que explica cómo se representan como objetos, y cómo leerlos y escribirlos. +También hay una especificación separada, [CSS Object Model (CSSOM)] (https://www.w3.org/TR/cssom-1/) para las reglas y hojas de estilo CSS, que explica cómo se representan como objetos y cómo leerlos y escribirlos. -CSSOM se usa junto con DOM cuando modificamos las reglas de estilo para el documento. En la práctica, sin embargo, rara vez se requiere CSSOM, porque generalmente las reglas de CSS son estáticas. Rara vez necesitamos agregar/eliminar reglas CSS desde JavaScript, por lo que no lo cubriremos ahora. +CSSOM se usa junto con DOM cuando modificamos las reglas de estilo para el documento. Sin embargo, en la práctica, rara vez se requiere CSSOM, porque rara vez necesitamos modificar las reglas CSS de JavaScript (generalmente solo agregamos / eliminamos clases CSS, no modificamos sus reglas CSS), pero eso también es posible. ``` ## BOM (parte de la especificación HTML) diff --git a/2-ui/1-document/07-modifying-document/article.md b/2-ui/1-document/07-modifying-document/article.md index c4796a1d4..6dfb2fe22 100644 --- a/2-ui/1-document/07-modifying-document/article.md +++ b/2-ui/1-document/07-modifying-document/article.md @@ -28,7 +28,7 @@ Here's how it will look: */!* ``` -That was an HTML example. Now let's create the same `div` with JavaScript (assuming that the styles are in the HTML or an external CSS file). +That was the HTML example. Now let's create the same `div` with JavaScript (assuming that the styles are in the HTML/CSS already). ## Creating an element @@ -48,21 +48,26 @@ To create DOM nodes, there are two methods: let textNode = document.createTextNode('Here I am'); ``` +Most of the time we need to create element nodes, such as the `div` for the message. + ### Creating the message -In our case the message is a `div` with `alert` class and the HTML in it: +Creating the message div takes 3 steps: ```js +// 1. Create
element let div = document.createElement('div'); +// 2. Set its class to "alert" div.className = "alert"; +// Fill it with the content div.innerHTML = "Hi there! You've read an important message."; ``` -We created the element, but as of now it's only in a variable. We can't see the element on the page, as it's not yet a part of the document. +We've created the element. But as of now it's only in a variable named `div`, not in the page yet. So we can't see it. ## Insertion methods -To make the `div` show up, we need to insert it somewhere into `document`. For instance, in `document.body`. +To make the `div` show up, we need to insert it somewhere into `document`. For instance, into `` element, referenced by `document.body`. There's a special method `append` for that: `document.body.append(div)`. @@ -90,7 +95,9 @@ Here's the full code: ``` -This set of methods provides more ways to insert: +Here we called `append` on `document.body`, but we can call `append` method on any other element, to put another element into it. For instance, we can append something to `
` by calling `div.append(anotherElement)`. + +Here are more insertion methods, they specify different places where to insert: - `node.append(...nodes or strings)` -- append nodes or strings at the end of `node`, - `node.prepend(...nodes or strings)` -- insert nodes or strings at the beginning of `node`, @@ -98,6 +105,10 @@ This set of methods provides more ways to insert: - `node.after(...nodes or strings)` –- insert nodes or strings after `node`, - `node.replaceWith(...nodes or strings)` –- replaces `node` with the given nodes or strings. +Arguments of these methods are an arbitrary list of DOM nodes to insert, or text strings (that become text nodes automatically). + +Let's see them in action. + Here's an example of using these methods to add items to a list and the text before/after it: ```html autorun @@ -121,7 +132,7 @@ Here's an example of using these methods to add items to a list and the text bef ``` -Here's a visual picture what methods do: +Here's a visual picture of what the methods do: ![](before-prepend-append-after.svg) @@ -139,7 +150,7 @@ before after ``` -These methods can insert multiple lists of nodes and text pieces in a single call. +As said, these methods can insert multiple nodes and text pieces in a single call. For instance, here a string and an element are inserted: @@ -150,7 +161,7 @@ For instance, here a string and an element are inserted: ``` -All text is inserted *as text*. +Please note: the text is inserted "as text", not "as HTML", with proper escaping of characters such as `<`, `>`. So the final HTML is: @@ -166,7 +177,7 @@ In other words, strings are inserted in a safe way, like `elem.textContent` does So, these methods can only be used to insert DOM nodes or text pieces. -But what if we want to insert HTML "as html", with all tags and stuff working, like `elem.innerHTML`? +But what if we'd like to insert an HTML string "as html", with all tags and stuff working, in the same manner as `elem.innerHTML` does it? ## insertAdjacentHTML/Text/Element diff --git a/2-ui/1-document/11-coordinates/article.md b/2-ui/1-document/11-coordinates/article.md index b4b577cd0..fb55edf57 100644 --- a/2-ui/1-document/11-coordinates/article.md +++ b/2-ui/1-document/11-coordinates/article.md @@ -216,6 +216,8 @@ function getCoords(elem) { return { top: box.top + window.pageYOffset, + right: box.right + window.pageXOffset, + bottom: box.bottom + window.pageYOffset, left: box.left + window.pageXOffset }; } diff --git a/2-ui/3-event-details/6-pointer-events/article.md b/2-ui/3-event-details/6-pointer-events/article.md index 734b76bd8..658465d39 100644 --- a/2-ui/3-event-details/6-pointer-events/article.md +++ b/2-ui/3-event-details/6-pointer-events/article.md @@ -177,7 +177,7 @@ But we continue tracking track `pointermove` events and move the thumb until `po [Previously](info:mouse-drag-and-drop), to handle `pointermove` events that happen outside of the slider, we listened for `pointermove` events on the whole `document`. -Pointer capturing provides an alternative solution: we can call `thumb.setPointerCapture(event.pointerId)` in `pointerdown` handler, and then all future pointer events until `pointerup` will be retarteted to `thumb`. +Pointer capturing provides an alternative solution: we can call `thumb.setPointerCapture(event.pointerId)` in `pointerdown` handler, and then all future pointer events until `pointerup` will be retargeted to `thumb`. That is: events handlers on `thumb` will be called, and `event.target` will always be `thumb`, even if the user moves their pointer around the whole document. So we can listen at `thumb` for `pointermove`, no matter where it happens. diff --git a/6-data-storage/03-indexeddb/article.md b/6-data-storage/03-indexeddb/article.md index 7b93fd12b..3f0cf0e5a 100644 --- a/6-data-storage/03-indexeddb/article.md +++ b/6-data-storage/03-indexeddb/article.md @@ -5,7 +5,7 @@ libs: # IndexedDB -IndexedDB is a database, that is built into browser, much more powerful than `localStorage`. +IndexedDB is a database that is built into browser, much more powerful than `localStorage`. - Stores almost any kind of values by keys, multiple key types. - Supports transactions for reliability. @@ -75,10 +75,10 @@ We can open it with version `2` and perform the upgrade like this: ```js let openRequest = indexedDB.open("store", *!*2*/!*); -openRequest.onupgradeneeded = function() { +openRequest.onupgradeneeded = function(event) { // the existing database version is less than 2 (or it doesn't exist) let db = openRequest.result; - switch(db.version) { // existing db version + switch(event.oldVersion) { // existing db version case 0: // version 0 means that the client had no database // perform initialization diff --git a/9-regular-expressions/03-regexp-unicode/article.md b/9-regular-expressions/03-regexp-unicode/article.md index 43a1e5483..444e79be1 100644 --- a/9-regular-expressions/03-regexp-unicode/article.md +++ b/9-regular-expressions/03-regexp-unicode/article.md @@ -96,7 +96,6 @@ Estas son las principales categorías y subcategorías de caracteres: - private use (uso privado) `Co`, - surrogate (sustitudo) `Cs`. - Entonces, por ejemplo si necesitamos letras en minúsculas, podemos escribir `pattern:\p{Ll}`, signos de puntuación: `pattern:\p{P}` y así sucesivamente. También hay otras categorías derivadas, como: diff --git a/9-regular-expressions/06-regexp-boundary/article.md b/9-regular-expressions/06-regexp-boundary/article.md index aad65877f..7c9f442fe 100644 --- a/9-regular-expressions/06-regexp-boundary/article.md +++ b/9-regular-expressions/06-regexp-boundary/article.md @@ -25,7 +25,7 @@ So, it matches the pattern `pattern:\bHello\b`, because: 1. At the beginning of the string matches the first test `pattern:\b`. 2. Then matches the word `pattern:Hello`. -3. Then the test `pattern:\b` matches again, as we're between `subject:o` and a space. +3. Then the test `pattern:\b` matches again, as we're between `subject:o` and a comma. The pattern `pattern:\bHello\b` would also match. But not `pattern:\bHell\b` (because there's no word boundary after `l`) and not `Java!\b` (because the exclamation sign is not a wordly character `pattern:\w`, so there's no word boundary after it).