diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..490051876 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: iliakan diff --git a/1-js/01-getting-started/1-intro/article.md b/1-js/01-getting-started/1-intro/article.md index 6d9b03eee..8c249da73 100644 --- a/1-js/01-getting-started/1-intro/article.md +++ b/1-js/01-getting-started/1-intro/article.md @@ -34,6 +34,12 @@ I nomi citati sopra possono essere utili da ricordare, poiché si possono trovar Il funzionamento di questi motori è complicato, ma i concetti alla base sono semplici. +<<<<<<< HEAD +======= +1. The engine (embedded if it's a browser) reads ("parses") the script. +2. Then it converts ("compiles") the script to machine code. +3. And then the machine code runs, pretty fast. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 1. I motori (integrati nei browser) leggono ("analizzano") lo script. 2. Successivamente convertono ("compilano") lo script nel linguaggio della macchina. @@ -44,7 +50,11 @@ Il motore ottimizza il codice ad ogni passaggio del processo, anche durante l'es ## Cosa può fare JavaScript a livello browser? +<<<<<<< HEAD JavaScript, al giorno d'oggi, è un linguaggio di programmazione "sicuro". Non consente alcun accesso di basso livello alla memoria o alla CPU. Questo perché è stato creato con lo scopo di funzionare nei browser, che non richiedono questi tipi di privilegi. +======= +Modern JavaScript is a "safe" programming language. It does not provide low-level access to memory or the CPU, because it was initially created for browsers which do not require it. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Le capacità di JavaScript dipendono molto dall'ambiente in cui lo si esegue. Ad esempio, [Node.js](https://wikipedia.org/wiki/Node.js) supporta funzioni che consentono a JavaScript di scrivere/leggere file, eseguire richieste web, etc. @@ -60,7 +70,11 @@ Ad esempio, è possibile: ## Cosa NON può fare JavaScript a livello browser? +<<<<<<< HEAD Per la sicurezza dell'utente, le possibilità di JavaScript nel browser sono limitate. L'intento è di prevenire che una pagina "maligna" tenti di accedere alle informazioni personali o di danneggiare i dati degli utenti. +======= +JavaScript's abilities in the browser are limited to protect the user's safety. The aim is to prevent an evil webpage from accessing private information or harming the user's data. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Esempi di queste restrizioni possono essere: @@ -68,6 +82,7 @@ Esempi di queste restrizioni possono essere: I moderni browser gli consentono di lavorare con i file, sempre con un accesso limitato e comunque solo se il comando proviene da utente, come il "dropping" di un file nella finestra del browser, o con la selezione tramite il tag ``. +<<<<<<< HEAD Ci sono anche funzionalità che consentono di interagire con la camera/microfono e altri dispositivi, ma in ogni caso richiedono il permesso esplicito dell'utente. Quindi una pagina con JavaScript abilitato non può attivare la web-cam di nascosto, osservare i nostri comportamenti e inviare informazioni alla [CIA](https://it.wikipedia.org/wiki/Central_Intelligence_Agency). - Pagine o schede diverse generalmente non sono a conoscenza dell'esistenza delle altre. In certi casi, tuttavia, può capitare; ad esempio quando una finestra ne apre un'altra tramite JavaScript. Ma anche in questo caso, il codice JavaScript non può accedere all'altra pagina se non appartiene allo stesso sito (stesso dominio, protocollo o porta). @@ -79,6 +94,19 @@ Esempi di queste restrizioni possono essere: ![](limitations.svg) Queste limitazioni non si pongono se JavaScript viene eseguito fuori dal browser, ad esempio in un server. I browser moderni permettono l'installazione di plugin ed estensioni che consentono di estendere vari permessi. +======= + There are ways to interact with the camera/microphone and other devices, but they require a user's explicit permission. So a JavaScript-enabled page may not sneakily enable a web-camera, observe the surroundings and send the information to the [NSA](https://en.wikipedia.org/wiki/National_Security_Agency). +- Different tabs/windows generally do not know about each other. Sometimes they do, for example when one window uses JavaScript to open the other one. But even in this case, JavaScript from one page may not access the other page if they come from different sites (from a different domain, protocol or port). + + This is called the "Same Origin Policy". To work around that, *both pages* must agree for data exchange and must contain special JavaScript code that handles it. We'll cover that in the tutorial. + + This limitation is, again, for the user's safety. A page from `http://anysite.com` which a user has opened must not be able to access another browser tab with the URL `http://gmail.com`, for example, and steal information from there. +- JavaScript can easily communicate over the net to the server where the current page came from. But its ability to receive data from other sites/domains is crippled. Though possible, it requires explicit agreement (expressed in HTTP headers) from the remote side. Once again, that's a safety limitation. + +![](limitations.svg) + +Such limitations do not exist if JavaScript is used outside of the browser, for example on a server. Modern browsers also allow plugins/extensions which may ask for extended permissions. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Cosa rende JavaScript unico? @@ -93,7 +121,11 @@ JavaScript è l'unica tecnologia in ambiente browser che combina queste tre cara Questo rende JavaScript unico. Ed è il motivo per cui è lo strumento più diffuso per creare interfacce web. +<<<<<<< HEAD Quando si ha in programma di imparare una nuova tecnologia, è fondamentale verificare le sue prospettive. Quindi diamo uno sguardo alle nuove tendenze che includono nuovi linguaggi e tecnologie. +======= +That said, JavaScript can be used to create servers, mobile applications, etc. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Linguaggi "oltre" JavaScript @@ -101,12 +133,17 @@ La sintassi di JavaScript non soddisfa le necessità di tutti. Alcune persone ne Questo è prevedibile, poiché i progetti e i requisiti sono diversi da persona a persona. +<<<<<<< HEAD Recentemente, per questo motivo, sono nati molti nuovi linguaggi che vengono *convertiti* in JavaScript prima di essere eseguiti nel browser. +======= +So, recently a plethora of new languages appeared, which are *transpiled* (converted) to JavaScript before they run in the browser. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Gli strumenti moderni rendono la conversione molto veloce e pulita, consentendo agli sviluppatori di programmare in un altro linguaggio e di auto-convertirlo *under the hood*. Esempi di alcuni linguaggi: +<<<<<<< HEAD - [CoffeeScript](http://coffeescript.org/) è un linguaggio che introduce una sintassi semplificata che consente di scrivere codice più leggibile. Amato dagli sviluppatori provenienti da Ruby. - [TypeScript](http://www.typescriptlang.org/) si occupa di aggiungere la "tipizzazione", per semplificare lo sviluppo e supportare sistemi più complessi. E' stato sviluppato da Microsoft. - [Flow](http://flow.org/) anche'esso aggiunge la tipizzazione dei dati, ma in un modo differente. Sviluppato da Facebook. @@ -115,6 +152,16 @@ Esempi di alcuni linguaggi: - [Kotlin](https://kotlinlang.org/docs/reference/js-overview.html) è un moderno, conciso e sicuro linguaggio di programmazione mirato ai browsers o a Node. Ce ne sono molti altri. Ovviamente, per comprendere cosa stiamo facendo, se utilizziamo uno di questi linguaggi dovremmo altresì conoscere JavaScript. +======= +- [CoffeeScript](https://coffeescript.org/) is "syntactic sugar" for JavaScript. It introduces shorter syntax, allowing us to write clearer and more precise code. Usually, Ruby devs like it. +- [TypeScript](https://www.typescriptlang.org/) is concentrated on adding "strict data typing" to simplify the development and support of complex systems. It is developed by Microsoft. +- [Flow](https://flow.org/) also adds data typing, but in a different way. Developed by Facebook. +- [Dart](https://www.dartlang.org/) is a standalone language that has its own engine that runs in non-browser environments (like mobile apps), but also can be transpiled to JavaScript. Developed by Google. +- [Brython](https://brython.info/) is a Python transpiler to JavaScript that enables the writing of applications in pure Python without JavaScript. +- [Kotlin](https://kotlinlang.org/docs/reference/js-overview.html) is a modern, concise and safe programming language that can target the browser or Node. + +There are more. Of course, even if we use one of these transpiled languages, we should also know JavaScript to really understand what we're doing. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Riepilogo diff --git a/1-js/01-getting-started/2-manuals-specifications/article.md b/1-js/01-getting-started/2-manuals-specifications/article.md index bb962523a..a4d4124e7 100644 --- a/1-js/01-getting-started/2-manuals-specifications/article.md +++ b/1-js/01-getting-started/2-manuals-specifications/article.md @@ -1,7 +1,11 @@ # Manuali e Specifiche +<<<<<<< HEAD Questo libro è un *tutorial*. L'obiettivo è quello di aiutarti ad apprender il linguaggio gradualmente. Una volta che avrai familiarizzato con le basi avrai bisogno di ulteriori risorse. +======= +This book is a *tutorial*. It aims to help you gradually learn the language. But once you're familiar with the basics, you'll need other resources. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Specifiche @@ -9,7 +13,11 @@ Questo libro è un *tutorial*. L'obiettivo è quello di aiutarti ad apprender il Iniziare a studiare dalla specifica può risultare difficile. Se avete bisogno di una fonte affidabile e formale riguardante i dettagli del linguaggio, la specifica è il posto in cui cercare. Ma non è una risorsa comoda da consultare per i problemi di tutti i giorni. +<<<<<<< HEAD Ogni anno viene rilasciata una nuova specifica. Di queste pubblicazioni, è possibile trovare l'ultima bozza a . +======= +A new specification version is released every year. Between these releases, the latest specification draft is at . +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Per leggere delle più recenti caratteristiche, incluse quelle considerate "quasi standard" (definite "stage 3"), potete consultare . @@ -19,16 +27,29 @@ Inoltre, se state sviluppando in ambiente browser, ci sono ulteriori specifiche - **MDN (Mozilla) JavaScript Reference** è il manuale principale, corredato di spiegazioni teoriche, esempi ed altre informazioni utili. E' ottimo per avere informazioni dettagliate riguardo le funzioni e altre caratteristiche del linguaggio. +<<<<<<< HEAD Può essere consultato a . Tuttavia, spesso è meglio fare una ricerca su internet. E' sufficiente cercare "MDN", seguito dal termine da ricercare, e.g. per ricercare la funzione `parseInt`, oppure frasi come "RegExp MSDN" o "RegExp MSDN jscript". +======= + You can find it at . + +Although, it's often best to use an internet search instead. Just use "MDN [term]" in the query, e.g. to search for the `parseInt` function. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Può essere consultato al link . - **MSDN** – Manuale Microsoft con molte informazioni, tra cui su JavaScript (a cui viene fatto riferimento con il termine JScript). Se si ha bisogno di ottenere qualche informazione specifica per Internet Explorer, meglio consultare la guida: . +<<<<<<< HEAD + +======= +- - per-feature tables of support, e.g. to see which engines support modern cryptography functions: . +- - a table with language features and engines that support those or don't support. +All these resources are useful in real-life development, as they contain valuable information about language details, their support, etc. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Tabelle di compatibilità diff --git a/1-js/01-getting-started/3-code-editors/article.md b/1-js/01-getting-started/3-code-editors/article.md index 820d767cf..59bc6b3e0 100644 --- a/1-js/01-getting-started/3-code-editors/article.md +++ b/1-js/01-getting-started/3-code-editors/article.md @@ -12,8 +12,13 @@ Un IDE carica il progetto (possono essere molti file), consente la navigazione t Se non hai ancora considerato di scegliere un IDE, dai un'occhiata a queste alternative: +<<<<<<< HEAD - [Visual Studio Code](https://code.visualstudio.com/) (*cross-platform*, gratutito). - [WebStorm](http://www.jetbrains.com/webstorm/) (*cross-platform*, a pagamento). +======= +- [Visual Studio Code](https://code.visualstudio.com/) (cross-platform, free). +- [WebStorm](https://www.jetbrains.com/webstorm/) (cross-platform, paid). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Per Windows, c'è anche l'editor "Visual Studio", da non confondere con "Visual Studio Code". "Visual Studio" è un potente editor (a pagamento) disponibile solo per Windows, ottimo per le piattaforme .NET. E' disponibile anche una versione gratuita: ([Visual Studio Community](https://www.visualstudio.com/vs/community/). @@ -29,6 +34,7 @@ La principale differenza tra gli editor semplici e un IDE è che quest'ultimo la In pratica, tuttavia, gli editor semplici possono avere molti plugin, tra cui la sintassi a livello directory e l'autocompletamento, quindi non ci sono delle differenze ben definite tra un editor semplice e un IDE. +<<<<<<< HEAD Meritano attenzione le seguenti opzioni: - [Atom](https://atom.io/) (*cross-platform*, gratuito). @@ -36,6 +42,13 @@ Meritano attenzione le seguenti opzioni: - [Sublime Text](http://www.sublimetext.com) (*cross-platform*, con prova gratuita). - [Notepad++](https://notepad-plus-plus.org/) (Windows, gratuito). - [Vim](http://www.vim.org/) e [Emacs](https://www.gnu.org/software/emacs/) sono particolarmente carini se si sanno utilizzare. +======= +There are many options, for instance: + +- [Sublime Text](https://www.sublimetext.com/) (cross-platform, shareware). +- [Notepad++](https://notepad-plus-plus.org/) (Windows, free). +- [Vim](https://www.vim.org/) and [Emacs](https://www.gnu.org/software/emacs/) are also cool if you know how to use them. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Non intestarditevi @@ -43,4 +56,13 @@ Gli editor elencanti sopra sono quelli che io e i miei amici, che considero buon Ci sono altri grandi editor nel nostro grande mondo. Scegli quello che più ti si addice. +<<<<<<< HEAD La scelta di un editor, come pure di altri strumenti, è individuale e dipende dai progetti, dalle abitudini e preferenze personali. +======= +The choice of an editor, like any other tool, is individual and depends on your projects, habits, and personal preferences. + +The author's personal opinion: + +- I'd use [Visual Studio Code](https://code.visualstudio.com/) if I develop mostly frontend. +- Otherwise, if it's mostly another language/platform and partially frontend, then consider other editors, such as XCode (Mac), Visual Studio (Windows) or Jetbrains family (Webstorm, PHPStorm, RubyMine etc, depending on the language). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/1-js/02-first-steps/04-variables/3-uppercast-constant/task.md b/1-js/02-first-steps/04-variables/3-uppercast-constant/task.md index 0a03dfaa4..bca66d0f7 100644 --- a/1-js/02-first-steps/04-variables/3-uppercast-constant/task.md +++ b/1-js/02-first-steps/04-variables/3-uppercast-constant/task.md @@ -12,13 +12,18 @@ const birthday = '18.04.1982'; const age = someCode(birthday); ``` +<<<<<<< HEAD Abbiamo una costante `birthday` che indica una data e `age` che viene calcolata da `birthday` tramite un algoritmo (non viene fornito per brevità, e perchè non è importante per descrivere l'argomento). +======= +Here we have a constant `birthday` for the date, and also the `age` constant. + +The `age` is calculated from `birthday` using `someCode()`, which means a function call that we didn't explain yet (we will soon!), but the details don't matter here, the point is that `age` is calculated somehow based on the `birthday`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Sarebbe giusto utilizzare lettere maiuscole per `birthday`? E per `age`? O anche per entrambe? ```js -const BIRTHDAY = '18.04.1982'; // make uppercase? +const BIRTHDAY = '18.04.1982'; // make birthday uppercase? -const AGE = someCode(BIRTHDAY); // make uppercase? +const AGE = someCode(BIRTHDAY); // make age uppercase? ``` - diff --git a/1-js/02-first-steps/04-variables/article.md b/1-js/02-first-steps/04-variables/article.md index a2574d9f2..19f6414bf 100644 --- a/1-js/02-first-steps/04-variables/article.md +++ b/1-js/02-first-steps/04-variables/article.md @@ -63,7 +63,12 @@ let age = 25; let message = 'Hello'; ``` +<<<<<<< HEAD Alcune persone scrivono variabili multiple in questo modo: +======= +Some people also define multiple variables in this multiline style: + +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js no-beautify let user = 'John', age = 25, @@ -87,16 +92,26 @@ Nei vecchi script potresti trovare: `var` piuttosto che `let`: *!*var*/!* message = 'Hello'; ``` +<<<<<<< HEAD La parola chiave `var` è *quasi* la stessa cosa di `let`. Dichiara comunque una variabile, ma in un maniera leggermente diversa, "vecchio stile". Ci sono delle sottili differenze tra `let` e `var`, ma per ora non hanno importanza. Le copriremo in dettaglio più avanti, nel capitolo . +======= +The `var` keyword is *almost* the same as `let`. It also declares a variable but in a slightly different, "old-school" way. + +There are subtle differences between `let` and `var`, but they do not matter to us yet. We'll cover them in detail in the chapter . +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```` ## Un'analogia con il mondo reale Possiamo comprendere meglio il concetto di "variabile" se la immaginiamo come una scatola per dati, con appiccicata un'etichetta univoca. +<<<<<<< HEAD Per esempio, la variabile `message` può essere immaginata come una scatola con etichetta `"message"` con il valore `"Hello!"` al suo interno: +======= +For instance, the variable `message` can be imagined as a box labelled `"message"` with the value `"Hello!"` in it: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ![](variable.svg) @@ -104,6 +119,11 @@ Possiamo inserire qualsiasi valore all'interno della scatola. Possiamo anche cambiarlo. Il valore può cambiare tutte le volte che ne abbiamo bisogno: +<<<<<<< HEAD +======= +We can also change it as many times as we want: + +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let message; @@ -148,12 +168,21 @@ let message = "That"; // SyntaxError: 'message' has already been declared Quindi, dovremmo dichiarare una variabile una volta sola, e farne riferimento senza la parola chiave `let`. ```` +<<<<<<< HEAD ```smart header="Linguaggi funzionali" Può essere interessante sapere che esistono anche linguaggi di programmazione [funzionale](https://en.wikipedia.org/wiki/Functional_programming) che vietano di cambiare il valore di una variabile. Per esempio, [Scala](http://www.scala-lang.org/) o [Erlang](http://www.erlang.org/). +======= +```smart header="Functional languages" +It's interesting to note that there exist so-called [pure functional](https://en.wikipedia.org/wiki/Purely_functional_programming) programming languages, such as [Haskell](https://en.wikipedia.org/wiki/Haskell), that forbid changing variable values. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 In questo tipo di linguaggi, una volta che il valore viene memorizzato "dentro la scatola", ci rimane per sempre. Se abbiamo bisogno di memorizzare qualcos altro, il linguaggio ci forza a creare una nuova scatola (dichiarare una nuova variabile). Non possiamo quindi riutilizzare quelle vecchie. +<<<<<<< HEAD Anche se potrebbero sembrare un po' strano a prima vista, questi linguaggi sono veramente capaci di sviluppare grandi cose. Inoltre, ci sono certe situazioni come calcoli paralleli in cui questi limiti portano dei benefici. Studiare un linguaggio di questo tipo (anche se non abbiamo intenzione di utilizzarlo a breve) è consigliato per allargare le proprie conoscenze. +======= +Though it may seem a little odd at first sight, these languages are quite capable of serious development. More than that, there are areas like parallel computations where this limitation confers certain benefits. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` ## Nomi delle variabili [#variable-naming] @@ -191,19 +220,32 @@ let 1a; // non può cominciare con una stringa let my-name; // '-' non è consentito nei nomi ``` +<<<<<<< HEAD ```smart header="La questione delle lettere" Le variabili `apple` ed `AppLE` sono distinte. ``` ````smart header="Le lettere non latine sono permesse, ma sono sconsigliate" E' possibile utilizzare qualsiasi alfabeto, compreso quello cirillico o addirittura i geroglifici: +======= +```smart header="Case matters" +Variables named `apple` and `APPLE` are two different variables. +``` + +````smart header="Non-Latin letters are allowed, but not recommended" +It is possible to use any language, including Cyrillic letters, Chinese logograms and so on, like this: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js let имя = '...'; let 我 = '...'; ``` +<<<<<<< HEAD Tecnicamente, non ci sono errori, questo tipo di nomi sono permessi, ma la tradizione internazionale è di utilizzare l'alfabeto inglese per il nome delle variabili. Anche se stiamo scrivendo un piccolo script, questo potrebbe infatti avere una lunga vita. Persone di altre nazionalità potrebbero aver bisogno di leggerlo. +======= +Technically, there is no error here. Such names are allowed, but there is an international convention to use English in variable names. Even if we're writing a small script, it may have a long life ahead. People from other countries may need to read it sometime. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```` ````warn header="Nomi riservati" @@ -258,12 +300,20 @@ const myBirthday = '18.04.1982'; myBirthday = '01.01.2001'; // errore, non è possibile riassegnare la costante! ``` +<<<<<<< HEAD Quando il programmatore è sicuro che il valore della variabile non cambierà mai, può utilizzare `const` per soddisfare questa esigenza, rendendolo cosi esplicito. +======= +When a programmer is sure that a variable will never change, they can declare it with `const` to guarantee and communicate that fact to everyone. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ### Le costanti maiuscole +<<<<<<< HEAD Una pratica molto diffusa è di utilizzare le variabili costanti come alias di valori difficili da ricordare, e che sono noti prima dell'esecuzione. +======= +There is a widespread practice to use constants as aliases for difficult-to-remember values that are known before execution. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Questo tipo di costanti vengono identificate con lettere maiuscole e underscore. @@ -288,16 +338,29 @@ Benefici: Quando dovremmo utilizzare lettere maiuscole per una costante, e quando invece trattarle come normali variabili? Facciamo un pò di chiarezza. +<<<<<<< HEAD Essere una "costante" significa che il valore non potrà mai cambiare. Ci sono costanti che sono note prima dell'esecuzione (come la codifica esadecimale del colore rosso), e ci sono quelle che vengono *calcolate* durante l'esecuzione, ma non cambieranno più dopo che gli sarà stato assegnato un valore. Per esempio: +======= +Being a "constant" just means that a variable's value never changes. But some constants are known before execution (like a hexadecimal value for red) and some constants are *calculated* in run-time, during the execution, but do not change after their initial assignment. + +For instance: + +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js const pageLoadTime = /* tempo necessario da una pagina web per caricare */; ``` +<<<<<<< HEAD Il valore di `pageLoadTime` non è noto prima del caricamento della pagina, quindi viene trattato come una normale variabile. Ma rimane comunque una costante, perché non potrà più cambiare dopo che gli sarà stato assegnato un valore. In altre parole, i nomi delle costanti in maiuscolo vengono utilizzati con variabili dal valore noto prima dell'esecuzione. +======= +The value of `pageLoadTime` is not known before the page load, so it's named normally. But it's still a constant because it doesn't change after the assignment. + +In other words, capital-named constants are only used as aliases for "hard-coded" values. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Dare i giusti nomi alle cose @@ -305,19 +368,32 @@ Parlando di variabili, c'è un'altra cosa estremamente importante. Il nome di una variabile dovrebbe sempre essere pulito, ovvio e descrittivo del suo contenuto. +<<<<<<< HEAD Dare i giusti nomi alle variabili è una delle abilità più importanti (e difficili) nella programmazione. Una rapida occhiata ai nomi delle variabili può rivelare se il codice è stato scritto da un principiante o da uno sviluppatore esperto. In un progetto reale, la maggior parte del tempo lo si perde a modificare ed estendere del codice già esistente, piuttosto che riscriverne uno nuovo. E quando ritorneremo sul codice, dopo aver fatto qualcos'altro, sarà molto pù facile trovare informazioni se sono ben descritte. In altre parole, quando le variabili utilizzano dei nomi efficaci. +======= +Variable naming is one of the most important and complex skills in programming. A glance at variable names can reveal which code was written by a beginner versus an experienced developer. + +In a real project, most of the time is spent modifying and extending an existing code base rather than writing something completely separate from scratch. When we return to some code after doing something else for a while, it's much easier to find information that is well-labelled. Or, in other words, when the variables have good names. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Quindi è utile spendere del tempo a pensare il giusto nome per una variabile, prima di dichiararla. Questo approccio vi ripagherà. Alcune regole da seguire: +<<<<<<< HEAD - Utilizzare nomi leggibili da persone, come `userName` o `shoppingCart`. - Evitate abbreviazioni o nomi brevi come `a`, `b`, `c`, senza che abbiano veramente senso. - Rendete il nome il più descrittivo e preciso possibile. Esempi di pessimi nomi sono `data` e `value`. Questo tipo di nomi non dicono niente. Si possono utilizzare eccezionalmente se il contesto rende esplicito il significato. - Definire delle regole personali o con il team. Se il visitatore del sito viene chiamato "user" allora dovremmo chiamare la relativa variabile come `currentUser` o `newUser`, non `currentVisitor` o `newManInTown`. +======= +- Use human-readable names like `userName` or `shoppingCart`. +- Stay away from abbreviations or short names like `a`, `b`, and `c`, unless you know what you're doing. +- Make names maximally descriptive and concise. Examples of bad names are `data` and `value`. Such names say nothing. It's only okay to use them if the context of the code makes it exceptionally obvious which data or value the variable is referencing. +- Agree on terms within your team and in your mind. If a site visitor is called a "user" then we should name related variables `currentUser` or `newUser` instead of `currentVisitor` or `newManInTown`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Sembra facile? Infatti lo è, ma trovare dei buoni nomi che siano precisi e descrittivi nella pratica non è sempre cosi semplice. diff --git a/1-js/02-first-steps/05-types/article.md b/1-js/02-first-steps/05-types/article.md index bd0fc7dfa..a680a06a3 100644 --- a/1-js/02-first-steps/05-types/article.md +++ b/1-js/02-first-steps/05-types/article.md @@ -46,13 +46,23 @@ Oltre a i normali valori numeri, esistono anche i "valori numerici speciali" che alert( "not a number" / 2 ); // NaN, è una divisione errata ``` +<<<<<<< HEAD `NaN` è "fisso". Qualsiasi operazione su `NaN` restituirà `NaN`: +======= + `NaN` is sticky. Any further mathematical operation on `NaN` returns `NaN`: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run - alert( "not a number" / 2 + 5 ); // NaN + alert( NaN + 1 ); // NaN + alert( 3 * NaN ); // NaN + alert( "not a number" / 2 - 1 ); // NaN ``` +<<<<<<< HEAD Quindi, se è presente un `NaN` da qualche parte nell'operazione matematica, questo si propagherà fino al risultato. +======= + So, if there's a `NaN` somewhere in a mathematical expression, it propagates to the whole result (there's only one exception to that: `NaN ** 0` is `1`). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```smart header="Le operazioni matematiche sono sicure" In JavaScript le operazioni matematiche sono sicure. Possiamo fare qualsiasi cosa: dividere per zero, trattare stringhe non numeriche come numeri, etc. @@ -66,9 +76,26 @@ Vedremo di più su come lavorare con i numeri nel capitolo . ## BigInt [#bigint-type] +<<<<<<< HEAD In JavaScript, il tipo "number" non può rappresentare valori interni più grandi di (253-1) (che equivale a `9007199254740991`), o minori di -(253-1). Questa è una limitazione tecnica dovuta alla loro rappresentazione interna. Per la maggior parte degli scopi, questo intervallo è sufficiente, ma in alcuni casi potremmo aver bisogno di numeri molto grandi, ad esempio per la crittografia o timestamp con precisione al microsecondo. +======= +In JavaScript, the "number" type cannot safely represent integer values larger than (253-1) (that's `9007199254740991`), or less than -(253-1) for negatives. + +To be really precise, the "number" type can store larger integers (up to 1.7976931348623157 * 10308), but outside of the safe integer range ±(253-1) there'll be a precision error, because not all digits fit into the fixed 64-bit storage. So an "approximate" value may be stored. + +For example, these two numbers (right above the safe range) are the same: + +```js +console.log(9007199254740991 + 1); // 9007199254740992 +console.log(9007199254740991 + 2); // 9007199254740992 +``` + +So to say, all odd integers greater than (253-1) can't be stored at all in the "number" type. + +For most purposes ±(253-1) range is quite enough, but sometimes we need the entire range of really big integers, e.g. for cryptography or microsecond-precision timestamps. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Il tipo `BigInt` è stato aggiunto di recente al linguaggio, e consente di rappresentare numeri interi di lunghezza arbitraria. @@ -81,6 +108,7 @@ const bigInt = 1234567890123456789012345678901234567890n; Poiché i `BigInt` sono utilizzati raramente, non li analizzeremo in questo articolo, ma li vedremo più in dettaglio nel capitolo dedicato . +<<<<<<< HEAD ```smart header="Problemi di compatibilità" Attualmente, `BigInt` sono supportati da Firefox/Chrome/Edge/Safari, ma non da IE. @@ -88,6 +116,8 @@ Attualmente, `BigInt` sono supportati da Firefox/Chrome/Edge/Safari, ma non da I Potete sempre verificare [la tabella di compatibilità di *MDN* BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility) per sapere quali versioni dei browser li supportano. +======= +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## String Una stringa in JavaScript deve essere tra apici. @@ -211,7 +241,11 @@ Il tipo `symbol` viene utilizzato per creare identificatori unici per gli oggett L'operatore `typeof` ritorna il tipo dell'argomento. E' utile quando vogliamo lavorare con valori di tipi differenti, o per eseguire controlli rapidi. +<<<<<<< HEAD Sono supportate due sintassi: +======= +The `typeof` operator returns the type of the operand. It's useful when we want to process values of different types differently or just want to do a quick check. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 1. Come operatore: `typeof x`. 2. Come funzione: `typeof(x)`. @@ -271,4 +305,27 @@ L'operatore `typeof` ci consente di vedere quale tipo è memorizzato nella varia - Ritorna una stringa con il nome del tipo, come `"string"`. - Il valore `null` ritorna `"object"` -- è un errore del linguaggio, infatti non è un oggetto. +<<<<<<< HEAD Nel prossimo capitolo ci concentreremo nei tipi primitivi e quando avremo preso familiarità, passeremo agli oggetti. +======= +There are 8 basic data types in JavaScript. + +- Seven primitive data types: + - `number` for numbers of any kind: integer or floating-point, integers are limited by ±(253-1). + - `bigint` for integer numbers of arbitrary length. + - `string` for strings. A string may have zero or more characters, there's no separate single-character type. + - `boolean` for `true`/`false`. + - `null` for unknown values -- a standalone type that has a single value `null`. + - `undefined` for unassigned values -- a standalone type that has a single value `undefined`. + - `symbol` for unique identifiers. +- And one non-primitive data type: + - `object` for more complex data structures. + +The `typeof` operator allows us to see which type is stored in a variable. + +- Usually used as `typeof x`, but `typeof(x)` is also possible. +- Returns a string with the name of the type, like `"string"`. +- For `null` returns `"object"` -- this is an error in the language, it's not actually an object. + +In the next chapters, we'll concentrate on primitive values and once we're familiar with them, we'll move on to objects. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/1-js/02-first-steps/07-type-conversions/article.md b/1-js/02-first-steps/07-type-conversions/article.md index df98466c0..e5ffbc3ab 100644 --- a/1-js/02-first-steps/07-type-conversions/article.md +++ b/1-js/02-first-steps/07-type-conversions/article.md @@ -6,8 +6,15 @@ Ad esempio, `alert` converte automaticamente un valore qualsiasi in una stringa, Ci sono invece casi in cui è necessario convertire esplicitamente i valori per poter evitare errori. +<<<<<<< HEAD ```smart header="Non parliamo ancora di oggetti" In questo capitolo non parleremo ancora di oggetti ma ci dedicheremo ai tipi primitivi. Approfondiremo gli oggetti e la loro conversione dopo averli studiati, nel capitolo . +======= +```smart header="Not talking about objects yet" +In this chapter, we won't cover objects. For now, we'll just be talking about primitives. + +Later, after we learn about objects, in the chapter we'll see how objects fit in. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` ## Conversione di stringhe @@ -32,7 +39,11 @@ La conversione in stringa è quella più semplice. Il valore `false` diventa la ## Conversione numerica +<<<<<<< HEAD La conversione a `Number` viene applicata automaticamente nelle funzioni ed espressioni matematiche. +======= +Numeric conversion in mathematical functions and expressions happens automatically. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio, quando la divisione `/` viene applicata ad un tipo non numerico: @@ -67,8 +78,13 @@ Le regole di conversione numerica: |-------|-------------| |`undefined`|`NaN`| |`null`|`0`| +<<<<<<< HEAD |true e false | `1` e `0` | | `string` | Gli spazi bianchi all'inizio e alla fine vengono rimossi. Se la stringa rimanente è vuota, il risultato sarà `0`. Altrimenti, il numero viene "letto" dalla stringa. Un errore restituirà `NaN`. | +======= +|true and false | `1` and `0` | +| `string` | Whitespaces (includes spaces, tabs `\t`, newlines `\n` etc.) from the start and end are removed. If the remaining string is empty, the result is `0`. Otherwise, the number is "read" from the string. An error gives `NaN`. | +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Esempi: @@ -140,7 +156,11 @@ La conversione segue le seguenti regole: |`undefined`|`NaN`| |`null`|`0`| |true / false | `1 / 0` | +<<<<<<< HEAD | `string` | La stringa viene letta per "com'è", gli spazi bianchi agli estremi vengono ignorati. Una stringa vuota diventa `0`. Un errore restituisce `NaN`. | +======= +| `string` | The string is read "as is", whitespaces (includes spaces, tabs `\t`, newlines `\n` etc.) from both sides are ignored. An empty string becomes `0`. An error gives `NaN`. | +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 **`Conversione booleana`** -- Avviene nelle operazioni logiche, può anche essere richiamato esplicitamente con `Boolean(value)`. diff --git a/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md index 43ac15a17..36498e242 100644 --- a/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md +++ b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md @@ -16,6 +16,7 @@ undefined + 1 = NaN // (6) " \t \n" - 2 = -2 // (7) ``` +<<<<<<< HEAD 1. L'addizione con una stringa `"" + 1` converte `1` a stringa: `"" + 1 = "1"`, applichiamo la stessa regola a `"1" + 0`. 2. La sottrazione `-` (come molte altre operazioni matematiche) funziona solamente con i numeri, quindi una stringa vuota come: `""` viene convertita in `0`. 3. La somma con una stringa appende in coda alla stringa il numero `5`. @@ -23,3 +24,12 @@ undefined + 1 = NaN // (6) 5. `null` diventa `0` dopo la conversione numerica. 6. `undefined` diventa `NaN` dopo la conversione numerica. 7. Gli spazi all'inizio e alla fine di una stringa vengono rimossi quando questa viene convertita ad numero. In questo caso l'intera stringa è composta da spazi, come `\t`, `\n` ed uno "spazio" normale tra di essi. Quindi allo stesso modo di una stringa vuota, diventa `0`. +======= +1. The addition with a string `"" + 1` converts `1` to a string: `"" + 1 = "1"`, and then we have `"1" + 0`, the same rule is applied. +2. The subtraction `-` (like most math operations) only works with numbers, it converts an empty string `""` to `0`. +3. The addition with a string appends the number `5` to the string. +4. The subtraction always converts to numbers, so it makes `" -9 "` a number `-9` (ignoring spaces around it). +5. `null` becomes `0` after the numeric conversion. +6. `undefined` becomes `NaN` after the numeric conversion. +7. Space characters are trimmed off string start and end when a string is converted to a number. Here the whole string consists of space characters, such as `\t`, `\n` and a "regular" space between them. So, similarly to an empty string, it becomes `0`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/1-js/02-first-steps/08-operators/article.md b/1-js/02-first-steps/08-operators/article.md index cc772d4c8..8cd203d92 100644 --- a/1-js/02-first-steps/08-operators/article.md +++ b/1-js/02-first-steps/08-operators/article.md @@ -51,8 +51,14 @@ Il risultato di `a % b` è il [resto](https://en.wikipedia.org/wiki/Remainder) d Ad esempio: ```js run +<<<<<<< HEAD alert( 5 % 2 ); // 1, è il resto dell'operazione 5 diviso 2 alert( 8 % 3 ); // 2, è il resto dell'operazione 8 diviso 3 +======= +alert( 5 % 2 ); // 1, the remainder of 5 divided by 2 +alert( 8 % 3 ); // 2, the remainder of 8 divided by 3 +alert( 8 % 4 ); // 0, the remainder of 8 divided by 4 +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` ### Elevamento a Potenza ** @@ -70,7 +76,11 @@ alert( 2 ** 3 ); // 2³ = 8 alert( 2 ** 4 ); // 2⁴ = 16 ``` +<<<<<<< HEAD Come in matematica, l'esponente può essere anche un valore numerico non intero. +======= +Just like in maths, the exponentiation operator is defined for non-integer numbers as well. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio, la radice quadrata può essere vista come un elevamento a potenza con esponente `1/2`: @@ -82,7 +92,11 @@ alert( 8 ** (1/3) ); // 2 (potenza 1/3 equivale alla radice cubica) ## Concatenazione di stringhe, operatore binario + +<<<<<<< HEAD Adesso diamo un'occhiata alle caratteristiche degli operatori in JavaScript, che vanno oltre l'aritmetica scolastica. +======= +Let's meet the features of JavaScript operators that are beyond school arithmetics. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Solitamente l'operatore di somma `+` viene utilizzato per sommare due numeri. @@ -199,22 +213,30 @@ Un estratto della [tabella delle precedenze](https://developer.mozilla.org/en/Ja | Precedence | Name | Sign | |------------|------|------| | ... | ... | ... | -| 17 | unary plus | `+` | -| 17 | unary negation | `-` | -| 16 | exponentiation | `**` | -| 15 | multiplication | `*` | -| 15 | division | `/` | -| 13 | addition | `+` | -| 13 | subtraction | `-` | +| 14 | unary plus | `+` | +| 14 | unary negation | `-` | +| 13 | exponentiation | `**` | +| 12 | multiplication | `*` | +| 12 | division | `/` | +| 11 | addition | `+` | +| 11 | subtraction | `-` | | ... | ... | ... | -| 3 | assignment | `=` | +| 2 | assignment | `=` | | ... | ... | ... | +<<<<<<< HEAD Come possiamo vedere, la "somma unaria"(unary plus) ha una priorità di `17`, che è maggiore del `13` dell'addizione(`+` binario). Questo è il motivo per cui l'espressione `"+apples + +oranges"` esegue prima il `+` unario, e successivamente l'addizione. +======= +As we can see, the "unary plus" has a priority of `14` which is higher than the `11` of "addition" (binary plus). That's why, in the expression `"+apples + +oranges"`, unary pluses work before the addition. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Assegnazione +<<<<<<< HEAD Da notare che anche l'assegnazione `=` è un operatore. Viene infatti elencato nella tabella delle precedenze con una priorità molto bassa: `3`. +======= +Let's note that an assignment `=` is also an operator. It is listed in the precedence table with the very low priority of `2`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Questo è il motivo per cui quando assegniamo un valore ad una variabile, come `x = 2 * 2 + 1`, i calcoli vengono eseguiti per primi, e successivamente viene valutato l'operatore `=`, che memorizza il risultato in `x`. @@ -312,9 +334,14 @@ Questi operatori hanno la stessa precedenza delle normali assegnazioni, quindi v ```js run let n = 2; -n *= 3 + 5; +n *= 3 + 5; // right part evaluated first, same as n *= 8 +<<<<<<< HEAD alert( n ); // 16 (prima viene valutata la parte destra, equivale a n *= 8) +======= +alert( n ); // 16 +``` +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Incremento/Decremento @@ -445,7 +472,11 @@ La lista degli operatori: - RIGHT SHIFT ( `>>` ) - ZERO-FILL RIGHT SHIFT ( `>>>` ) +<<<<<<< HEAD Questi operatori vengono utilizzati molto raramente, quando abbiamo bisogno di lavorare con i numeri al più basso livello (bit per bit). Non avremo bisogno di questi operatori molto presto, poiché lo sviluppo web ne fa un uso limitato, ma in alcune aree speciali, come la crittografia, sono utili.In caso di necessità potete leggere l'articolo [operatori BitWise](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators) su MDN. +======= +These operators are used very rarely, when we need to fiddle with numbers on the very lowest (bitwise) level. We won't need these operators any time soon, as web development has little use of them, but in some special areas, such as cryptography, they are useful. You can read the [Bitwise Operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#bitwise_operators) chapter on MDN when a need arises. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Virgola diff --git a/1-js/02-first-steps/10-ifelse/article.md b/1-js/02-first-steps/10-ifelse/article.md index dfceb67e8..8062869e1 100644 --- a/1-js/02-first-steps/10-ifelse/article.md +++ b/1-js/02-first-steps/10-ifelse/article.md @@ -68,7 +68,11 @@ if (cond) { ## La clausola "else" +<<<<<<< HEAD L'istruzione `if` può essere seguita da un blocco opzionale "else". Questo viene eseguito quando la condizione è falsa. +======= +The `if` statement may contain an optional `else` block. It executes when the condition is falsy. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio: ```js run @@ -180,10 +184,17 @@ alert( message ); Potrebbe essere difficile, inizialmente, capirne la logica. Ma dopo averlo guardato da più vicino ci accorgeremo che è una semplice sequenza di condizioni. +<<<<<<< HEAD 1. Il primo operatore "?" controlla `age < 3`. 2. Se è vero -- ritorna `'Hi, baby!'`, altrimenti -- segue la colonna `":"`, controlla `age < 18`. 3. Se questo è vero -- ritorna `'Hello!'`, altrimenti -- segue la colonna `":"`, controlla `age < 100`. 4. Se questo è vero -- ritorna `'Greetings!'`, altrimenti -- segue la colonna `":"`, ritorna `'What an unusual age!'`. +======= +1. The first question mark checks whether `age < 3`. +2. If true -- it returns `'Hi, baby!'`. Otherwise, it continues to the expression after the colon ":", checking `age < 18`. +3. If that's true -- it returns `'Hello!'`. Otherwise, it continues to the expression after the next colon ":", checking `age < 100`. +4. If that's true -- it returns `'Greetings!'`. Otherwise, it continues to the expression after the last colon ":", returning `'What an unusual age!'`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 La stessa logica riscritta utilizzando `if..else`: diff --git a/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md b/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md index aadc5b0bd..cc1e6030f 100644 --- a/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md +++ b/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md @@ -1,6 +1,6 @@ La risposta è: `null`, perchè è il primo valore falso nella lista. ```js run -alert( 1 && null && 2 ); +alert(1 && null && 2); ``` diff --git a/1-js/02-first-steps/12-nullish-coalescing-operator/article.md b/1-js/02-first-steps/12-nullish-coalescing-operator/article.md index 4c60535d7..f6b05d4f3 100644 --- a/1-js/02-first-steps/12-nullish-coalescing-operator/article.md +++ b/1-js/02-first-steps/12-nullish-coalescing-operator/article.md @@ -4,7 +4,11 @@ Il *nullish coalescing operator* è rappresentato da due punti di domanda `??`. +<<<<<<< HEAD Siccome trattiamo `null` e `undefined` in modo simile, avremo bisogno di una definizione particolare. In questo articolo, diremo che un'espressione è "definita" quando non è né `null` né `undefined`. +======= +As it treats `null` and `undefined` similarly, we'll use a special term here, in this article. For brevity, we'll say that a value is "defined" when it's neither `null` nor `undefined`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Il risultato di `a ?? b` è: - se `a` è definito, allora `a`, @@ -22,12 +26,18 @@ result = (a !== null && a !== undefined) ? a : b; Un caso d'uso comune per l'operatore `??` è quello di fornire un valore di default per una variabile potenzialmente "non definita". +<<<<<<< HEAD Per esempio, qui mostriamo `Anonymous` se `user` non è definito: +======= +The common use case for `??` is to provide a default value. + +For example, here we show `user` if its value isn't `null/undefined`, otherwise `Anonymous`: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let user; -alert(user ?? "Anonymous"); // Anonymous (user not defined) +alert(user ?? "Anonymous"); // Anonymous (user is undefined) ``` Ovviamente, se `user` ha un qualsiasi valore eccetto `null/undefined`, allora vedremo quel valore: @@ -35,14 +45,20 @@ Ovviamente, se `user` ha un qualsiasi valore eccetto `null/undefined`, allora ve ```js run let user = "John"; -alert(user ?? "Anonymous"); // John (user defined) +alert(user ?? "Anonymous"); // John (user is not null/undefined) ``` Possiamo anche usare una sequenza di `??` per selezionare, da una lista, il primo valore che non sia `null/undefined`. +<<<<<<< HEAD Per esempio, supponiamo di avere i dati di un utente nelle variabili `firstName`, `lastName` o `nickName`. Tutte queste potrebbero essere non definite, se l'utente dovesse decidere di non inserirne i valori. Vorremmo visualizzare il nome dell'utente usando una di queste variabili, oppure mostrare "Anonymous" se nessuna di esse è definita. +======= +Let's say we have a user's data in variables `firstName`, `lastName` or `nickName`. All of them may be not defined, if the user decided not to fill in the corresponding values. + +We'd like to display the user name using one of these variables, or show "Anonymous" if all of them are `null/undefined`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Usiamo l'operatore `??`: @@ -74,7 +90,11 @@ alert(firstName || lastName || nickName || "Anonymous"); // Supercoder */!* ``` +<<<<<<< HEAD L'operatore OR `||` esiste sin dagli inizi di JavaScript e gli sviluppatori lo hanno usato a tale scopo per molto tempo. +======= +Historically, the OR `||` operator was there first. It's been there since the beginning of JavaScript, so developers were using it for such purposes for a long time. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Il nullish coalescing operator `??`, invece, è stato aggiunto recentemente. La ragione è che alcuni sviluppatori non erano del tutto contenti dell'operatore `||`. @@ -104,9 +124,17 @@ Se un'altezza pari a zero è un valore accettabile, questo non dovrebbe essere r ## Precedenza +<<<<<<< HEAD La precedenza dell'operatore `??` è piuttosto bassa: `5` nella [MDN table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table). Quindi `??` è valutato prima di `=` e `?`, ma dopo la maggior parte degli altri operatori, come `+` o `*`. Quindi, se volessimo scegliere un valore tramite l'operatore `??` in un'espressione contenente altri operatori, dovremmo considerare l'utilizzo delle parentesi: +======= +The precedence of the `??` operator is the same as `||`. They both equal `3` in the [MDN table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table). + +That means that, just like `||`, the nullish coalescing operator `??` is evaluated before `=` and `?`, but after most other operations, such as `+`, `*`. + +So we may need to add parentheses in expressions like this: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let height = null; @@ -124,7 +152,11 @@ Altrimenti, se omettessimo le parentesi, siccome `*` ha una precedenza maggiore // senza parentesi let area = height ?? 100 * width ?? 50; +<<<<<<< HEAD // ...funziona allo stesso modo del seguente codice (probabilmente non ciò che vogliamo) +======= +// ...works this way (not what we want): +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 let area = height ?? (100 * width) ?? 50; ``` diff --git a/1-js/02-first-steps/13-while-for/article.md b/1-js/02-first-steps/13-while-for/article.md index 81f44c398..6cf521b78 100644 --- a/1-js/02-first-steps/13-while-for/article.md +++ b/1-js/02-first-steps/13-while-for/article.md @@ -6,7 +6,24 @@ Ad esempio, quando abbiamo bisogno di ritornare, una dopo l'altra, della merce d I *cicli* sono un modo di ripetere una stessa parte di codice più volte. +<<<<<<< HEAD ## Il ciclo "while" +======= +```smart header="The for..of and for..in loops" +A small announcement for advanced readers. + +This article covers only basic loops: `while`, `do..while` and `for(..;..;..)`. + +If you came to this article searching for other types of loops, here are the pointers: + +- See [for..in](info:object#forin) to loop over object properties. +- See [for..of](info:array#loops) and [iterables](info:iterable) for looping over arrays and iterable objects. + +Otherwise, please read on. +``` + +## The "while" loop +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Il ciclo `while` ha la seguente sintassi: @@ -161,11 +178,14 @@ for (i = 0; i < 3; i++) { // utilizza una variabile esistente alert(i); // 3; la variabile `i` è accessibile (è stata dichiarata fuori dal corpo del ciclo) ``` - ```` +<<<<<<< HEAD ### Parti opzionali +======= +### Skipping parts +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ogni parte del ciclo `for` è opzionale. @@ -265,7 +285,13 @@ for (let i = 0; i < 10; i++) { } ``` +<<<<<<< HEAD Ovviamente possiamo raccogliere il codice in un blocco `if` piuttosto di usare `continue`. Dal punto di vista tecnico l'esempio sopra è identico a quello che lo precede, che invece utilizza `continue`. Nell'esempio sopra il codice dentro il corpo di `if` è una semplice chiamata ad `alert`; ma se il codice fosse più lungo di un paio di righe si rischierebbe di perdere in leggibilità. +======= +From a technical point of view, this is identical to the example above. Surely, we can just wrap the code in an `if` block instead of using `continue`. + +But as a side effect, this created one more level of nesting (the `alert` call inside the curly braces). If the code inside of `if` is longer than a few lines, that may decrease the overall readability. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```` ````warn header="Vietato `break/continue` alla desta di '?'" @@ -283,7 +309,6 @@ if (i > 5) { ...E lo riscriviamo utilizzando l'operatore ternario: - ```js no-beautify (i > 5) ? alert(i) : *!*continue*/!*; // continue non è consentito qui ``` @@ -320,7 +345,12 @@ Abbiamo bisogno di un modo per bloccare il processo se l'utente annulla l'input. Un semplice `break` dopo la variabile `input` interromperebbe solo il ciclo più interno. Questo non è sufficiente. I *label* ci vengono in soccorso. +<<<<<<< HEAD Un *label* ("etichetta") è un identificatore seguito da ":" e da un ciclo: +======= +A *label* is an identifier with a colon before a loop: + +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js labelName: for (...) { ... @@ -344,6 +374,7 @@ Come nell'esempio: // fa qualcosa con i valori... } } + alert('Done!'); ``` @@ -363,14 +394,24 @@ Anche la direttiva `continue` può essere utilizzata con un'etichetta. In questo ````warn header="I *label* non equivalgono a \"goto\"" I *label* non permettono di saltare in un punto arbitrario del codice. +<<<<<<< HEAD Ad esempio, non è possibile: +======= +For example, it is impossible to do this: + +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js break label; // non salta all'etichetta sotto label: for (...) ``` +<<<<<<< HEAD La direttiva `break` deve essere all'interno del blocco di codice. Tecnicamente l'etichettatura funzionerà con qualsiasi blocco di codice, ad esempio: +======= +A `break` directive must be inside a code block. Technically, any labelled code block will do, e.g.: + +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js label: { // ... diff --git a/1-js/02-first-steps/14-switch/article.md b/1-js/02-first-steps/14-switch/article.md index 4bc607614..5e4b4fd56 100644 --- a/1-js/02-first-steps/14-switch/article.md +++ b/1-js/02-first-steps/14-switch/article.md @@ -140,7 +140,11 @@ switch (a) { Ora sia `3` che `5` mostreranno lo stesso messaggio. +<<<<<<< HEAD L'abilità di "raggruppare" più `case` è un effetto collaterale di come `switch/case` funziona senza `break`. Qui l'esecuzione del `case 3` inizia dalla linea `(*)` e prosegue fino a `case 5`, perché non c'è alcun `break`. +======= +The ability to "group" cases is a side effect of how `switch/case` works without `break`. Here the execution of `case 3` starts from the line `(*)` and goes through `case 5`, because there's no `break`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Il tipo conta diff --git a/1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md b/1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md index 7fe85340a..07575fa30 100644 --- a/1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md +++ b/1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md @@ -1 +1,7 @@ -No, non ci sono differenze. \ No newline at end of file +<<<<<<< HEAD +No, non ci sono differenze. +======= +No difference! + +In both cases, `return confirm('Did parents allow you?')` executes exactly when the `if` condition is falsy. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/1-js/02-first-steps/15-function-basics/article.md b/1-js/02-first-steps/15-function-basics/article.md index bc2dc7a94..1fb08f25b 100644 --- a/1-js/02-first-steps/15-function-basics/article.md +++ b/1-js/02-first-steps/15-function-basics/article.md @@ -24,7 +24,7 @@ La parola chiave `function` va posta all'inizio; viene seguita dal *nome della f ```js function name(parameter1, parameter2, ... parameterN) { - ...body... + // body } ``` @@ -177,8 +177,13 @@ Quando un valore viene passato come parametro di funzione, vine anche chiamato * In altre parole In other words, per chiarire questi termini: +<<<<<<< HEAD - Un parametro è la variabile elencata tra parentesi nella dichiarazione della funzione (fa parte della dichiarazione). - Un argomento è il valore passato alla funzione quando viene chiamata (fa parte della chiamata). +======= +- A parameter is the variable listed inside the parentheses in the function declaration (it's a declaration time term). +- An argument is the value that is passed to the function when it is called (it's a call time term). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Dichiariamo le funzioni elencando i loro parametri, quindi le chiamiamo passando gli argomenti. @@ -206,7 +211,17 @@ function showMessage(from, *!*text = "no text given"*/!*) { showMessage("Ann"); // Ann: nessun text fornito ``` +<<<<<<< HEAD Adesso, se il parametro `text` non viene passato, assumerà il valore `"no text given"` +======= +Now if the `text` parameter is not passed, it will get the value `"no text given"`. + +The default value also jumps in if the parameter exists, but strictly equals `undefined`, like this: + +```js +showMessage("Ann", undefined); // Ann: no text given +``` +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 In questo caso `"no text given"` è una stringa, ma potrebbe essere un'espressione più complessa, che viene valutata e assegnata solamente se il parametro non viene fornito. Quindi, è possibile anche: @@ -225,9 +240,49 @@ Nell'esempio sopra, `anotherFunctions()` non viene chiamata se viene passato il Viene invece chiamata ogni volta che il parametro manca. ``` +<<<<<<< HEAD A volte ha senso assegnare valori default ai parametri, non nella dichiarazione della funzione, ma in una fase successiva. Possiamo verificare se il parametro viene passato durante l'esecuzione della funzione, confrontandolo con `undefined`: +======= +````smart header="Default parameters in old JavaScript code" +Several years ago, JavaScript didn't support the syntax for default parameters. So people used other ways to specify them. + +Nowadays, we can come across them in old scripts. + +For example, an explicit check for `undefined`: + +```js +function showMessage(from, text) { +*!* + if (text === undefined) { + text = 'no text given'; + } +*/!* + + alert( from + ": " + text ); +} +``` + +...Or using the `||` operator: + +```js +function showMessage(from, text) { + // If the value of text is falsy, assign the default value + // this assumes that text == "" is the same as no text at all + text = text || 'no text given'; + ... +} +``` +```` + + +### Alternative default parameters + +Sometimes it makes sense to assign default values for parameters at a later stage after the function declaration. + +We can check if the parameter is passed during the function execution, by comparing it with `undefined`: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run function showMessage(text) { @@ -409,7 +464,11 @@ Questi esempi assumono i significati comuni dei prefissi. Il loro significato di ```smart header="Nomi di funzioni ultra-corti" Funzioni che vengono utilizzate *molto spesso* potrebbero avere nomi molto corti. +<<<<<<< HEAD Ad esempio il framework [jQuery](http://jquery.com) definisce una funzione con `$`. La libreria [Lodash](http://lodash.com/) ha nel *core* una funzione denominata `_`. +======= +For example, the [jQuery](https://jquery.com/) framework defines a function with `$`. The [Lodash](https://lodash.com/) library has its core function named `_`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Queste sono eccezioni. Generalmente i nomi delle funzioni dovrebbero essere concisi e descrittivi. ``` @@ -477,7 +536,11 @@ function name(parameters, delimited, by, comma) { Per rendere il codice pulito e più facile da leggere, è consigliabile utilizzare principalmente variabili locali e parametri di funzione, non variabili esterne. +<<<<<<< HEAD E' sempre più facile capire una funzione che accetta parametri, li lavora e ritorna un valore piuttosto di una funzione che non richiede parametri ma, come effetto collaterale, modifica variabili esterne. +======= +It is always easier to understand a function which gets parameters, works with them and returns a result than a function which gets no parameters, but modifies outer variables as a side effect. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Denominare le funzioni: diff --git a/1-js/02-first-steps/16-function-expressions/article.md b/1-js/02-first-steps/16-function-expressions/article.md index e5aefd78a..2d7a34330 100644 --- a/1-js/02-first-steps/16-function-expressions/article.md +++ b/1-js/02-first-steps/16-function-expressions/article.md @@ -12,7 +12,13 @@ function sayHi() { E' disponibile un'altra sintassi per creare una funzione, chiamata *function expression*. +<<<<<<< HEAD La sintassi: +======= +It allows us to create a new function in the middle of any expression. + +For example: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js let sayHi = function() { @@ -72,15 +78,20 @@ let sayHi = function() { // (1) create alert( "Hello" ); }; -let func = sayHi; +let func = sayHi; //(2) // ... ``` Tutto funzionerebbe ugualmente. Risulta anche più chiaro cosa sta succedendo, giusto? +<<<<<<< HEAD ````smart header="Perché c'è un punto e virgola alla fine?" Vi starete chiedendo perché con la function expression bisogna mettere `;` alla fine, mentre con la dichiarazione di funzione non serve: +======= +````smart header="Why is there a semicolon at the end?" +You might wonder, why do Function Expressions have a semicolon `;` at the end, but Function Declarations do not: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js function sayHi() { @@ -135,13 +146,21 @@ function showCancel() { ask("Do you agree?", showOk, showCancel); ``` +<<<<<<< HEAD Queste funzioni possono essere molto utili. La principale differenza tra un'implementazione realistica e gli esempi sopra è che le funzioni "reali" utilizzano modalità più complesse per interagire con l'utente, non un semplice `confirm`. In ambiente browser, queste funzioni mostrano spesso delle finestre molto carine per gli input dell'utente. Ma questo è un altro discorso. +======= +In practice, such functions are quite useful. The major difference between a real-life `ask` and the example above is that real-life functions use more complex ways to interact with the user than a simple `confirm`. In the browser, such functions usually draw a nice-looking question window. But that's another story. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 **Gli argomenti `showOk` e `showCancel` della `ask` sono chiamati *funzioni di richiamo* o semplicemente *callbacks*.** L'idea è di passare una funzione e di "richiamarla" più tardi se necessario. Nel nostro caso `showOk` diventa la callback per la risposta "yes", e `showCancel` per la risposta "no". +<<<<<<< HEAD Possiamo utilizzare una function expression per scrivere la stessa funzione più concisamente: +======= +We can use Function Expressions to write an equivalent, shorter function: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run no-beautify function ask(question, yes, no) { @@ -179,7 +198,11 @@ Cerchiamo di elencare le differenze chiave tra Dichiarazioni ed Espressioni di F Primo, la sintassi: come distinguerle nel codice. +<<<<<<< HEAD - *Dichiarazione di funzione:* una funzione, dichiarata come un'istruzione separata, nel flusso principale del programma. +======= +- *Function Declaration:* a function, declared as a separate statement, in the main code flow: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js // Dichiarazione di funzione @@ -187,8 +210,13 @@ Primo, la sintassi: come distinguerle nel codice. return a + b; } ``` +<<<<<<< HEAD - *Function expression:* una funzione, creata all'interno di un'espressione o all'interno di un altro costrutto. Qui, la funzione è creata alla destra dell' "espressione di assegnazione" `=`: +======= +- *Function Expression:* a function, created inside an expression or inside another syntax construct. Here, the function is created on the right side of the "assignment expression" `=`: + +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js // function expression let sum = function(a, b) { @@ -284,9 +312,15 @@ if (age < 18) { welcome(); // \ (esegue) */!* // | +<<<<<<< HEAD function welcome() { // | alert("Hello!"); // | Dichiarazione di funzione disponibile } // | ovunque nel blocco in cui è stata dichiarata +======= + function welcome() { // | + alert("Hello!"); // | Function Declaration is available + } // | everywhere in the block where it's declared +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 // | *!* welcome(); // / (esegue) @@ -294,7 +328,11 @@ if (age < 18) { } else { +<<<<<<< HEAD function welcome() { +======= + function welcome() { +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 alert("Greetings!"); } } @@ -352,8 +390,13 @@ welcome(); // ora funziona ``` +<<<<<<< HEAD ```smart header="Quando conviene scegliere una dichiarazione di funzione piuttosto di una function expression?" Come regola fondamentale, quando abbiamo la necessità di dichiarare una funzione, la prima opzione da considerare è la dichiarazione di funzione. Fornisce maggiore libertà per quanto riguarda l'organizzazione del codice, poiché possiamo utilizzare la funzione anche prima della sua dichiarazione. +======= +```smart header="When to choose Function Declaration versus Function Expression?" +As a rule of thumb, when we need to declare a function, the first thing to consider is Function Declaration syntax. It gives more freedom in how to organize our code, because we can call such functions before they are declared. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Risulta anche più facile vedere `function f(…) {…}`, nel codice, piuttosto di `let f = function(…) {…}`. La dichiarazione di funzione è più facile da individuare. diff --git a/1-js/02-first-steps/17-arrow-functions-basics/article.md b/1-js/02-first-steps/17-arrow-functions-basics/article.md index 1a1dc2a09..3d6f11556 100644 --- a/1-js/02-first-steps/17-arrow-functions-basics/article.md +++ b/1-js/02-first-steps/17-arrow-functions-basics/article.md @@ -33,7 +33,11 @@ let sum = function(a, b) { alert( sum(1, 2) ); // 3 ``` +<<<<<<< HEAD Come puoi vedere `(a, b) => a + b` rappresenta una funzione che accetta due argomenti `a` e `b`. Al momento dell'esecuzione, questa valuta l'espressione `a + b` e restituisce il risultato. +======= +As you can see, `(a, b) => a + b` means a function that accepts two arguments named `a` and `b`. Upon the execution, it evaluates the expression `a + b` and returns the result. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 - Se abbiamo un solo argomento, le parentesi che racchiudono gli argomenti possono essere omesse, abbreviando ulteriormente il codice. @@ -48,7 +52,11 @@ Come puoi vedere `(a, b) => a + b` rappresenta una funzione che accetta due argo alert( double(3) ); // 6 ``` +<<<<<<< HEAD - Se non ci sono argomenti, le parentesi saranno vuote (ma devono essere presenti): +======= +- If there are no arguments, parentheses are empty, but they must be present: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let sayHi = () => alert("Hello!"); @@ -64,7 +72,7 @@ Ad esempio, per creare dinamicamente una funzione: let age = prompt("What is your age?", 18); let welcome = (age < 18) ? - () => alert('Hello') : + () => alert('Hello!') : () => alert("Greetings!"); welcome(); @@ -76,9 +84,15 @@ Esse sono molto comode per semplici azioni su una riga, se siamo troppo pigri pe ## Arrow functions su più linee +<<<<<<< HEAD Gli esempi precedenti hanno preso argomenti alla sinistra di "=>" e con essi hanno valutato l'espressione a destra. A volte abbiamo bisogno di qualcosa di un po' più complesso, come espressioni o dichiarazioni multiple. Anche questo è possibile, ma dovremo racchiuderle tra parentesi graffe ed usare un normale return. +======= +The arrow functions that we've seen so far were very simple. They took arguments from the left of `=>`, evaluated and returned the right-side expression with them. + +Sometimes we need a more complex function, with multiple expressions and statements. In that case, we can enclose them in curly braces. The major difference is that curly braces require a `return` within them to return a value (just like a regular function does). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 In questo modo: @@ -86,7 +100,11 @@ In questo modo: let sum = (a, b) => { // le parentesi graffe aprono una funzione multilinea let result = a + b; *!* +<<<<<<< HEAD return result; // se usiamo le parentesi graffe abbiamo bisogno di un esplicito "return" +======= + return result; // if we use curly braces, then we need an explicit "return" +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 */!* }; @@ -106,8 +124,15 @@ Per ora possiamo già utilizzarle per azioni su una riga sola e per callbacks. ## Summary +<<<<<<< HEAD Le arrow functions sono utili per azioni su una riga sola. Possono essere scritte in due modi: 1. Senza parentesi graffe: `(...args) => expression` -- la parte destra è un'espressione: la funzione la valuta e restituisce il risultato. 2. Con parentesi graffe: `(...args) => { body }` -- le parentesi ci permettono di scrivere comandi multipli all'interno della funzione, ma abbiamo bisogno di dichiarare esplicitamente `return` affinché sia ritornato qualcosa. +======= +Arrow functions are handy for simple actions, especially for one-liners. They come in two flavors: + +1. Without curly braces: `(...args) => expression` -- the right side is an expression: the function evaluates it and returns the result. Parentheses can be omitted, if there's only a single argument, e.g. `n => n*2`. +2. With curly braces: `(...args) => { body }` -- brackets allow us to write multiple statements inside the function, but we need an explicit `return` to return something. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/1-js/02-first-steps/18-javascript-specials/article.md b/1-js/02-first-steps/18-javascript-specials/article.md index 1f891fd26..d91311f41 100644 --- a/1-js/02-first-steps/18-javascript-specials/article.md +++ b/1-js/02-first-steps/18-javascript-specials/article.md @@ -55,7 +55,11 @@ Per abilitare completamente tutte le caratteristiche del moderno JavaScript, dov La direttiva deve essere posta all'inizio di ogni script o all'inizio di una funzione. +<<<<<<< HEAD Senza `"use strict"`, tutto continuerebbe a funzionare, ma alcune caratteristiche si comporterebbero in vecchio-stile, per retrocompatibilità. Generalmente si preferisce la modalità con i comportamenti moderni. +======= +Without `"use strict"`, everything still works, but some features behave in the old-fashioned, "compatible" way. We'd generally prefer the modern behavior. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Alcune caratteristiche moderne del linguaggio (come le classi che studieremo più avanti) attivano automaticamente la modalità script. @@ -103,6 +107,7 @@ Di più in: e . Abbiamo utilizzato solo il browser come ambiente di sviluppo, quindi le interfacce di base saranno: +<<<<<<< HEAD [`prompt(question[, default])`](mdn:api/Window/prompt) : Pone una domanda `question`, e ritorna quello che l'utente ha inserito oppure `null` se ha premuto "cancel". @@ -111,6 +116,16 @@ Abbiamo utilizzato solo il browser come ambiente di sviluppo, quindi le interfac [`alert(message)`](mdn:api/Window/alert) : Stampa un messaggio `message`. +======= +[`prompt(question, [default])`](https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt) +: Ask a `question`, and return either what the visitor entered or `null` if they clicked "cancel". + +[`confirm(question)`](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm) +: Ask a `question` and suggest to choose between Ok and Cancel. The choice is returned as `true/false`. + +[`alert(message)`](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert) +: Output a `message`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Tutte queste funzioni sono dei *modal*, interrompono l'esecuzione e impediscono all'utente di interagire con una pagina fino a che il visitatore non risponde. @@ -143,8 +158,13 @@ Aritmetici Assegnazione : Ci sono le assegnazioni semplici: `a = b` e quelle combinate `a *= 2`. +<<<<<<< HEAD Bit a Bit : Gli operatori bit a bit funzionano con gli interi a livello di bit: guarda la [documentazione](mdn:/JavaScript/Reference/Operators/Bitwise_Operators) se ne avrai bisogno. +======= +Bitwise +: Bitwise operators work with 32-bit integers at the lowest, bit-level: see the [docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#bitwise_operators) when they are needed. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ternari : C'è un solo operatore con tre parametri: `cond ? resultA : resultB`. Se `cond` è vera, ritorna `resultA`, altrimenti `resultB`. @@ -258,7 +278,11 @@ Abbiamo studiato tre modi per creare funzioni in JavaScript: 3. Funzione freccia: ```js +<<<<<<< HEAD // espressione dalla parte destra +======= + // expression on the right side +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 let sum = (a, b) => a + b; // oppure la sintassi multi-riga con { ... }, è necessario esplicitare return diff --git a/1-js/03-code-quality/01-debugging-chrome/article.md b/1-js/03-code-quality/01-debugging-chrome/article.md index a944af1b1..12e2c63b6 100644 --- a/1-js/03-code-quality/01-debugging-chrome/article.md +++ b/1-js/03-code-quality/01-debugging-chrome/article.md @@ -38,7 +38,11 @@ Se premiamo `key:Esc`, si apre una console in basso. Possiamo digitare comandi e Dopo l'esecuzione dell'istruzione, il risultato viene mostrato sotto. +<<<<<<< HEAD Ad esempio, `1+2` con risultato `3`, ed `hello("debugger")` non ritorna nulla, quindi il risultato è `undefined`: +======= +For example, here `1+2` results in `3`, while the function call `hello("debugger")` returns nothing, so the result is `undefined`: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ![](chrome-sources-console.svg) @@ -62,13 +66,22 @@ Possiamo anche visualizzare la lista dei breakpoint nel pannello di destra. Ques - Rimuovere breakpoint cliccando con il tasto destro e selezionando Rimuovi. - ...E molto altro. +<<<<<<< HEAD ```smart header="Breakpoint condizionali" *Tasto destro* sul numero della riga ci consente di creare un breakpoint *condizionale*. Che viene attivato solo quando l'espressione fornita risulta vera. +======= +```smart header="Conditional breakpoints" +*Right click* on the line number allows to create a *conditional* breakpoint. It only triggers when the given expression, that you should provide when you create it, is truthy. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Questa caratteristica risulta molto utile quando abbiamo bisogno di fermare il flusso di esecuzione per determinati valori di una variabile. ``` +<<<<<<< HEAD ## Comando debugger +======= +## The command "debugger" +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Possiamo mettere in pausa il codice anche utilizzando il comando `debugger`, come nell'esempio: @@ -84,8 +97,12 @@ function hello(name) { } ``` +<<<<<<< HEAD Questo risulta molto utile quando stiamo lavorando in un editor e non vogliamo passare alla finestra del browser, cercare il punto corretto nello script interessato e impostare il breakpoint. +======= +Such command works only when the development tools are open, otherwise the browser ignores it. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Interrompere l'esecuzione e guardarsi intorno @@ -99,7 +116,11 @@ Ora aprite il menu a cascata (quello con la freccetta accanto al nome). Ti conse 1. **`Watch` -- mostra il valore corrente per ogni espressione.** +<<<<<<< HEAD Puoi cliccare su `+` e inserire un espressione. Il debugger ti mostrerà il suo valore ad ogni istante, che verrà automaticamente ricalcolato durante l'esecuzione. +======= + You can click the plus `+` and input an expression. The debugger will show its value, automatically recalculating it in the process of execution. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 2. **`Call Stack` -- mostra la catena delle chiamate annidate.** @@ -134,12 +155,21 @@ Ci sono dei bottoni appositi nella parte superiore del pannello di destra. Provi Continuando a cliccare eseguiremo lo script un passo per volta. +<<<<<<< HEAD -- "Step over": esegue il prossimo comando, ma *non entra nella funzione*, hotkey `key:F10`. : Molto simile al comando "Step", ma si comporta diversamente nel caso in cui l'istruzione successiva sia una chiamata a funzione. O meglio: non una funzione built-in come `alert`, ma una funzione definita da noi. Il comando "Step" entra nella funzione e mette in pausa l'esecuzione, mentre "Step over" esegue la chiamata a funzione, saltandone il contenuto. L'esecuzione viene interrotta al termine della chiamata. +======= + -- "Step over": run the next command, but *don't go into a function*, hotkey `key:F10`. +: Similar to the previous "Step" command, but behaves differently if the next statement is a function call (not a built-in, like `alert`, but a function of our own). + + If we compare them, the "Step" command goes into a nested function call and pauses the execution at its first line, while "Step over" executes the nested function call invisibly to us, skipping the function internals. + + The execution is then paused immediately after that function call. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Questo è molto utile se non siamo interessati nel vedere cosa accade dentro la funzione. @@ -157,8 +187,13 @@ Ci sono dei bottoni appositi nella parte superiore del pannello di destra. Provi -- attiva/disattiva tutti i breakpoint. : Questo bottone non influenza l'esecuzione. E' semplicemente un on/off per i breakpoint. +<<<<<<< HEAD -- attiva/disattiva la pausa automatica in caso di errori. : Quando questa opzione è attiva, e il pannello degli strumenti sviluppatore è aperto, un errore nello script metterà automaticamente in pausa l'esecuzione. Cosi potremmo analizzare le variabili per capire cosa è andato storto. Quindi se il nostro script si blocca con un errore, possiamo aprire il debugger, attivare questa opzione e ricaricare la pagina per vedere dove si blocca lo script e capirne il motivo. +======= + -- enable/disable automatic pause in case of an error. +: When enabled, if the developer tools is open, an error during the script execution automatically pauses it. Then we can analyze variables in the debugger to see what went wrong. So if our script dies with an error, we can open debugger, enable this option and reload the page to see where it dies and what's the context at that moment. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```smart header="Continua fino a qui" Premendo tasto destro su una riga di codice si aprirà un menu con una bellissima opzione denominata "Continua fino a qui". @@ -190,7 +225,11 @@ Come abbiamo visto, ci sono tre diversi modi di mettere in pausa uno script: 2. L'istruzione `debugger`. 3. Un errore (solo se gli strumenti sviluppatore sono aperti ed è attivo il bottone ) +<<<<<<< HEAD Cosi possiamo esaminare le variabili e capire cosa è andato male durante l'esecuzione. +======= +When paused, we can debug: examine variables and trace the code to see where the execution goes wrong. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ci sono veramente troppe opzioni negli strumenti da sviluppatore per coprirle qui. Il manuale completo è disponibile all'indirizzo . diff --git a/1-js/03-code-quality/01-debugging-chrome/chrome-open-sources.svg b/1-js/03-code-quality/01-debugging-chrome/chrome-open-sources.svg index a3c7db6ec..5fc6dce3a 100644 --- a/1-js/03-code-quality/01-debugging-chrome/chrome-open-sources.svg +++ b/1-js/03-code-quality/01-debugging-chrome/chrome-open-sources.svg @@ -1 +1 @@ -open sources \ No newline at end of file +open sources \ No newline at end of file diff --git a/1-js/03-code-quality/01-debugging-chrome/chrome-sources-breakpoint.svg b/1-js/03-code-quality/01-debugging-chrome/chrome-sources-breakpoint.svg index 6e7b60f85..63bf4966e 100644 --- a/1-js/03-code-quality/01-debugging-chrome/chrome-sources-breakpoint.svg +++ b/1-js/03-code-quality/01-debugging-chrome/chrome-sources-breakpoint.svg @@ -1 +1 @@ -here's the listbreakpoints \ No newline at end of file +here's the listbreakpoints \ No newline at end of file diff --git a/1-js/03-code-quality/01-debugging-chrome/chrome-sources-console.svg b/1-js/03-code-quality/01-debugging-chrome/chrome-sources-console.svg index d5d2a0b93..3fe5f124f 100644 --- a/1-js/03-code-quality/01-debugging-chrome/chrome-sources-console.svg +++ b/1-js/03-code-quality/01-debugging-chrome/chrome-sources-console.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/1-js/03-code-quality/01-debugging-chrome/chrome-sources-debugger-pause.svg b/1-js/03-code-quality/01-debugging-chrome/chrome-sources-debugger-pause.svg index 83468fddb..0147c2e0a 100644 --- a/1-js/03-code-quality/01-debugging-chrome/chrome-sources-debugger-pause.svg +++ b/1-js/03-code-quality/01-debugging-chrome/chrome-sources-debugger-pause.svg @@ -1 +1 @@ -213see the outer call detailswatch expressionscurrent variables \ No newline at end of file +213see the outer call detailswatch expressionscurrent variables \ No newline at end of file diff --git a/1-js/03-code-quality/01-debugging-chrome/chrome-sources-debugger-trace-1.svg b/1-js/03-code-quality/01-debugging-chrome/chrome-sources-debugger-trace-1.svg index 23937e0d6..9fa1b3b8c 100644 --- a/1-js/03-code-quality/01-debugging-chrome/chrome-sources-debugger-trace-1.svg +++ b/1-js/03-code-quality/01-debugging-chrome/chrome-sources-debugger-trace-1.svg @@ -1 +1 @@ -nested calls \ No newline at end of file +nested calls \ No newline at end of file diff --git a/1-js/03-code-quality/01-debugging-chrome/chrome-tabs.svg b/1-js/03-code-quality/01-debugging-chrome/chrome-tabs.svg index 41a3d8784..016708256 100644 --- a/1-js/03-code-quality/01-debugging-chrome/chrome-tabs.svg +++ b/1-js/03-code-quality/01-debugging-chrome/chrome-tabs.svg @@ -1 +1 @@ -213 \ No newline at end of file +213 \ No newline at end of file diff --git a/1-js/03-code-quality/02-coding-style/code-style.svg b/1-js/03-code-quality/02-coding-style/code-style.svg index 12a755c97..739d9f1ed 100644 --- a/1-js/03-code-quality/02-coding-style/code-style.svg +++ b/1-js/03-code-quality/02-coding-style/code-style.svg @@ -1 +1 @@ -2No space between the function name and parentheses between the parentheses and the parameterIndentation 2 spacesA space after for/if/while…} else { without a line breakSpaces around a nested callAn empty line between logical blocksLines are not very longA semicolon ; is mandatorySpaces around operatorsCurly brace { on the same line, after a spaceA space between argumentsA space between parameters \ No newline at end of file +2No space between the function name and parentheses between the parentheses and the parameterIndentation 2 spacesA space after for/if/while…} else { without a line breakSpaces around a nested callAn empty line between logical blocksLines are not very longA semicolon ; is mandatorySpaces around operatorsCurly brace { on the same line, after a spaceA space between argumentsA space between parameters \ No newline at end of file diff --git a/1-js/03-code-quality/03-comments/article.md b/1-js/03-code-quality/03-comments/article.md index b69514c70..61be0a234 100644 --- a/1-js/03-code-quality/03-comments/article.md +++ b/1-js/03-code-quality/03-comments/article.md @@ -143,7 +143,11 @@ Documentare l'utilizzo di una funzione I molti casi, gli editor come [WebStorm](https://www.jetbrains.com/webstorm/) sono in grado di comprenderli e possono quindi utilizzarli per autocompletamenti e alcune verifiche automatiche del codice. +<<<<<<< HEAD Ci sono anche tool come [JSDoc 3](https://github.com/jsdoc3/jsdoc) che possono generare documentazione in HTML a partire dai commenti. Puoi scoprire di più riguardo JSDoc su . +======= +Also, there are tools like [JSDoc 3](https://github.com/jsdoc/jsdoc) that can generate HTML-documentation from the comments. You can read more information about JSDoc at . +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Perché l'azione viene risolta in quel modo? : Quello che viene scritto è fondamentale. Ma quello che *non* viene scritto potrebbe esserlo anche di più per capire cosa sta succedendo. Perché l'azione viene portata a termine in quel modo? Il codice non fornisce risposte. diff --git a/1-js/03-code-quality/05-testing-mocha/article.md b/1-js/03-code-quality/05-testing-mocha/article.md index e117b8959..9c33bf411 100644 --- a/1-js/03-code-quality/05-testing-mocha/article.md +++ b/1-js/03-code-quality/05-testing-mocha/article.md @@ -53,7 +53,11 @@ describe("pow", function() { Una spec ha tre principali blocchi: `describe("title", function() { ... })` +<<<<<<< HEAD : Viene descritta la funzionalità. Utilizzata per raggruppare le "attività" -- i blocchi `it`. Nel nostro caso descriviamo la funzione `pow`. +======= +: What functionality we're describing? In our case we're describing the function `pow`. Used to group "workers" -- the `it` blocks. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 `it("title", function() { ... })` : Nel titolo di `it` descriviamo il particolare caso d'uso *leggibile per gli umani*, come secondo argomento una funzione che lo testa. @@ -69,6 +73,7 @@ Una spec ha tre principali blocchi: Il flusso di sviluppo solitamente segue i passi: +<<<<<<< HEAD 1. Viene scritta una spec iniziale, con dei test per le funzionalità di base. 2. Si crea un implementazione di base. 3. Per verificare che questa funzioni, utilizziamo un framework di testing come [Mocha](http://mochajs.org/) (presto maggiori dettagli) che esegue le spec. Vengono mostrati gli errori. Facciamo le correzioni e riproviamo finché tutto funziona correttamente. @@ -76,12 +81,25 @@ Il flusso di sviluppo solitamente segue i passi: 5. Aggiungiamo più casi d'uso alla spec, magari ancora non supportate dall'implementazione. Cosi i test inizieranno a fallire. 6. Quindi tornate al passo 3, aggiornate l'implementazione e continuate finché tutto non funziona correttamente. 7. Ripetete gli step 3-6 fino ad ottenere la funzionalità desiderata. +======= +1. An initial spec is written, with tests for the most basic functionality. +2. An initial implementation is created. +3. To check whether it works, we run the testing framework [Mocha](https://mochajs.org/) (more details soon) that runs the spec. While the functionality is not complete, errors are displayed. We make corrections until everything works. +4. Now we have a working initial implementation with tests. +5. We add more use cases to the spec, probably not yet supported by the implementations. Tests start to fail. +6. Go to 3, update the implementation till tests give no errors. +7. Repeat steps 3-6 till the functionality is ready. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Quindi la fase di sviluppo è *iterativa*. Scriviamo la specifica, la implementiamo, ci accertiamo che passi i test, ci assicuriamo che faccia ciò che deve. Al termine di questa procedura avremmo un implementazione già testata e funzionante. Nel nostro caso, il primo step è completo: abbiamo un specifica iniziale di `pow`. Quindi ora passiamo all'implementazione. Come prima cosa facciamo l'esecuzione "zero" con le specifiche scritte, per essere sicuri che tutto funzioni (ovviamente i test dovrebbero fallire tutti). +<<<<<<< HEAD ## La spec in azione +======= +The first step is already complete: we have an initial spec for `pow`. Now, before making the implementation, let's use a few JavaScript libraries to run the tests, just to see that they are working (they will all fail). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 In questo guida utilizzeremo le seguenti librerie JavaScript per fare test: @@ -89,7 +107,13 @@ In questo guida utilizzeremo le seguenti librerie JavaScript per fare test: - [Chai](http://chaijs.com) -- una libreria con molte asserzioni. Ci consente di utilizzare molte asserzioni differenti, per ora ci servirà solamente `assert.equal`. - [Sinon](http://sinonjs.org/) -- una libreria per il controllo oltre le funzioni, emula funzioni integrate e molto altro, la utilizzeremo più avanti. +<<<<<<< HEAD Queste librerie sono utili sia per per il test browser, sia per il test lato server. Qui considereremo la variante browser. +======= +- [Mocha](https://mochajs.org/) -- the core framework: it provides common testing functions including `describe` and `it` and the main function that runs tests. +- [Chai](https://www.chaijs.com/) -- the library with many assertions. It allows to use a lot of different assertions, for now we need only `assert.equal`. +- [Sinon](https://sinonjs.org/) -- a library to spy over functions, emulate built-in functions and more, we'll need it much later. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 La pagina HTML con questi framework e le spec di pow `pow`: @@ -336,6 +360,7 @@ I nuovi test aggiunti falliranno, perché la nostra implementazione non li suppo ```smart header="Altre asserzioni" +<<<<<<< HEAD Metto in evidenza l'asserzione `assert.isNaN`: che effettua controlli di tipo `NaN`. In Chai sono presenti molte altre asserzioni, ad esempio: @@ -346,6 +371,16 @@ In Chai sono presenti molte altre asserzioni, ad esempio: - `assert.isTrue(value)` -- esegue il controllo `value === true` - `assert.isFalse(value)` -- verifica che `value === false` - ...l'inter lista è disponibile nella [documentazione](http://chaijs.com/api/assert/) +======= +There are other assertions in [Chai](https://www.chaijs.com/) as well, for instance: + +- `assert.equal(value1, value2)` -- checks the equality `value1 == value2`. +- `assert.strictEqual(value1, value2)` -- checks the strict equality `value1 === value2`. +- `assert.notEqual`, `assert.notStrictEqual` -- inverse checks to the ones above. +- `assert.isTrue(value)` -- checks that `value === true` +- `assert.isFalse(value)` -- checks that `value === false` +- ...the full list is in the [docs](https://www.chaijs.com/api/assert/) +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` Dovremmo quindi aggiungere un paio di linee a `pow`: diff --git a/1-js/03-code-quality/06-polyfills/article.md b/1-js/03-code-quality/06-polyfills/article.md index fbb1f1182..78edf1c5c 100644 --- a/1-js/03-code-quality/06-polyfills/article.md +++ b/1-js/03-code-quality/06-polyfills/article.md @@ -1,13 +1,23 @@ # Polyfills e transpilers +<<<<<<< HEAD Il linguaggio JavaScript si evolve costantemente. Nuove proposte per il linguaggio arrivano regolarmente, vengono analizzate, e successivamente se ritenute valide vengono aggiunte alla lista fino a diventare delle [specifiche](http://www.ecma-international.org/publications/standards/Ecma-262.htm). +======= +The JavaScript language steadily evolves. New proposals to the language appear regularly, they are analyzed and, if considered worthy, are appended to the list at and then progress to the [specification](https://www.ecma-international.org/publications-and-standards/standards/ecma-262/). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 I team che stanno dietro il motore di JavaScript hanno le loro personali idee riguardo cosa implementare. Potrebbero quindi decidere di implementare delle proposte recenti e posticipare quelle più vecchie a causa di difficoltà nell'implementazione. +<<<<<<< HEAD Quindi per un motore di script è naturale implementare solo le cose che si trovano nello standard. Se si vuole rimanere aggiornati riguardo lo stato di supporto delle caratteristiche si può controllare la pagina (è molto grande, dovremmo studiare ancora molto). +======= +So it's quite common for an engine to implement only part of the standard. + +A good page to see the current state of support for language features is (it's big, we have a lot to study yet). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Come programmatori, amiamo utilizzare le più recenti caratteristiche del linguaggio! @@ -40,9 +50,15 @@ Ora il codice riscritto è adatto anche ai vecchi motori JavaScript. In genere lo sviluppatore fa girare il transpiler in locale sul proprio computer, quindi distribuisce sul server il codice riscritto. +<<<<<<< HEAD Facendo qualche nome, [Babel](https://babeljs.io) è uno dei più diffusi transpilers del momento. I moderni 'bundler' utilizzati per 'assemblare' progetti, come [webpack](http://webpack.github.io/), possono eseguire il transpiler automaticamente ad ogni modifica del codice, è quindi molto facile integrarlo nei processi di sviluppo. +======= +Speaking of names, [Babel](https://babeljs.io) is one of the most prominent transpilers out there. + +Modern project build systems, such as [webpack](https://webpack.js.org/), provide a means to run a transpiler automatically on every code change, so it's very easy to integrate into the development process. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Polyfills @@ -69,17 +85,23 @@ if (!Math.trunc) { // se la funzione non esiste } ``` +<<<<<<< HEAD JavaScript è un linguaggio altamente dinamico, gli script possono aggiungere/modificare qualsiasi funzione, anche quelle integrate. Due interessanti librerie polyfills sono: - [core js](https://github.com/zloirock/core-js) ha molte funzioni e consente di includere solo le funzionalità necessarie. - [polyfill.io](http://polyfill.io) servizio che fornisce uno script con polyfill, a seconda delle funzionalità e del browser dell'utente. +======= +JavaScript is a highly dynamic language. Scripts may add/modify any function, even built-in ones. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 +One interesting polyfill library is [core-js](https://github.com/zloirock/core-js), which supports a wide range of features and allows you to include only the ones you need. ## Riepilogo In questo capitolo vorremmo motivarvi a studiare le funzionalità più moderne ed all'avanguardia" del linguaggio, anche se non sono ancora ben supportate dai motori JavaScript. +<<<<<<< HEAD Basta non dimenticare di usare transpiler (se si utilizza la sintassi o gli operatori moderni) e i polyfill (per aggiungere funzioni che potrebbero mancare). Questi si assicureranno che il codice funzioni. Ad esempio, in seguito, quando avrai familiarità con JavaScript, potrai configurare un sistema di compilazione del codice basato su [webpack](http://webpack.github.io/) con [babel-loader](https://github.com/babel/babel-loader) plugin. @@ -87,5 +109,16 @@ Ad esempio, in seguito, quando avrai familiarità con JavaScript, potrai configu Buone risorse che mostrano lo stato attuale del supporto per varie funzionalità: - - per puro JavaScript. - - per le funzioni integrate dei browsers. +======= +Just don't forget to use a transpiler (if using modern syntax or operators) and polyfills (to add functions that may be missing). They'll ensure that the code works. + +For example, later when you're familiar with JavaScript, you can setup a code build system based on [webpack](https://webpack.js.org/) with the [babel-loader](https://github.com/babel/babel-loader) plugin. + +Good resources that show the current state of support for various features: +- - for pure JavaScript. +- - for browser-related functions. + +P.S. Google Chrome is usually the most up-to-date with language features, try it if a tutorial demo fails. Most tutorial demos work with any modern browser though. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 P.S. Google Chrome è solitamente il browser più aggiornato con le funzionalità del linguaggio, provalo se una demo tutorial fallisce. Tuttavia, la maggior parte delle demo dei tutorial funziona con qualsiasi browser moderno. diff --git a/1-js/04-object-basics/01-object/article.md b/1-js/04-object-basics/01-object/article.md index 2a19bcda5..74fb186e6 100644 --- a/1-js/04-object-basics/01-object/article.md +++ b/1-js/04-object-basics/01-object/article.md @@ -44,7 +44,11 @@ L'oggetto `user` può essere visto come un archivio con due file etichettati com ![user object](object-user.svg) +<<<<<<< HEAD Possiamo aggiungere, rimuovere o leggere un file in qualsiasi momento. +======= +We can add, remove and read files from it at any time. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 I valori delle proprietà sono accessibili utilizzando la notazione puntata: @@ -62,7 +66,11 @@ user.isAdmin = true; ![user object 2](object-user-isadmin.svg) +<<<<<<< HEAD Per rimuovere una proprietà, possiamo utilizzare l'operatore `delete`: +======= +To remove a property, we can use the `delete` operator: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js delete user.age; @@ -197,13 +205,21 @@ let bag = { }; ``` +<<<<<<< HEAD Le parentesi quadre sono molto più potenti della notazione puntata. Ci permettono di assegnare qualsiasi nome, ma sono più "ingombranti". La maggior parte delle volte, quando il nome della proprietà è conosciuto e semplice, la notazione puntata viene preferita. Se invece necessitiamo di qualcosa di più complesso, possiamo utilizzare le parentesi quadre. +======= +Square brackets are much more powerful than dot notation. They allow any property names and variables. But they are also more cumbersome to write. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Abbreviazione per il valore di una proprietà +<<<<<<< HEAD Spesso usiamo delle variabili esistenti come valori per i nomi delle proprietà. +======= +In real code, we often use existing variables as values for property names. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio: @@ -247,7 +263,15 @@ let user = { Come già sappiamo, una variabile non può avere il nome uguale ad una parola chiave riservata al linguaggio come "for", "let", "return" etc. +<<<<<<< HEAD Ma per le proprietà degli oggetti, non ci sono restrizioni: +======= +## Property names limitations + +As we already know, a variable cannot have a name equal to one of the language-reserved words like "for", "let", "return" etc. + +But for an object property, there's no such restriction: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run // queste variabili sono tutte corrette @@ -318,7 +342,11 @@ alert( "blabla" in user ); // false, significa che user.blabla non esiste Da notare che alla sinistra di `in` deve esserci il *nome di una proprietà*. Questa, solitamente, è una stringa. +<<<<<<< HEAD Se omettiamo le virgolette attorno alla proprietà da cercare, verrà cercata una variabile con quel nome e verrà utilizzato il suo valore. Ad esempio: +======= +If we omit quotes, that means a variable should contain the actual name to be tested. For instance: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let user = { age: 30 }; @@ -348,7 +376,11 @@ Nel codice sopra, tecnicamente, la proprietà `obj.test` esiste. Quindi l'operat Situazioni come questa capitano raramente, perché solitamente non si assegna `undefined`. Si usa più comunemente `null` per valori "sconosciuti" o "vuoti". Quindi l'operatore `in` è più un ospite "esotico" nel codice. +<<<<<<< HEAD ## Il ciclo "for..in" +======= +## The "for..in" loop [#forin] +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Per attraversare tutte le chiavi di un oggetto, esiste una speciale forma di ciclo: `for..in`. Questo è completamente diverso da `for(;;)`. @@ -406,7 +438,11 @@ for (let code in codes) { */!* ``` +<<<<<<< HEAD L'oggetto può essere utilizzato per suggerire una lista di opzioni all'utente. Se stiamo sviluppando un sito dedicato al pubblico tedesco propbabilmente vorrano vedersi apparire come primo valore `49`. +======= +The object may be used to suggest a list of options to the user. If we're making a site mainly for a German audience then we probably want `49` to be the first. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Se proviamo ad eseguire il codice, vedremo un risultato totalmente inaspettato: @@ -418,6 +454,7 @@ I prefissi telefonici seguono un ordine crescente; questo accade perché sono nu ````smart header="Proprietà degli interi? Cos'è?" La "proprietà degli interi" è un termine che indica una stringa che può essere convertita da e ad un intero senza subire modifiche. +<<<<<<< HEAD Quindi "49" segue la proprietà degli interi, perché quando viene trasformato in un numero intero e riportato a stringa, rimane uguale. Ad esempio "+49" e "1.2" non lo sono: ```js run @@ -425,6 +462,16 @@ Quindi "49" segue la proprietà degli interi, perché quando viene trasformato i alert( String(Math.trunc(Number("49"))) ); // "49", rimane uguale alert( String(Math.trunc(Number("+49"))) ); // "49", è diverso da "+49" ⇒ non è un numero intero alert( String(Math.trunc(Number("1.2"))) ); // "1", è diverso da "1.2" ⇒ non è un numero intero +======= +So, `"49"` is an integer property name, because when it's transformed to an integer number and back, it's still the same. But `"+49"` and `"1.2"` are not: + +```js run +// Number(...) explicitly converts to a number +// Math.trunc is a built-in function that removes the decimal part +alert( String(Math.trunc(Number("49"))) ); // "49", same, integer property +alert( String(Math.trunc(Number("+49"))) ); // "49", not same "+49" ⇒ not integer property +alert( String(Math.trunc(Number("1.2"))) ); // "1", not same "1.2" ⇒ not integer property +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` ```` @@ -476,10 +523,16 @@ Per accedere ad una proprietà possiamo utilizzare: - La notazione puntata: `obj.property`. - La notazione con parentesi quadre `obj["property"]`. Questa notazione consente di accettare chiavi dalle variabili, come `obj[varWithKey]`. +<<<<<<< HEAD Operatori specifici: - Per cancellare una proprietà: `delete obj.prop`. - Per controllare se un una proprietà con un certo nome esiste: `"key" in obj`. - Per iterare un oggetto: `for(let key in obj)`. +======= +To access a property, we can use: +- The dot notation: `obj.property`. +- Square brackets notation `obj["property"]`. Square brackets allow taking the key from a variable, like `obj[varWithKey]`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Gli oggetti vengono assegnati e copiati per riferimento. In altre parole, la variabile non memorizza il "valore dell'oggetto", ma piuttosto un "riferimento" (indirizzo di memoria). Quindi copiando questa variabile o passandola come argomento ad una funzione, fornirà un riferimento all'oggetto e non una copia. Tutte le operazioni effettuate su un oggetto copiato per riferimento (come aggiungere/rimuovere proprietà) vengono effettuate sullo stesso oggetto. diff --git a/1-js/04-object-basics/02-object-copy/article.md b/1-js/04-object-basics/02-object-copy/article.md index 69d7f769a..ec8cdcd57 100644 --- a/1-js/04-object-basics/02-object-copy/article.md +++ b/1-js/04-object-basics/02-object-copy/article.md @@ -37,7 +37,11 @@ Ed ecco come viene effettivamente archiviata in memoria: L'oggetto è archiviato da qualche parte nella memoria (a destra nell'immagine), mentre la variabile `user` (a sinistra) contiene il "riferimento" ad esso. +<<<<<<< HEAD Potremmo immaginare la "variabile oggetto" `user`, come un foglio di carta con scritto l'indirizzo dell'oggetto. +======= +We may think of an object variable, such as `user`, like a sheet of paper with the address of the object on it. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Quando eseguiamo azioni con l'oggetto, ad es. leggere una proprietà `user.name`, il motore JavaScript guarda cosa c'è a quell'indirizzo ed esegue l'operazione sull'oggetto reale. @@ -101,6 +105,7 @@ alert( a == b ); // false Per confronti tra oggetti (Es. `obj1 > obj2`) o con primitivi (Es. `obj == 5`), gli oggetti vengono convertiti in primitivi. Vedremo molto presto come avviene questa conversione, anche se, a dire il vero, questo tipo di confronto è molto raro e generalmente è il risultato di un errore di programmazione. +<<<<<<< HEAD ## Clonazione e unione, Object.assign [#cloning-and-merging-object-assign] Come abbiamo detto, copiare una "variabile oggetto" crea un ulteriore riferimento allo stesso oggetto. @@ -235,6 +240,10 @@ Per implementare questa funzione possiamo usare la ricorsione. Oppure, per non r ````smart header="Gli oggetti dichiarati con const possono essere modificati" Un importante "side effect" della memorizzazione per riferimento è che un oggetto dichiarato con `const` *può* essere modificato. +======= +````smart header="Const objects can be modified" +An important side effect of storing objects as references is that an object declared as `const` *can* be modified. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Esempio: @@ -257,10 +266,210 @@ In altre parole, `const user` restituisce un errore solo se se proviamo a riasse Detto questo, se vogliamo veramente rendere invariabili le proprietà di un oggetto, possiamo farlo, ma con un metodo totalmente differente. Ne parleremo nel capitolo . ```` +<<<<<<< HEAD ## Riepilogo +======= +## Cloning and merging, Object.assign [#cloning-and-merging-object-assign] + +So, copying an object variable creates one more reference to the same object. + +But what if we need to duplicate an object? + +We can create a new object and replicate the structure of the existing one, by iterating over its properties and copying them on the primitive level. + +Like this: + +```js run +let user = { + name: "John", + age: 30 +}; + +*!* +let clone = {}; // the new empty object + +// let's copy all user properties into it +for (let key in user) { + clone[key] = user[key]; +} +*/!* + +// now clone is a fully independent object with the same content +clone.name = "Pete"; // changed the data in it + +alert( user.name ); // still John in the original object +``` + +We can also use the method [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign). + +The syntax is: + +```js +Object.assign(dest, ...sources) +``` + +- The first argument `dest` is a target object. +- Further arguments is a list of source objects. + +It copies the properties of all source objects into the target `dest`, and then returns it as the result. + +For example, we have `user` object, let's add a couple of permissions to it: + +```js run +let user = { name: "John" }; + +let permissions1 = { canView: true }; +let permissions2 = { canEdit: true }; + +*!* +// copies all properties from permissions1 and permissions2 into user +Object.assign(user, permissions1, permissions2); +*/!* + +// now user = { name: "John", canView: true, canEdit: true } +alert(user.name); // John +alert(user.canView); // true +alert(user.canEdit); // true +``` + +If the copied property name already exists, it gets overwritten: + +```js run +let user = { name: "John" }; + +Object.assign(user, { name: "Pete" }); + +alert(user.name); // now user = { name: "Pete" } +``` + +We also can use `Object.assign` to perform a simple object cloning: + +```js run +let user = { + name: "John", + age: 30 +}; + +*!* +let clone = Object.assign({}, user); +*/!* + +alert(clone.name); // John +alert(clone.age); // 30 +``` + +Here it copies all properties of `user` into the empty object and returns it. + +There are also other methods of cloning an object, e.g. using the [spread syntax](info:rest-parameters-spread) `clone = {...user}`, covered later in the tutorial. + +## Nested cloning + +Until now we assumed that all properties of `user` are primitive. But properties can be references to other objects. + +Like this: +```js run +let user = { + name: "John", + sizes: { + height: 182, + width: 50 + } +}; + +alert( user.sizes.height ); // 182 +``` + +Now it's not enough to copy `clone.sizes = user.sizes`, because `user.sizes` is an object, and will be copied by reference, so `clone` and `user` will share the same sizes: + +```js run +let user = { + name: "John", + sizes: { + height: 182, + width: 50 + } +}; + +let clone = Object.assign({}, user); + +alert( user.sizes === clone.sizes ); // true, same object + +// user and clone share sizes +user.sizes.width = 60; // change a property from one place +alert(clone.sizes.width); // 60, get the result from the other one +``` + +To fix that and make `user` and `clone` truly separate objects, we should use a cloning loop that examines each value of `user[key]` and, if it's an object, then replicate its structure as well. That is called a "deep cloning" or "structured cloning". There's [structuredClone](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone) method that implements deep cloning. + + +### structuredClone + +The call `structuredClone(object)` clones the `object` with all nested properties. + +Here's how we can use it in our example: + +```js run +let user = { + name: "John", + sizes: { + height: 182, + width: 50 + } +}; + +*!* +let clone = structuredClone(user); +*/!* + +alert( user.sizes === clone.sizes ); // false, different objects + +// user and clone are totally unrelated now +user.sizes.width = 60; // change a property from one place +alert(clone.sizes.width); // 50, not related +``` + +The `structuredClone` method can clone most data types, such as objects, arrays, primitive values. + +It also supports circular references, when an object property references the object itself (directly or via a chain or references). + +For instance: + +```js run +let user = {}; +// let's create a circular reference: +// user.me references the user itself +user.me = user; + +let clone = structuredClone(user); +alert(clone.me === clone); // true +``` + +As you can see, `clone.me` references the `clone`, not the `user`! So the circular reference was cloned correctly as well. + +Although, there are cases when `structuredClone` fails. + +For instance, when an object has a function property: + +```js run +// error +structuredClone({ + f: function() {} +}); +``` + +Function properties aren't supported. + +To handle such complex cases we may need to use a combination of cloning methods, write custom code or, to not reinvent the wheel, take an existing implementation, for instance [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) from the JavaScript library [lodash](https://lodash.com). + +## Summary +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Gli oggetti sono assegnati e copiati per riferimento. In altre parole una variabile non contiene il "valore oggetto" ma un "riferimento" (indirizzo in memoria) di quel valore. Quindi copiando tale variabile o passandola come argomento di una funzione si copia quel riferimento, non l'oggetto stesso. Tutte le operazioni su un riferimento duplicato (come aggiungere o rimuovere proprietà) hanno effetto sul medesimo oggetto. +<<<<<<< HEAD Per creare una "vera copia" (clonare) effettuare una cosiddetta "shallow copy" (copia superficiale) con `Object.assign`(gli oggetti nidificati vengo copiati per riferimento), oppure un "deep cloning" (copia profonda) con funzioni tipo [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). +======= +To make a "real copy" (a clone) we can use `Object.assign` for the so-called "shallow copy" (nested objects are copied by reference) or a "deep cloning" function `structuredClone` or use a custom cloning implementation, such as [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/1-js/04-object-basics/03-garbage-collection/article.md b/1-js/04-object-basics/03-garbage-collection/article.md index c73b62c12..41687925e 100644 --- a/1-js/04-object-basics/03-garbage-collection/article.md +++ b/1-js/04-object-basics/03-garbage-collection/article.md @@ -74,7 +74,11 @@ Ora se facciamo: user = null; ``` +<<<<<<< HEAD ...L'oggetto rimane raggiungibile tramite `admin`, quindi è in memoria. Se sovrascriviamo anche `admin`, allora verrà rimosso. +======= +...Then the object is still reachable via `admin` global variable, so it must stay in memory. If we overwrite `admin` too, then it can be removed. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Oggetti interconnessi @@ -169,11 +173,19 @@ Il primo step sta nel marcare le radici: ![](garbage-collection-2.svg) +<<<<<<< HEAD Poi vengono marcari i loro riferimenti: ![](garbage-collection-3.svg) ...E i loro riferimenti, finchè non si esauriscono: +======= +Then we follow their references and mark referenced objects: + +![](garbage-collection-3.svg) + +...And continue to follow further references, while possible: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ![](garbage-collection-4.svg) @@ -183,13 +195,23 @@ Ora gli oggetti che non sono stati visitati vengono considerati irraggiungibili Questo è il concetto che sta dietro il funzionamento del Garbage collector. +<<<<<<< HEAD JavaScript applica diverse ottimizzazioni per renderlo più rapido. +======= +That's the concept of how garbage collection works. JavaScript engines apply many optimizations to make it run faster and not introduce any delays into the code execution. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Alcune delle ottimizzazioni: +<<<<<<< HEAD - **Raggruppamento generazionale** -- gli oggetti vengono divisi in due gruppi: "nuovi" e "vecchi". Molti oggetti vengono costruiti, eseguono il proprio lavoro e muoiono, quindi possono essere rimossi rapidamente. Quelli che vivono abbastanza al lungo vengono considerati come "vecchi" e verranno controllati con minore intensità - **Raggruppamento incrementale** -- se ci sono molti oggetti, e ci mettessimo a controllare interi gruppi per marcarli, si perderebbe molto tempo, questo ritardo diventerebbe visibile durante l'esecuzione. Quindi i motori JavaScript tentano di dividere il processo in diverse parti. Questi pezzi vengono controllati uno per uno, separatamente. E' richiesto l'utilizzo di un registro per tenere traccia dei cambiamenti, in cambio avremmo tanti piccoli ritardi piuttosto che uno singolo ma enorme. - **Raggruppamento per inattività** -- il garbage collector cerca di eseguire i suoi processi solo nei momenti in cui la CPU è inattiva, per ridurre al minimo possibile i ritardi durante l'esecuzione. +======= +- **Generational collection** -- objects are split into two sets: "new ones" and "old ones". In typical code, many objects have a short life span: they appear, do their job and die fast, so it makes sense to track new objects and clear the memory from them if that's the case. Those that survive for long enough, become "old" and are examined less often. +- **Incremental collection** -- if there are many objects, and we try to walk and mark the whole object set at once, it may take some time and introduce visible delays in the execution. So the engine splits the whole set of existing objects into multiple parts. And then clear these parts one after another. There are many small garbage collections instead of a total one. That requires some extra bookkeeping between them to track changes, but we get many tiny delays instead of a big one. +- **Idle-time collection** -- the garbage collector tries to run only while the CPU is idle, to reduce the possible effect on the execution. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ci sono altre ottimizzazioni per ottimizzare i processi del Garbage collector. Anche se mi piacerebbe poterli spiegare in dettaglio, sono costretto a fermarmi, poiché le varia ottimizzazioni dipendono dai motori che vengono utilizzati. Inoltre, i motori cambiano, si aggiornano e diventano sempre più "avanzati". Quindi se siete realmente interessati, vi lascio qualche link sotto. @@ -197,9 +219,15 @@ Ci sono altre ottimizzazioni per ottimizzare i processi del Garbage collector. A Le principali cose da conoscere: +<<<<<<< HEAD - Il processo di Garbage collection viene eseguito automaticamente. Non possiamo forzarlo o bloccarlo. - Gli oggetti vengono mantenuti in memoria solo finché risultano raggiungibili. - Essere riferimento di qualunque altro oggetto non significa essere raggiungibili (dalla radice): un gruppo di oggetti possono diventare irraggiungibili in un solo colpo. +======= +- Garbage collection is performed automatically. We cannot force or prevent it. +- Objects are retained in memory while they are reachable. +- Being referenced is not the same as being reachable (from a root): a pack of interlinked objects can become unreachable as a whole, as we've seen in the example above. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 I motori moderni applicano algoritmi avanzati di garbage collection. @@ -207,6 +235,14 @@ Un buon libro "The Garbage Collection Handbook: The Art of Automatic Memory Mana Se conoscete la programmazione a basso livello, informazioni più dettagliate riguardo il Garbage collector V8 sono disponibili nell'articolo [A tour of V8: Garbage Collection](http://jayconrod.com/posts/55/a-tour-of-v8-garbage-collection). +<<<<<<< HEAD [V8 blog](http://v8project.blogspot.com/) pubblica articoli riguardo i cambiamenti nella gestione della memoria. Ovviamente per apprendere il processo di garbage collection, è fortemente consigliato imparare il funzionamento del garbage collector V8 leggendo il blog [Vyacheslav Egorov](http://mrale.ph) che ha lavorato come ingegnere per lo sviluppo del V8. Vi dico "V8" perché è quello più utilizzato e maggiormente spiegato su internet. Per gli altri motori, gli approcci sono simili, ci sono alcune sottili differenze. Le conoscenze profonde dei motori sono importanti quando necessitate di ottimizzazioni a basso livello. Potrebbe essere un buon traguardo dopo essere diventati familiari con il linguaggio. +======= +If you are familiar with low-level programming, more detailed information about V8's garbage collector is in the article [A tour of V8: Garbage Collection](https://jayconrod.com/posts/55/a-tour-of-v8-garbage-collection). + +The [V8 blog](https://v8.dev/) also publishes articles about changes in memory management from time to time. Naturally, to learn more about garbage collection, you'd better prepare by learning about V8 internals in general and read the blog of [Vyacheslav Egorov](https://mrale.ph) who worked as one of the V8 engineers. I'm saying: "V8", because it is best covered by articles on the internet. For other engines, many approaches are similar, but garbage collection differs in many aspects. + +In-depth knowledge of engines is good when you need low-level optimizations. It would be wise to plan that as the next step after you're familiar with the language. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/1-js/04-object-basics/04-object-methods/7-calculator/task.md b/1-js/04-object-basics/04-object-methods/7-calculator/task.md index de0bab7c8..99a754b12 100644 --- a/1-js/04-object-basics/04-object-methods/7-calculator/task.md +++ b/1-js/04-object-basics/04-object-methods/7-calculator/task.md @@ -6,9 +6,15 @@ importance: 5 Create un oggetto `calculator` con tre metodi: +<<<<<<< HEAD - `read()` richiede tramite prompt due valori e li salva come proprietà dell'oggetto. - `sum()` ritorna la somma dei valori salvati. - `mul()` moltiplica i valori salvati e ritorna il risultato. +======= +- `read()` prompts for two values and saves them as object properties with names `a` and `b` respectively. +- `sum()` returns the sum of saved values. +- `mul()` multiplies saved values and returns the result. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js let calculator = { @@ -21,4 +27,3 @@ alert( calculator.mul() ); ``` [demo] - diff --git a/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/solution.js b/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/solution.js index e98fe6410..a35c009cc 100644 --- a/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/solution.js +++ b/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/solution.js @@ -11,5 +11,6 @@ let ladder = { }, showStep: function() { alert(this.step); + return this; } }; \ No newline at end of file diff --git a/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/test.js b/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/test.js index a2b17fcc4..b4f2459b7 100644 --- a/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/test.js +++ b/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/test.js @@ -32,6 +32,14 @@ describe('Ladder', function() { it('down().up().up().up() ', function() { assert.equal(ladder.down().up().up().up().step, 2); }); + + it('showStep() should return this', function() { + assert.equal(ladder.showStep(), ladder); + }); + + it('up().up().down().showStep().down().showStep()', function () { + assert.equal(ladder.up().up().down().showStep().down().showStep().step, 0) + }); after(function() { ladder.step = 0; diff --git a/1-js/04-object-basics/04-object-methods/8-chain-calls/task.md b/1-js/04-object-basics/04-object-methods/8-chain-calls/task.md index 14205e239..413b70ab3 100644 --- a/1-js/04-object-basics/04-object-methods/8-chain-calls/task.md +++ b/1-js/04-object-basics/04-object-methods/8-chain-calls/task.md @@ -4,7 +4,11 @@ importance: 2 # Concatenazione +<<<<<<< HEAD Qui abbiamo un oggetto `ladder` che ci consente di salire e scendere: +======= +There's a `ladder` object that allows you to go up and down: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js let ladder = { @@ -21,7 +25,11 @@ let ladder = { }; ``` +<<<<<<< HEAD Ora, se abbiamo bisogno di eseguire più chiamate in sequenza, possiamo: +======= +Now, if we need to make several calls in sequence, we can do it like this: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js ladder.up(); @@ -32,10 +40,18 @@ ladder.down(); ladder.showStep(); // 0 ``` +<<<<<<< HEAD Modificare il codice di `up`, `down` e `showStep` per rendere le chiamate concatenabili, come in questo esempio: +======= +Modify the code of `up`, `down`, and `showStep` to make the calls chainable, like this: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js ladder.up().up().down().showStep().down().showStep(); // shows 1 then 0 ``` +<<<<<<< HEAD Questo approccio è largamente utilizzato dalle librerie JavaScript. +======= +Such an approach is widely used across JavaScript libraries. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/1-js/04-object-basics/04-object-methods/article.md b/1-js/04-object-basics/04-object-methods/article.md index bec5a5e71..8b423d587 100644 --- a/1-js/04-object-basics/04-object-methods/article.md +++ b/1-js/04-object-basics/04-object-methods/article.md @@ -51,7 +51,7 @@ let user = { // prima la dichiariamo function sayHi() { alert("Hello!"); -}; +} // poi la aggiungiamo come metodo user.sayHi = sayHi; @@ -90,7 +90,11 @@ user = { Come possiamo notare, si può omettere `"function"` e scrivere solamente `sayHi()`. +<<<<<<< HEAD A dire la verità, la notazione non è proprio uguale. Ci sono delle sottili differenze legate all'ereditarietà degli oggetti (le studieremo più avanti), ma per ora non hanno importanza. Nella maggior parte dei casi la forma breve viene preferita. +======= +To tell the truth, the notations are not fully identical. There are subtle differences related to object inheritance (to be covered later), but for now they do not matter. In almost all cases, the shorter syntax is preferred. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## "this" nei metodi diff --git a/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md b/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md index 5f7a88939..2e086830b 100644 --- a/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md +++ b/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md @@ -10,8 +10,8 @@ E' possibile creare due funzioni `A` e `B` tali che `new A()==new B()`? function A() { ... } function B() { ... } -let a = new A; -let b = new B; +let a = new A(); +let b = new B(); alert( a == b ); // true ``` diff --git a/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md index cd8c4b5e3..fca13508c 100644 --- a/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md +++ b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md @@ -6,9 +6,15 @@ importance: 5 Scrivete un costruttore `Calculator` che crea oggetti con 3 metodi: +<<<<<<< HEAD - `read()` richiede due valori utilizzando `prompt` e li memorizza nelle proprietà dell'oggetto. - `sum()` ritorna la somma delle proprietà. - `mul()` ritorna il prodotto delle proprietà. +======= +- `read()` prompts for two values and saves them as object properties with names `a` and `b` respectively. +- `sum()` returns the sum of these properties. +- `mul()` returns the multiplication product of these properties. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio: diff --git a/1-js/04-object-basics/06-constructor-new/article.md b/1-js/04-object-basics/06-constructor-new/article.md index 7286f0359..e7f9cde28 100644 --- a/1-js/04-object-basics/06-constructor-new/article.md +++ b/1-js/04-object-basics/06-constructor-new/article.md @@ -1,6 +1,10 @@ # Costruttore, operatore "new" +<<<<<<< HEAD La sintassi `{...}` ci consente di creare un oggetto. Ma spesso abbiamo bisogno di creare multipli oggetti simili, come ad esempio più utenti, oggetti del menu e molto altro. +======= +The regular `{...}` syntax allows us to create one object. But often we need to create many similar objects, like multiple users or menu items and so on. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Questo può essere fatto utilizzando un costruttore e l'operatore `"new"`. @@ -172,8 +176,13 @@ alert(new SmallUser().name); //John Solitamente i costruttori non hanno l'istruzione `return`. Abbiamo comunque riportato, per completezza, quel che succede se si tenta di ritornare un oggetto. +<<<<<<< HEAD ````smart header="Omettere le parentesi" Possiamo anche omettere le parentesi dopo `new`, se non ci sono argomenti: +======= +````smart header="Omitting parentheses" +By the way, we can omit parentheses after `new`: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js let user = new User; // <-- no parentheses diff --git a/1-js/04-object-basics/07-optional-chaining/article.md b/1-js/04-object-basics/07-optional-chaining/article.md index 367cb9d9f..73849513e 100644 --- a/1-js/04-object-basics/07-optional-chaining/article.md +++ b/1-js/04-object-basics/07-optional-chaining/article.md @@ -26,14 +26,22 @@ Questo è il risultato che ci si aspetta. JavaScript funziona in questo modo. Se Nella maggior parte dei casi, preferiremmo avere `undefined` piuttosto di un errore (in questo caso con il significato "nessuna via"). +<<<<<<< HEAD ... Un altro esempio. Il metodo `document.querySelector('.elem')` ritorna un oggetto che corrisponde ad un elemento della pagina web, che ritorna `null` quando l'elemento non esiste. +======= +...and another example. In Web development, we can get an object that corresponds to a web page element using a special method call, such as `document.querySelector('.elem')`, and it returns `null` when there's no such element. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run // document.querySelector('.elem') è null se non esiste l'elemento let html = document.querySelector('.elem').innerHTML; // errore se è null ``` +<<<<<<< HEAD Di nuovo, se un elemento non esiste, otterremo un errore nel tentativo di accedere a `.innerHTML` di `null`. In alcuni casi, in cui l'assenza di un elemento è normale, vorremo evitare l'errore e accettare come risultato `html = null`. +======= +Once again, if the element doesn't exist, we'll get an error accessing `.innerHTML` property of `null`. And in some cases, when the absence of the element is normal, we'd like to avoid the error and just accept `html = null` as the result. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Come possiamo farlo? @@ -45,11 +53,27 @@ let user = {}; alert(user.address ? user.address.street : undefined); ``` +<<<<<<< HEAD Funziona, nessun errore... Ma è poco elegante. Come potete vedere , `"user.address"` appare due volte nel codice. Per proprietà molto più annidate, potrebbe diventare un problema, in quanto saranno necessarie molte più ripetizioni. Ad esempio, proviamo a recuperare il valore di `user.address.street.name`. Dobbiamo verificare sia `user.address` che `user.address.street`: +======= +It works, there's no error... But it's quite inelegant. As you can see, the `"user.address"` appears twice in the code. + +Here's how the same would look for `document.querySelector`: + +```js run +let html = document.querySelector('.elem') ? document.querySelector('.elem').innerHTML : null; +``` + +We can see that the element search `document.querySelector('.elem')` is actually called twice here. Not good. + +For more deeply nested properties, it becomes even uglier, as more repetitions are required. + +E.g. let's get `user.address.street.name` in a similar fashion. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js let user = {}; // l'utente non ha address @@ -59,7 +83,11 @@ alert(user.address ? user.address.street ? user.address.street.name : null : nul Questo è semplicemente terribile, un codice del genere potrebbe essere difficile da comprendere. +<<<<<<< HEAD Ci sarebbe un modo migliore per riscriverlo, utilizzando l'operatore `&&`: +======= +There's a little better way to write it, using the `&&` operator: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let user = {}; // l'utente non ha address @@ -93,7 +121,17 @@ alert( user?.address?.street ); // undefined (nessun errore) Il codice è corto e pulito, non c'è alcuna duplicazione. +<<<<<<< HEAD Leggere l'indirizzo con `user?.address` funzionerebbe anche se l'oggetto `user` non esistesse: +======= +Here's an example with `document.querySelector`: + +```js run +let html = document.querySelector('.elem')?.innerHTML; // will be undefined, if there's no element +``` + +Reading the address with `user?.address` works even if `user` object doesn't exist: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let user = null; @@ -109,9 +147,15 @@ Ad esempio in `user?.address.street.name` il costrutto `?.` permette alla propri ```warn header="Non abusate della concatenazione opzionale" Dovremmo utilizzare `?.` solamente quando va bene che una proprietà possa non esistere. +<<<<<<< HEAD Ad esempio, considerando la logica del nostro codice, l'oggetto `user` deve necessariamente esistere, mentre `address` è opzionale, quindi dovremmo scrivere `user.address?.street`, non `user?.address?.street`. Quindi, se `user` dovesse essere `undefined` per errore, otterremo un errore e potremmo sistemarlo. Altrimenti, gli errori di programmazione potrebbero essere silenziati in modo non appropriato, rendendo il debug molto difficile. +======= +For example, if according to our code logic `user` object must exist, but `address` is optional, then we should write `user.address?.street`, but not `user?.address?.street`. + +Then, if `user` happens to be undefined, we'll see a programming error about it and fix it. Otherwise, if we overuse `?.`, coding errors can be silenced where not appropriate, and become more difficult to debug. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` ````warn header="La variabile che precede `?.` deve essere dichiarata" @@ -128,7 +172,11 @@ La variabile deve essere dichiarata (ad esempio come `let/const/var user` o come Come detto in precedenza, il costrutto `?.` interrompe immediatamente (manda in "corto circuito") la valutazione se la proprietà a destra non esiste. +<<<<<<< HEAD Quindi, nel caso ci siano ulteriori chiamate a funzione o side-effects, questi non verranno eseguiti. +======= +So, if there are any further function calls or operations to the right of `?.`, they won't be made. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio: @@ -136,7 +184,11 @@ Ad esempio: let user = null; let x = 0; +<<<<<<< HEAD user?.sayHi(x++); // non esiste "sayHi", quindi l'esecuzione non raggiungerà x++ +======= +user?.sayHi(x++); // no "user", so the execution doesn't reach sayHi call and x++ +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 alert(x); // 0, valore non incrementato ``` @@ -163,6 +215,7 @@ userAdmin.admin?.(); // I am admin */!* *!* +<<<<<<< HEAD userGuest.admin?.(); // niente (il metodo non esiste) */!* ``` @@ -170,6 +223,15 @@ userGuest.admin?.(); // niente (il metodo non esiste) Qui, in entrambe le righe, come prima cosa abbiamo utilizzato il punto (`user1.admin`) per ottenere la proprietà `admin`, poiché l'oggetto `user` deve necessariamente esistere, quindi l'accesso è sicuro. Successivamente `?.()` controlla la parte sinistra: se la funzione `admin` esiste, allora viene eseguita (ciò che accade con `user1`). Altrimenti (con `user2`) la valutazione si interrompe senza errori. +======= +userGuest.admin?.(); // nothing happens (no such method) +*/!* +``` + +Here, in both lines we first use the dot (`userAdmin.admin`) to get `admin` property, because we assume that the `user` object exists, so it's safe read from it. + +Then `?.()` checks the left part: if the `admin` function exists, then it runs (that's so for `userAdmin`). Otherwise (for `userGuest`) the evaluation stops without errors. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 La sintassi `?.` funziona anche con le parentesi `[]` (invece del punto `.`). Come nei casi precedenti, possiamo accedere con sicurezza alla proprietà di un oggetto che potrebbe non esistere. @@ -180,7 +242,7 @@ let user1 = { firstName: "John" }; -let user2 = null; +let user2 = null; alert( user1?.[key] ); // John alert( user2?.[key] ); // undefined @@ -192,18 +254,30 @@ Possiamo anche utilizzare `?.` con `delete`: delete user?.name; // cancella user.name se l'utente esiste ``` +<<<<<<< HEAD ````warn header="Possiamo utilizzare `?.` per l'accesso e la rimozione sicura, ma non per la scrittura" La concatenazione opzionale `?.` non ha alcun significato alla sinistra di un'assegnazione. +======= +````warn header="We can use `?.` for safe reading and deleting, but not writing" +The optional chaining `?.` has no use on the left side of an assignment. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio: ```js run let user = null; +<<<<<<< HEAD user?.name = "John"; // Errore, non funziona // poiché valuta undefined = "John" ``` Non è cosi intelligente. +======= +user?.name = "John"; // Error, doesn't work +// because it evaluates to: undefined = "John" +``` + +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```` ## Riepilogo @@ -218,4 +292,8 @@ Come possiamo vedere, le tre forme sono semplici da utilizzare. Il costrutto `?. La concatenazione di `?.` permette di accedere in sicurezza a proprietà annidate. +<<<<<<< HEAD In ogni caso, dovremmo applicare `?.` con prudenza, solamente nei casi in cui è accettabile che la parte sinistra possa non esistere. In questo modo evitiamo di nascondere errori di programmazione, nel caso ce ne siano. +======= +Still, we should apply `?.` carefully, only where it's acceptable, according to our code logic, that the left part doesn't exist. So that it won't hide programming errors from us, if they occur. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/1-js/04-object-basics/08-symbol/article.md b/1-js/04-object-basics/08-symbol/article.md index 19d88c15e..20e27a1a2 100644 --- a/1-js/04-object-basics/08-symbol/article.md +++ b/1-js/04-object-basics/08-symbol/article.md @@ -1,9 +1,22 @@ # Il tipo Symbol +<<<<<<< HEAD Secondo le specifiche, le chiavi delle proprietà di un oggetto possono essere di tipo stringa o di tipo symbol("simbolo"). Non sono accettati numeri o valori booleani, solamente stringhe e symbol. Finora abbiamo utilizzato solo stringhe. Ora proviamo a vedere i vantaggi forniti dal tipo symbol. +======= +By specification, only two primitive types may serve as object property keys: + +- string type, or +- symbol type. + +Otherwise, if one uses another type, such as number, it's autoconverted to string. So that `obj[1]` is the same as `obj["1"]`, and `obj[true]` is the same as `obj["true"]`. + +Until now we've been using only strings. + +Now let's explore symbols, see what they can do for us. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Symbol @@ -12,18 +25,29 @@ Il valore "Symbol" rappresenta un identificatore univoco. Un valore di questo tipo può essere creato usando `Symbol()`: ```js +<<<<<<< HEAD // id è un nuovo symbol let id = Symbol(); ``` Al momento della creazione, possiamo anche fornire una descrizione al symbol (chiamata nome del symbol), utile per il debugging: +======= +let id = Symbol(); +``` + +Upon creation, we can give symbols a description (also called a symbol name), mostly useful for debugging purposes: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js // id è un symbol con descrizione "id" let id = Symbol("id"); ``` +<<<<<<< HEAD I Symbol garantiscono di essere unici. Anche se creiamo più simboli con la stessa descrizione, saranno comunque valori differenti. La descrizione è utile solamente come etichetta, non ha effetto su nulla. +======= +Symbols are guaranteed to be unique. Even if we create many symbols with exactly the same description, they are different values. The description is just a label that doesn't affect anything. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio, qui abbiamo due simboli con la stessa descrizione -- ma non sono uguali: @@ -38,8 +62,15 @@ alert(id1 == id2); // false Se conosci Ruby, od altri linguaggi che possiedono la keyword "symbol", fai attenzione a non confonderti. I symbol in JavaScript sono differenti. +<<<<<<< HEAD ````warn header="I symbol non si auto-convertono a stringa" Molti valori in JavaScript supportano la conversione implicita a stinga. Ad esempio, possiamo utilizzare `alert` con quasi tutti i valori, e funzionerà ugualmente. Symbol è un tipo speciale, non verrà convertito. +======= +So, to summarize, a symbol is a "primitive unique value" with an optional description. Let's see where we can use them. + +````warn header="Symbols don't auto-convert to a string" +Most values in JavaScript support implicit conversion to a string. For instance, we can `alert` almost any value, and it will work. Symbols are special. They don't auto-convert. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio, questo `alert` vi mostrerà un errore: @@ -53,6 +84,11 @@ Questo è un "controllo del linguaggio" per prevenire pasticci, perché le strin Se vogliamo veramente mostrare un symbol, dobbiamo convertirlo esplicitamente utilizzando `.toString()`: +<<<<<<< HEAD +======= +If we really want to show a symbol, we need to explicitly call `.toString()` on it, like here: + +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let id = Symbol("id"); *!* @@ -60,7 +96,11 @@ alert(id.toString()); // Symbol(id), ora funziona */!* ``` +<<<<<<< HEAD Oppure usare la proprietà symbol.description per mostrare solo la descrizione: +======= +Or get `symbol.description` property to show the description only: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let id = Symbol("id"); @@ -72,7 +112,12 @@ alert(id.description); // id ## Proprietà "nascoste" +<<<<<<< HEAD Symbol ci consente di creare delle proprietà "nascoste" dentro un oggetto, che nessun'altra parte del codice potrà leggere o modificare. +======= + +Symbols allow us to create "hidden" properties of an object, that no other part of code can accidentally access or overwrite. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio, se stiamo lavorando con l'oggetto `user`, che appartiene a un codice di terze parti, e vogliamo aggiungere identificatore. @@ -90,9 +135,15 @@ alert( user[id] ); // possiamo accedere ai dati utilizzando il symbol come chiav Qual'è il beneficio di utilizzare `Symbol("id")` piuttosto che `"id"`? +<<<<<<< HEAD Poiché l'oggetto `user` appartiene a un altro codice che lo utilizza, non dovremmo aggiungervi alcun campo, non è sicuro. Ma un *symbol* non è accessibile accidentalmente, il codice di terze parti probabilmente non lo vedrà nemmeno, quindi andrà tutto bene. Inoltre, immagina che un altro script necessiti di avere il proprio identificatore all'interno di `user`. Potrebbe essere un'altra libreria JavaScript, e gli script sarebbero completamente inconsapevoli l'uno dell'altro. +======= +As `user` objects belong to another codebase, it's unsafe to add fields to them, since we might affect pre-defined behavior in that other codebase. However, symbols cannot be accessed accidentally. The third-party code won't be aware of newly defined symbols, so it's safe to add symbols to the `user` objects. + +Also, imagine that another script wants to have its own identifier inside `user`, for its own purposes. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Quindi ogni script può creare il suo `Symbol("id")`: @@ -155,8 +206,13 @@ let user = { for (let key in user) alert(key); // name, age (nessun symbol) */!* +<<<<<<< HEAD // l'accesso diretto al symbol funziona alert( "Direct: " + user[id] ); +======= +// the direct access by the symbol works +alert( "Direct: " + user[id] ); // Direct: 123 +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` Anche [Object.keys(user)](mdn:js/Object/keys) li ignora. Questo fa parte del principio generale di occultazione delle proprietà symbol. Se uno script esterno o una libreria eseguisse un ciclo sul nostro oggetto, non avrebbe inaspettatamente accesso a una proprietà di tipo symbol. @@ -204,12 +260,20 @@ I symbols dentro il registro vengono chiamati *symbol globali*. Se abbiamo bisog ```smart header="Assomigliano a Ruby" In alcuni linguaggi di programmazione, come Ruby, c'è un solo symbol per nome. +<<<<<<< HEAD In JavaScript, come possiamo vedere, questo è vero solo per i symbol globali. +======= +In JavaScript, as we can see, that's true for global symbols. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` ### Symbol.keyFor +<<<<<<< HEAD Per i symbol globali, non esiste solo `Symbol.for(key)` per accedere ad un symbol, è possibile anche la chiamata inversa: `Symbol.keyFor(sym)`, che fa l'opposto: ritorna il nome di un symbol globale. +======= +We have seen that for global symbols, `Symbol.for(key)` returns a symbol by name. To do the opposite -- return a name by global symbol -- we can use: `Symbol.keyFor(sym)`: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio: @@ -225,7 +289,11 @@ alert( Symbol.keyFor(sym2) ); // id La funzione `Symbol.keyFor` internamente utilizza il registro globale dei symbol per cercare la chiave del symbol. Quindi non avrà alcun effetto per symbol non globali. Se gli viene passato un symbol non globale, non sarà in grado di trovarlo e ritornerà `undefined`. +<<<<<<< HEAD Detto questo, ogni symbol possiede una proprietà `description`. +======= +That said, all symbols have the `description` property. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio: @@ -265,10 +333,20 @@ I symbol sono sempre differenti, anche se hanno lo stesso nome. Se abbiamo bisog I symbol hanno due principali ambiti d'uso: +<<<<<<< HEAD 1. "Nascondere" le proprietà di un oggetto. Se vogliamo aggiungere una proprietà ad un oggetto che "appartiene" ad un altro script (o libreria), possiamo creare un symbol ed utilizzarlo come chiave della proprietà. Una proprietà di tipo symbol non sarà disponibile in un `for..in`, quindi non sarà mai resa visibile. Non sarà nemmeno accessibile direttamente poiché uno script diverso non potrà avere i nostri symbol. Quindi la proprietà sarà protetta dall'uso accidentale o dalla sovrascrittura. +======= +1. "Hidden" object properties. + + If we want to add a property into an object that "belongs" to another script or a library, we can create a symbol and use it as a property key. A symbolic property does not appear in `for..in`, so it won't be accidentally processed together with other properties. Also it won't be accessed directly, because another script does not have our symbol. So the property will be protected from accidental use or overwrite. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Possiamo quindi aggiungere "di nascosto" una proprietà in un oggetto se ne abbiamo la necessità, senza che nessun altro possa vederla, usando proprietà di tipo symbol. 2. Ci sono diversi symbol di sistema utilizzati da JavaScript che sono accessibili come `Symbol.*`. Possiamo utilizzarli per modificare alcune caratteristiche native. Ad esempio, più avanti nella guida utilizzeremo `Symbol.iterator` per [iterables](info:iterable), `Symbol.toPrimitive` per impostare la [conversione da oggetto a primitivo](info:object-toprimitive). +<<<<<<< HEAD Tecnicamente i symbol non sono nascosti al 100%. C'è un metodo nativo in JavaScript [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) che ci consente di ottenere tutti i symbol. Esiste anche un metodo chiamato [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) che ritorna *tutte* le chiavi di un oggetto incluse quelle di tipo symbol. Quindi non sono realmente invisibili. Ma la maggior parte delle librerie, delle funzioni native e dei costrutti non utilizzano questi metodi. +======= +Technically, symbols are not 100% hidden. There is a built-in method [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) that allows us to get all symbols. Also there is a method named [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) that returns *all* keys of an object including symbolic ones. But most libraries, built-in functions and syntax constructs don't use these methods. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index 8f53f0324..e331a0868 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -3,15 +3,27 @@ Cosa accade quando degli oggetti vengono sommati `obj1 + obj2`, sottratti `obj1 - obj2` o mostrati tramite `alert(obj)`? +<<<<<<< HEAD JavaScript non consente di personalizzare come gli operatori lavorano sugli oggetti. Diversamente da alcuni linguaggi di programmazione, come Ruby o C++, non implementa nessun metodo speciale per gestire l'addizione (o altri operatori). +======= +JavaScript doesn't allow you to customize how operators work on objects. Unlike some other programming languages, such as Ruby or C++, we can't implement a special object method to handle addition (or other operators). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Nel caso si effettuassero queste operazioni, gli oggetti vengono convertiti automaticamente in primitivi e le operazioni vengo effettuate su questi, restituendo poi un valore anch'esso primitivo. +<<<<<<< HEAD Questa è un'importante limitazione, in quanto il risultato di `obj1 + obj2` non può essere un altro oggetto! +======= +That's an important limitation: the result of `obj1 + obj2` (or another math operation) can't be another object! +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Per esempio. non possiamo creare oggetti che rappresentano vettori o matrici (o archievements o altro), sommarli ed aspettarsi un oggetto "somma" come risultato. Tali architetture non sono contemplate. +<<<<<<< HEAD Quindi, poiché non possiamo intervenire, non c'è matematica con oggetti in progetti reali. Quando succede, di solito è a causa di un errore di codice. +======= +So, because we can't technically do much here, there's no maths with objects in real projects. When it happens, with rare exceptions, it's because of a coding mistake. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 In questo capitolo tratteremo come un oggetto si converte in primitivo e come personalizzarlo. @@ -24,6 +36,7 @@ Abbiamo due scopi: Nel capitolo abbiamo visto le regole per le conversioni dei primitivi di tipo numerico, stringa e booleano. Però abbiamo lasciato un vuoto riguardo gli oggetti. Adesso che conosciamo i metodi e i symbol diventa più semplice parlarne. +<<<<<<< HEAD 1. Tutti gli oggetti sono `true` in contesto booleano. Ci sono solamente conversioni numeriche e a stringhe. 2. La conversione numerica avviene quando eseguiamo una sottrazione tra oggetti oppure applichiamo funzioni matematiche. Ad esempio, gli oggetti `Date` (che studieremo nel capitolo ) possono essere sottratti, ed il risultato di `date1 - date2` è la differenza di tempo tra le due date. 3. Le conversioni a stringa -- solitamente avvengono quando mostriamo un oggetto, come in `alert(obj)` e in altri contesti simili. @@ -33,6 +46,21 @@ Possiamo perfezionare la conversione di stringhe e numeri, utilizzando metodi og Esistono tre varianti di conversione del tipo, che si verificano in varie situazioni. Sono chiamate "hints", come descritto in [specification](https://tc39.github.io/ecma262/#sec-toprimitive): +======= +1. There's no conversion to boolean. All objects are `true` in a boolean context, as simple as that. There exist only numeric and string conversions. +2. The numeric conversion happens when we subtract objects or apply mathematical functions. For instance, `Date` objects (to be covered in the chapter ) can be subtracted, and the result of `date1 - date2` is the time difference between two dates. +3. As for the string conversion -- it usually happens when we output an object with `alert(obj)` and in similar contexts. + +We can implement string and numeric conversion by ourselves, using special object methods. + +Now let's get into technical details, because it's the only way to cover the topic in-depth. + +## Hints + +How does JavaScript decide which conversion to apply? + +There are three variants of type conversion, that happen in various situations. They're called "hints", as described in the [specification](https://tc39.github.io/ecma262/#sec-toprimitive): +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 `"string"` : Un'operazione di conversione oggetto a stringa, avviene quando un operazione si aspetta una stringa, come `alert`: @@ -60,10 +88,18 @@ Sono chiamate "hints", come descritto in [specification](https://tc39.github.io/ let greater = user1 > user2; ``` + Most built-in mathematical functions also include such conversion. + `"default"` : Utilizzata in casi rari quando l'operatore "non è sicuro" del tipo da aspettarsi. +<<<<<<< HEAD Ad esempio, la somma binaria `+` può essere utilizzata sia con le stringhe (per concatenarle) sia con i numeri (per eseguire la somma), quindi sia la conversione a stringa che quella a tipo numerico potrebbero andare bene. Oppure quando un oggetto viene confrontato usando `==` con una stringa, un numero o un symbol. +======= + For instance, binary plus `+` can work both with strings (concatenates them) and numbers (adds them). So if a binary plus gets an object as an argument, it uses the `"default"` hint to convert it. + + Also, if an object is compared using `==` with a string, number or a symbol, it's also unclear which conversion should be done, so the `"default"` hint is used. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js // somma binaria @@ -75,6 +111,7 @@ Sono chiamate "hints", come descritto in [specification](https://tc39.github.io/ L'operatore maggiore/minore `<>` può funzionare sia con stringhe che con numeri. Ad oggi, per motivi storici, si suppone la conversione a "numero" e non quella di "default". +<<<<<<< HEAD Nella pratica, tutti gli oggetti integrati (tranne oggetti `Date`, che studieremo più avanti) implementano la conversione `"default"` nello stesso modo di quella `"number"`. Noi dovremmo quindi fare lo stesso. Notate -- ci sono solo tre hint. Semplice. Non esiste alcuna conversione al tipo "boolean" (tutti gli oggetti sono `true` nei contesti booleani). Se trattiamo `"default"` e `"number"` allo stesso modo, come la maggior parte degli oggetti integrati, ci sono solo due conversioni. @@ -86,6 +123,21 @@ Notate -- ci sono solo tre hint. Semplice. Non esiste alcuna conversione al tipo - prova `obj.toString()` e `obj.valueOf()`, sempre se esistono. 3. Altrimenti se "hint" è di tipo `"number"` o `"default"` - prova `obj.valueOf()` and `obj.toString()`, sempre se esistono. +======= +In practice though, things are a bit simpler. + +All built-in objects except for one case (`Date` object, we'll learn it later) implement `"default"` conversion the same way as `"number"`. And we probably should do the same. + +Still, it's important to know about all 3 hints, soon we'll see why. + +**To do the conversion, JavaScript tries to find and call three object methods:** + +1. Call `obj[Symbol.toPrimitive](hint)` - the method with the symbolic key `Symbol.toPrimitive` (system symbol), if such method exists, +2. Otherwise if hint is `"string"` + - try calling `obj.toString()` or `obj.valueOf()`, whatever exists. +3. Otherwise if hint is `"number"` or `"default"` + - try calling `obj.valueOf()` or `obj.toString()`, whatever exists. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Symbol.toPrimitive @@ -120,15 +172,24 @@ alert(+user); // hint: number -> 1000 alert(user + 500); // hint: default -> 1500 ``` +<<<<<<< HEAD Come possiamo vedere nel codice, `user` diventa una stringa auto-descrittiva o una quantità di soldi, in base al tipo di conversione. Il semplice metodo `user[Symbol.toPrimitive]` gestisce tutte le conversioni. +======= +As we can see from the code, `user` becomes a self-descriptive string or a money amount, depending on the conversion. The single method `user[Symbol.toPrimitive]` handles all conversion cases. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## toString/valueOf Non esiste alcun `Symbol.toPrimitive` quindi JavaScript prova a trovare i metodi `toString` e `valueOf`: +<<<<<<< HEAD - Per "string" hint: `toString`, e se non esiste, `valueOf` (quindi `toString` ha la priorità per la conversione di stringhe). - Per altri hints: `valueOf`, e se non esiste, `toString` (quindi `valueOf` ha la priorità per le operazioni matematiche). +======= +- For the `"string"` hint: call `toString` method, and if it doesn't exist or if it returns an object instead of a primitive value, then call `valueOf` (so `toString` has the priority for string conversions). +- For other hints: call `valueOf`, and if it doesn't exist or if it returns an object instead of a primitive value, then call `toString` (so `valueOf` has the priority for maths). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Mi metodi `toString` arrivano `valueOf` da molto lontano. Non sono symbols (i symbols non esistevano tempo fa), ma piuttosto "normali" metodi. Forniscono un modo alternativo "vecchio stile" per implementare la conversione. @@ -199,23 +260,37 @@ In assenza di `Symbol.toPrimitive` e `valueOf`, `toString` gestirà tutte le con Una cosa importante da sapere riguardo le conversioni primitive è che non devono necessariamente ritornare il tipo "hint" (suggerito). +<<<<<<< HEAD Non c'è controllo riguardo al ritorno; ad esempio se `toString` ritorna effettivamente una stringa, o se `Symbol.toPrimitive` ritorna un numero per una *hint* `"number"` +======= +There is no control whether `toString` returns exactly a string, or whether `Symbol.toPrimitive` method returns a number for the hint `"number"`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 L'unico obbligo: questi metodi devono ritornare un tipo primitivo, non un oggetto. ```smart header="Note storiche" Per ragioni storiche, se `toString` o `valueOf` ritornassero un oggetto, non ci sarebbero errori, ma il risultato sarebbe ignorato (come se il metodo non esistesse). Questo accade perché inizialmente in JavaScript non c'era il concetto di "errore". +<<<<<<< HEAD Invece, `Symbol.toPrimitive` *deve* ritornare un tipo primitivo, altrimenti ci sarebbe un errore. +======= +In contrast, `Symbol.toPrimitive` is stricter, it *must* return a primitive, otherwise there will be an error. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` ## Ulteriori conversioni Come già sappiamo, molti operatori eseguono una conversione dei tipi, per esempio l'operatore `*`, che converte gli operandi a numeri. +<<<<<<< HEAD Se passiamo un oggetto come argomento, ci sono due passaggi: 1. L'oggetto è convertito a primitivo (secondo le regole spiegate sopra). 2. Se il risultato primitivo non è del tipo giusto, viene convertito. +======= +If we pass an object as an argument, then there are two stages of calculations: +1. The object is converted to a primitive (using the rules described above). +2. If necessary for further calculations, the resulting primitive is also converted. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio: @@ -243,7 +318,11 @@ let obj = { } }; +<<<<<<< HEAD alert(obj + 2); // 22 ("2" + 2), la conversione a primitivo ha restituito una stringa => concatenazione +======= +alert(obj + 2); // "22" ("2" + 2), conversion to primitive returned a string => concatenation +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` ## Riepilogo @@ -254,11 +333,21 @@ Ce ne sono tre tipi (hint): - `"number"` (per operazioni matematiche) - `"default"` (alcuni operatori) +<<<<<<< HEAD Le specifiche descrivono esplicitamente quali operatori utilizzano quali hint. Ci sono veramente pochi operatori che "non sanno quali utilizzare" e quindi scelgono quello di `"default"`. Solitamente per gli oggetti integrati l'hint `"default"` si comporta nello stesso modo di quello di tipo `"number"`, quindi nella pratica questi ultimi due sono spesso uniti. +======= +There are 3 types (hints) of it: +- `"string"` (for `alert` and other operations that need a string) +- `"number"` (for maths) +- `"default"` (few operators, usually objects implement it the same way as `"number"`) + +The specification describes explicitly which operator uses which hint. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 L'algoritmo di conversione segue questi passi: +<<<<<<< HEAD 1. Chiama `obj[Symbol.toPrimitive](hint)` se il metodo esiste, 2. Altrimenti se "hint" è di tipo `"string"` - prova `obj.toString()` e `obj.valueOf()`, sempre se esiste. @@ -268,3 +357,14 @@ L'algoritmo di conversione segue questi passi: Nella pratica, spesso è sufficiente implementare solo `obj.toString()` come metodo che "cattura tutte" le conversioni e ritorna una rappresentazione dell'oggetto "interpretabile dall'uomo", per mostrarlo o per il debugging. Per quanto riguarda le operazioni matematiche, JavaScript non fornisce un modo per "sovrascriverle" utilizzando i metodi, quindi vengono raramente utilizzate sugli oggetti. +======= +1. Call `obj[Symbol.toPrimitive](hint)` if the method exists, +2. Otherwise if hint is `"string"` + - try calling `obj.toString()` or `obj.valueOf()`, whatever exists. +3. Otherwise if hint is `"number"` or `"default"` + - try calling `obj.valueOf()` or `obj.toString()`, whatever exists. + +All these methods must return a primitive to work (if defined). + +In practice, it's often enough to implement only `obj.toString()` as a "catch-all" method for string conversions that should return a "human-readable" representation of an object, for logging or debugging purposes. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md b/1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md index 011b293ad..0644965b2 100644 --- a/1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md +++ b/1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md @@ -14,4 +14,8 @@ str.test = 5; alert(str.test); ``` +<<<<<<< HEAD Cosa ne pensate, potrebbe funzionare? Cosa verrebbe mostrato? +======= +What do you think, will it work? What will be shown? +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/1-js/05-data-types/01-primitives-methods/article.md b/1-js/05-data-types/01-primitives-methods/article.md index 84b2a41e5..425c7ab15 100644 --- a/1-js/05-data-types/01-primitives-methods/article.md +++ b/1-js/05-data-types/01-primitives-methods/article.md @@ -41,8 +41,13 @@ Gli oggetti sono più "pesanti" dei tipi primitivi. Richiedono risorse extra per Questo è il paradosso contro cui si è scontato il creatore di JavaScript: +<<<<<<< HEAD - Esistono molte operazioni che uno sviluppatore vorrebbe poter fare con i diversi tipi primitivi, come una stringhe o un numeri. Sarebbe molto bello poter accedere a dei metodi per questi tipi di dato. - I tipi primitivi devono essere veloci e il più leggeri possibile. +======= +- There are many things one would want to do with a primitive, like a string or a number. It would be great to access them using methods. +- Primitives must be as fast and lightweight as possible. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 La soluzione sembra un po' strana: @@ -106,9 +111,16 @@ if (zero) { // zero è true, perché è un oggetto } ``` +<<<<<<< HEAD In altre parole, utilizzare le stesse funzioni con `String/Number/Boolean` senza `new` è completamente sicuro. Poiché le variabili primitive verranno convertite all'oggetto corrispondente: ad una stringa, ad un numero, o ad un bool. Ad esempio, il seguente codice è corretto: +======= +On the other hand, using the same functions `String/Number/Boolean` without `new` is totally fine and useful thing. They convert a value to the corresponding type: to a string, a number, or a boolean (primitive). + +For example, this is entirely valid: + +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js let num = Number("123"); // converte una string in number ``` diff --git a/1-js/05-data-types/02-number/2-why-rounded-down/solution.md b/1-js/05-data-types/02-number/2-why-rounded-down/solution.md index 9bde25cf6..7808fc0b0 100644 --- a/1-js/05-data-types/02-number/2-why-rounded-down/solution.md +++ b/1-js/05-data-types/02-number/2-why-rounded-down/solution.md @@ -28,6 +28,6 @@ Notate che `63.5` non provoca perdita di precisione. Infatti la parte decimale ` ```js run -alert( Math.round(6.35 * 10) / 10); // 6.35 -> 63.5 -> 64(rounded) -> 6.4 +alert( Math.round(6.35 * 10) / 10 ); // 6.35 -> 63.5 -> 64(rounded) -> 6.4 ``` diff --git a/1-js/05-data-types/02-number/article.md b/1-js/05-data-types/02-number/article.md index 99180145c..faaac3280 100644 --- a/1-js/05-data-types/02-number/article.md +++ b/1-js/05-data-types/02-number/article.md @@ -2,9 +2,15 @@ Nella versione moderna di JavaScript ci sono due differenti tipi di numeri: +<<<<<<< HEAD 1. I numeri regolari, che vengono memorizzati nel formato a 64 bit [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754-2008_revision), conosciuti anche come "numeri in virgola mobile con doppia precisione". Questi sono i numeri che utilizziamo la maggior parte del tempo, e sono quelli di cui parleremo in questo capitolo. 2. I BigInt, che vengono utilizzati per rappresentare numeri interi di lunghezza arbitraria. Talvolta possono tornare utili, poiché i numeri regolari non possono eccedere 253 od essere inferiori di -253. Poiché i BigInt vengono utilizzati in alcune aree speciali, gli abbiamo dedicato un capitolo . +======= +1. Regular numbers in JavaScript are stored in 64-bit format [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754), also known as "double precision floating point numbers". These are numbers that we're using most of the time, and we'll talk about them in this chapter. + +2. BigInt numbers represent integers of arbitrary length. They are sometimes needed because a regular integer number can't safely exceed (253-1) or be less than -(253-1), as we mentioned earlier in the chapter . As bigints are used in a few special areas, we devote them to a special chapter . +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Quindi in questo capitolo parleremo dei numeri regolari. @@ -22,7 +28,11 @@ Possiamo anche usare il carattere underscore `_` come separatore: let billion = 1_000_000_000; ``` +<<<<<<< HEAD Qui il carattere `_` gioca il ruolo di "zucchero sintattico", cioè rende il numero più leggibile. Il motore JavaScript semplicemente ignorerà i caratteri `_` tra le cifre, quindi è equivalente al milione scritto sopra. +======= +Here the underscore `_` plays the role of the "[syntactic sugar](https://en.wikipedia.org/wiki/Syntactic_sugar)", it makes the number more readable. The JavaScript engine simply ignores `_` between digits, so it's exactly the same one billion as above. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Nella vita reale però cerchiamo di evitare di scrivere lunghe file di zeri per evitare errori. E anche perché siamo pigri. Solitamente scriviamo qualcosa del tipo `"1ml"` per un milione o `"7.3ml"` 7 milioni e 300mila. Lo stesso vale per i numeri più grandi. @@ -42,16 +52,27 @@ In altre parole, `"e"` moltiplica il numero `1` seguito dal numero di zeri dati. 1.23e6 = 1.23 * 1000000 // e6 significa *1000000 ``` +<<<<<<< HEAD Ora proviamo a scrivere qualcosa di molto piccolo. Ad esempio, 1 microsecondo (un milionesimo di secondo): +======= +Now let's write something very small. Say, 1 microsecond (one-millionth of a second): +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js -let ms = 0.000001; +let mсs = 0.000001; ``` +<<<<<<< HEAD Come prima, l'utilizzo di `"e"` può aiutare. Se volessimo evitare di scrivere esplicitamente tutti gli "0", potremmo scrivere: ```js let ms = 1e-6; // sei zeri alla sinistra di 1 +======= +Just like before, using `"e"` can help. If we'd like to avoid writing the zeroes explicitly, we could write the same as: + +```js +let mcs = 1e-6; // five zeroes to the left from 1 +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` Se contiamo gli zeri in `0.000001`, ce ne sono 6. Quindi ovviamente `1e-6`. @@ -62,8 +83,16 @@ In altre parole, un numero negativo dopo `"e"` significa una divisione per 1 seg // -3 divide 1 con 3 zeri 1e-3 = 1 / 1000; // 0.001 +<<<<<<< HEAD // -6 divide 1 con 6 zeri 1.23e-6 = 1.23 / 1000000; // 0.00000123 +======= +// -6 divides by 1 with 6 zeroes +1.23e-6 === 1.23 / 1000000; // 0.00000123 + +// an example with a bigger number +1234e-2 === 1234 / 100; // 12.34, decimal point moves 2 times +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` ### Numeri esadecimali, binari e ottali @@ -101,13 +130,23 @@ alert( num.toString(16) ); // ff alert( num.toString(2) ); // 11111111 ``` +<<<<<<< HEAD La `base` può variare da `2` a `36`. Di default vale `10`. +======= +The `base` can vary from `2` to `36`. By default, it's `10`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Altri casi di uso comune sono: +<<<<<<< HEAD - **base=16** si utilizza per colori in esadecimale, codifiche di caratteri, i caratteri supportati sono `0..9` o `A..F`. - **base=2** viene utilizzato per debugging o operazioni bit a bit, i caratteri accettati sono `0` o `1`. - **base=36** la base massima, i caratteri possono andare da `0..9` o `A..Z`. L'intero alfabeto latino viene utilizzato per rappresentare un numero. Un caso divertente di utilizzo per la base `36` è quando abbiamo bisogno che un identificatore molto lungo diventi qualcosa di più breve, come ad esempio per accorciare gli url. Possiamo semplicemente rappresentarlo in base `36`: +======= +- **base=16** is used for hex colors, character encodings etc, digits can be `0..9` or `A..F`. +- **base=2** is mostly for debugging bitwise operations, digits can be `0` or `1`. +- **base=36** is the maximum, digits can be `0..9` or `A..Z`. The whole Latin alphabet is used to represent a number. A funny, but useful case for `36` is when we need to turn a long numeric identifier into something shorter, for example, to make a short url. Can simply represent it in the numeral system with base `36`: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run alert( 123456..toString(36) ); // 2n9c @@ -116,7 +155,13 @@ Altri casi di uso comune sono: ```warn header="Due punti per chiamare un metodo" Da notare che i due punti in `123456..toString(36)` non sono un errore. Se vogliamo chiamare un metodo direttamente da un numero, come `toString` nell'esempio sopra, abbiamo bisogno di inserire due punti `..`. +<<<<<<< HEAD Se inseriamo un solo punto: `123456.toString(36)`, otterremo un errore, perché la sintassi JavaScript implica una parte decimale a seguire del primo punto. Se invece inseriamo un ulteriore punto, allora JavaScript capirà che la parte decimale è vuota e procederà nel chiamare il metodo. +======= +If we placed a single dot: `123456.toString(36)`, then there would be an error, because JavaScript syntax implies the decimal part after the first dot. And if we place one more dot, then JavaScript knows that the decimal part is empty and now uses the method. + +Also could write `(123456).toString(36)`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Potremmo anche scrivere `(123456).toString(36)`. ``` @@ -134,6 +179,10 @@ Ci sono diverse funzioni integrate per eseguire questa operazione: : Arrotonda per eccesso: `3.1` diventa `4`, e `-1.1` diventa `-1`. `Math.round` +<<<<<<< HEAD +======= +: Rounds to the nearest integer: `3.1` becomes `3`, `3.6` becomes `4`. In the middle cases `3.5` rounds up to `4`, and `-3.5` rounds up to `-3`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 : Arrotonda all'intero più vicino: `3.1` diventa `3`, `3.6` diventa `4`, e `3.5` viene arrotondato anch'esso a `4`. @@ -145,8 +194,10 @@ Qui abbiamo una tabella che riassume le principali differenze: | | `Math.floor` | `Math.ceil` | `Math.round` | `Math.trunc` | |---|---------|--------|---------|---------| |`3.1`| `3` | `4` | `3` | `3` | +|`3.5`| `3` | `4` | `4` | `3` | |`3.6`| `3` | `4` | `4` | `3` | |`-1.1`| `-2` | `-1` | `-1` | `-1` | +|`-1.5`| `-2` | `-1` | `-1` | `-1` | |`-1.6`| `-2` | `-1` | `-2` | `-1` | @@ -158,7 +209,11 @@ Ci sono due modi per farlo: 1. Moltiplica e dividi. +<<<<<<< HEAD Ad esempio, per arrotondare un numero alla seconda cifra decimale, possiamo moltiplicare il numero per `100`, chiamare la funzione di arrotondamento e dividerlo nuovamente. +======= + For example, to round the number to the 2nd digit after the decimal, we can multiply the number by `100`, call the rounding function and then divide it back. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let num = 1.23456; @@ -179,20 +234,34 @@ Ci sono due modi per farlo: alert( num.toFixed(1) ); // "12.4" ``` +<<<<<<< HEAD Da notare che il risultato di `toFixed` è una stringa. Se la parte decimale è più breve di quanto richiesto, verranno aggiunti degli zeri: +======= + Please note that the result of `toFixed` is a string. If the decimal part is shorter than required, zeroes are appended to the end: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let num = 12.34; alert( num.toFixed(5) ); // "12.34000", aggiunti gli zeri per renderlo esattamente di 5 cifre decimali ``` +<<<<<<< HEAD Possiamo convertire il risultato al tipo numerico utilizzando la somma unaria o chiamando il metodo `Number()`: `+num.toFixed(5)`. +======= + We can convert it to a number using the unary plus or a `Number()` call, e.g. write `+num.toFixed(5)`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Calcoli imprecisi +<<<<<<< HEAD Internamente, un numero è rappresentato in formato 64-bit [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754-2008_revision), quindi vengono utilizzati esattamente 64 bit per rappresentare un numero: 52 vengono utilizzati per rappresentare le cifre, 11 per la parte decimale, e infine 1 bit per il segno. Se un numero è troppo grande, tale da superare i 64 bit disponibili, come ad esempio un numero potenzialmente infinito: +======= +Internally, a number is represented in 64-bit format [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754), so there are exactly 64 bits to store a number: 52 of them are used to store the digits, 11 of them store the position of the decimal point, and 1 bit is for the sign. + +If a number is really huge, it may overflow the 64-bit storage and become a special numeric value `Infinity`: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run alert( 1e500 ); // Infinity @@ -200,7 +269,11 @@ alert( 1e500 ); // Infinity Potrebbe essere poco ovvio, ma quello che accade è la perdita di precisione. +<<<<<<< HEAD Consideriamo questo test (falso!): +======= +Consider this (falsy!) equality test: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run alert( 0.1 + 0.2 == 0.3 ); // *!*false*/!* @@ -214,13 +287,27 @@ Strano! Quale può essere il risultato se non `0.3`? alert( 0.1 + 0.2 ); // 0.30000000000000004 ``` +<<<<<<< HEAD Ouch! Un confronto errato di questo tipo può generare diverse conseguenze. Immaginate di progettare un sito di e-shop in cui i visitatori aggiungono al carrello articoli da `$0.10` e `$0.20`. Poi come prezzo totale viene mostrato `$0.30000000000000004`. Questo risultato lascerebbe sorpreso chiunque. +======= +Ouch! Imagine you're making an e-shopping site and the visitor puts `$0.10` and `$0.20` goods into their cart. The order total will be `$0.30000000000000004`. That would surprise anyone. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ma perché accade questo? Un numero viene memorizzato nella sua forma binaria, una sequenza di "1" e "0". I numeri con virgola come `0.1`, `0.2` che visti nella loro forma decimale sembrano semplici, sono in realtà una sequenza infinita di cifre nella forma binaria. +<<<<<<< HEAD In altre parole, cos'è `0.1`? Vale 1 diviso 10 `1/10`, "un decimo". Nel sistema decimale questi numeri sono facilmente rappresentabili. Prendiamo invece "un terzo": `1/3`. Diventa un numero con infiniti decimali `0.33333(3)`. +======= +```js run +alert(0.1.toString(2)); // 0.0001100110011001100110011001100110011001100110011001101 +alert(0.2.toString(2)); // 0.001100110011001100110011001100110011001100110011001101 +alert((0.1 + 0.2).toString(2)); // 0.0100110011001100110011001100110011001100110011001101 +``` + +What is `0.1`? It is one divided by ten `1/10`, one-tenth. In the decimal numeral system, such numbers are easily representable. Compare it to one-third: `1/3`. It becomes an endless fraction `0.33333(3)`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Quindi, le divisioni per potenze di `10` funzionano molto bene nel sistema decimale, non vale lo stesso con la divisione per `3`. Per la stessa ragione, nel sistema binario le divisioni per potenze di `2` sono una garanzia, ma `1/10` diventa una sequenza infinita di cifre. @@ -240,7 +327,11 @@ Questo è il motivo per cui `0.1 + 0.2` non vale esattamente `0.3`. ```smart header="Non solo JavaScript" Lo stesso problema esiste in molti altri linguaggi di programmazione. +<<<<<<< HEAD PHP, Java, C, Perl, Ruby hanno lo stesso tipo di problema, poiché si basano sullo stesso formato numerico. +======= +PHP, Java, C, Perl, and Ruby give exactly the same result, because they are based on the same numeric format. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` Possiamo risolvere questo problema? Certamente, ci sono diverse soluzioni: @@ -249,7 +340,7 @@ Possiamo risolvere questo problema? Certamente, ci sono diverse soluzioni: ```js run let sum = 0.1 + 0.2; -alert( sum.toFixed(2) ); // 0.30 +alert( sum.toFixed(2) ); // "0.30" ``` Da notare che `toFixed` ritorna sempre una stringa. Viene cosi garantito che ci siano almeno due cifre dopo la virgola decimale. Questo ci torna molto utile se abbiamo un e-shopping e vogliamo mostrare `$0.30`. Per tutti gli altri casi possiamo semplicemente chiamare la conversione con l'operatore di somma unaria: @@ -266,7 +357,11 @@ alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3 alert( (0.28 * 100 + 0.14 * 100) / 100); // 0.4200000000000001 ``` +<<<<<<< HEAD Questo funziona perché quando facciamo `0.1 * 10 = 1` e `0.2 * 10 = 2` entrambi diventano interi, non vi è quindi perdita di precisione. +======= +So, the multiply/divide approach reduces the error, but doesn't remove it totally. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 3. Se abbiamo a che fare con dei prezzi, la miglior soluzione rimane quella di memorizzare tutti i prezzi in centesimi, evitando quindi di utilizzare i numeri con virgola. Ma cosa succede se proviamo ad applicare uno sconto del 30%? Nella pratica, evitare completamente questo problema è difficile, in alcuni casi possono tornare utili entrambe le soluzioni viste sopra. @@ -292,7 +387,11 @@ Un'altra conseguenza divertente della rappresentazione interna è l'esistenza di Questo perché il segno viene rappresentato con un solo bit, in questo modo ogni numero può essere positivo o negativo, lo stesso vale per lo zero. +<<<<<<< HEAD Nella maggior parte dei casi questa differenza è impercettibile, poiché gli operatori sono studiati per trattarli allo stesso modo. +======= +In most cases, the distinction is unnoticeable, because operators are suited to treat them as the same. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` ## Test: isFinite e isNaN @@ -312,7 +411,11 @@ Questi appartengono al tipo `number`, ma non sono dei numeri "normali", esistono alert( isNaN("str") ); // true ``` +<<<<<<< HEAD Ma abbiamo veramente bisogno di questa funzione? Non possiamo semplicemente usare il confronto `=== NaN`? Purtroppo la risposta è no. Il valore `NaN` è unico in questo aspetto, non è uguale a niente, nemmeno a se stesso: +======= + But do we need this function? Can't we just use the comparison `=== NaN`? Unfortunately not. The value `NaN` is unique in that it does not equal anything, including itself: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run alert( NaN === NaN ); // false @@ -338,16 +441,57 @@ alert( isFinite(num) ); Da notare che una stringa vuota o contenente solo spazi viene trattata come `0` in qualsiasi funzione numerica, compresa `isFinite`. +<<<<<<< HEAD ```smart header="Confronto con `Object.is`" Esiste uno speciale metodo integrato [Object.is](mdn:js/Object/is) che confronta valori proprio come `===`, ma risulta molto più affidabile in due casi limite: 1. Funziona con `NaN`: `Object.is(NaN, NaN) === true`, e questo è un bene. 2. I valori `0` e `-0` sono diversi: `Object.is(0, -0) === false`, tecnicamente sarebbero uguali, però internamente vengono rappresentati con il bit di segno, che in questo caso è diverso. +======= +````smart header="`Number.isNaN` and `Number.isFinite`" +[Number.isNaN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN) and [Number.isFinite](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isFinite) methods are the more "strict" versions of `isNaN` and `isFinite` functions. They do not autoconvert their argument into a number, but check if it belongs to the `number` type instead. + +- `Number.isNaN(value)` returns `true` if the argument belongs to the `number` type and it is `NaN`. In any other case, it returns `false`. + + ```js run + alert( Number.isNaN(NaN) ); // true + alert( Number.isNaN("str" / 2) ); // true + + // Note the difference: + alert( Number.isNaN("str") ); // false, because "str" belongs to the string type, not the number type + alert( isNaN("str") ); // true, because isNaN converts string "str" into a number and gets NaN as a result of this conversion + ``` + +- `Number.isFinite(value)` returns `true` if the argument belongs to the `number` type and it is not `NaN/Infinity/-Infinity`. In any other case, it returns `false`. + + ```js run + alert( Number.isFinite(123) ); // true + alert( Number.isFinite(Infinity) ); // false + alert( Number.isFinite(2 / 0) ); // false + + // Note the difference: + alert( Number.isFinite("123") ); // false, because "123" belongs to the string type, not the number type + alert( isFinite("123") ); // true, because isFinite converts string "123" into a number 123 + ``` + +In a way, `Number.isNaN` and `Number.isFinite` are simpler and more straightforward than `isNaN` and `isFinite` functions. In practice though, `isNaN` and `isFinite` are mostly used, as they're shorter to write. +```` + +```smart header="Comparison with `Object.is`" +There is a special built-in method `Object.is` that compares values like `===`, but is more reliable for two edge cases: + +1. It works with `NaN`: `Object.is(NaN, NaN) === true`, that's a good thing. +2. Values `0` and `-0` are different: `Object.is(0, -0) === false`, technically that's correct because internally the number has a sign bit that may be different even if all other bits are zeroes. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 In tutti gli altri casi, `Object.is(a, b)` equivale a `a === b`. +<<<<<<< HEAD Questo metodo di confronto viene spesso utilizzato in JavaScript. Quando un algoritmo interno ha necessità di verificare che due valori siano esattamente la stessa cosa, si utilizza `Object.is` (internamente chiamato [SameValue](https://tc39.github.io/ecma262/#sec-samevalue)). +======= +We mention `Object.is` here, because it's often used in JavaScript specification. When an internal algorithm needs to compare two values for being exactly the same, it uses `Object.is` (internally called [SameValue](https://tc39.github.io/ecma262/#sec-samevalue)). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` @@ -361,7 +505,11 @@ alert( +"100px" ); // NaN L'unica eccezione tollerata è la presenza di spazi all'inizio o alla fine della stringa, poiché vengono ignorati. +<<<<<<< HEAD Ma nella vita reale spesso abbiamo valori in unità, come `"100px"` o `"12pt"` in CSS. In molti stati il simbolo della valuta va dopo il saldo, quindi abbiamo `"19€"` e vorremmo estrarre un valore numerico. +======= +But in real life, we often have values in units, like `"100px"` or `"12pt"` in CSS. Also in many countries, the currency symbol goes after the amount, so we have `"19€"` and would like to extract a numeric value out of that. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Questo è il motivo per cui sono stati pensati `parseInt` e `parseFloat`. @@ -407,8 +555,13 @@ Un paio di esempi: alert( Math.random() ); // ... (numero casuale) ``` +<<<<<<< HEAD `Math.max(a, b, c...)` / `Math.min(a, b, c...)` : Ritorna il maggiore/minore fra una lista di argomenti. +======= +`Math.max(a, b, c...)` and `Math.min(a, b, c...)` +: Returns the greatest and smallest from the arbitrary number of arguments. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run alert( Math.max(3, 5, -10, 0, 1) ); // 5 @@ -434,9 +587,20 @@ Per scrivere numeri molto grandi: Per diversi sistemi numerici: +<<<<<<< HEAD - Potete scrivere direttamente in esadecimale (`0x`), ottale (`0o`) e binario (`0b`) - `parseInt(str, base)` analizza un numero intero con un qualsiasi sistema numerico con base: `2 ≤ base ≤ 36`. - `num.toString(base)` converte un numero ad una stringa utilizzando il sistema numerico fornito in `base`. +======= +For regular number tests: + +- `isNaN(value)` converts its argument to a number and then tests it for being `NaN` +- `Number.isNaN(value)` checks whether its argument belongs to the `number` type, and if so, tests it for being `NaN` +- `isFinite(value)` converts its argument to a number and then tests it for not being `NaN/Infinity/-Infinity` +- `Number.isFinite(value)` checks whether its argument belongs to the `number` type, and if so, tests it for not being `NaN/Infinity/-Infinity` + +For converting values like `12pt` and `100px` to a number: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Per convertire a numeri valori del tipo `12pt` e `100px`: @@ -451,3 +615,7 @@ Altre funzioni matematiche: - Guardate l'oggetto [Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) in caso di necessità. La libreria non è molto ampia, ma è in grado di coprire le necessità di base. +<<<<<<< HEAD +======= +- See the [Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) object when you need them. The library is very small but can cover basic needs. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/1-js/05-data-types/03-string/1-ucfirst/solution.md b/1-js/05-data-types/03-string/1-ucfirst/solution.md index d8b45d7a1..6112985a7 100644 --- a/1-js/05-data-types/03-string/1-ucfirst/solution.md +++ b/1-js/05-data-types/03-string/1-ucfirst/solution.md @@ -8,12 +8,16 @@ let newStr = str[0].toUpperCase() + str.slice(1); C'è comunque un piccolo problema. Se `str` è vuota, allora `str[0]` è `undefined`, quindi otterremo un errore. +<<<<<<< HEAD Ci sono due possibili varianti qui: 1. Utilizzare `str.charAt(0)`, che ritorna sempre una stringa (eventualmente vuota). 2. Aggiungere una verifica di stringa vuota. Qui abbiamo scelto la seconda variante: +======= +The easiest way out is to add a test for an empty string, like this: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run demo function ucFirst(str) { @@ -24,4 +28,3 @@ function ucFirst(str) { alert( ucFirst("john") ); // John ``` - diff --git a/1-js/05-data-types/03-string/3-truncate/task.md b/1-js/05-data-types/03-string/3-truncate/task.md index a3c5bd3b4..7d1b19047 100644 --- a/1-js/05-data-types/03-string/3-truncate/task.md +++ b/1-js/05-data-types/03-string/3-truncate/task.md @@ -11,7 +11,7 @@ Come risultato la funzione dovrebbe troncare la stringa (se ce n'è bisogno). Ad esempio: ```js -truncate("What I'd like to tell on this topic is:", 20) = "What I'd like to te…" +truncate("What I'd like to tell on this topic is:", 20) == "What I'd like to te…" -truncate("Hi everyone!", 20) = "Hi everyone!" +truncate("Hi everyone!", 20) == "Hi everyone!" ``` diff --git a/1-js/05-data-types/03-string/article.md b/1-js/05-data-types/03-string/article.md index 41b8e5914..f4f8978b2 100644 --- a/1-js/05-data-types/03-string/article.md +++ b/1-js/05-data-types/03-string/article.md @@ -45,9 +45,15 @@ let guestList = "Guests: // Error: Unexpected token ILLEGAL * John"; ``` +<<<<<<< HEAD Gli apici singoli e doppi sono nati insieme al linguaggio, quando non era stato ancora messo in conto la possibilità di stringhe multilinea. Le backticks sono apparse più tardi, per questo risultano più versatili. Le backticks ci consentono anche di specificare un "template di funzione" prima della backtick di apertura. La sintassi è: func`string`. La funzione `func` viene chiamata automaticamente, gli viene passata la "string", può essere cosi trattata dalla funzione. Potete approfondire leggendo la [documentazione](mdn:/JavaScript/Reference/Template_literals#Tagged_templates). Questo viene chiamata "funzione template". Con questa caratteristica diventa più facile raccogliere stringhe da passare a funzioni, ma è raramente utilizzata. +======= +Single and double quotes come from ancient times of language creation, when the need for multiline strings was not taken into account. Backticks appeared much later and thus are more versatile. + +Backticks also allow us to specify a "template function" before the first backtick. The syntax is: func`string`. The function `func` is called automatically, receives the string and embedded expressions and can process them. This feature is called "tagged templates", it's rarely seen, but you can read about it in the MDN: [Template literals](mdn:/JavaScript/Reference/Template_literals#Tagged_templates). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Caratteri speciali @@ -57,10 +63,17 @@ E' comunque possibile creare stringhe multilinea con singoli apici utilizzando i ```js run let guestList = "Guests:\n * John\n * Pete\n * Mary"; +<<<<<<< HEAD alert(guestList); // una lista di guest multi riga ``` Ad esempio, queste due funzioni portano allo stesso risultato: +======= +alert(guestList); // a multiline list of guests, same as above +``` + +As a simpler example, these two lines are equal, just written differently: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let str1 = "Hello\nWorld"; // due righe utilizzando il "carattere nuova riga" @@ -70,6 +83,7 @@ let str2 = `Hello World`; ``` +<<<<<<< HEAD Ci sono altri caratteri "speciali" meno comuni. Qui una lista: | Carattere | Descrizione | @@ -95,6 +109,28 @@ alert( "\u{1F60D}" ); // 😍, un simbolo di faccia sorridente (long unicode) Tutti i caratteri speciali iniziano con un backslash `\`. Che viene anche chiamato "carattere di escape". Dobbiamo utilizzarlo anche se abbiamo intenzione di inserire un apice all'interno della stringa. +======= +There are other, less common special characters: + +| Character | Description | +|-----------|-------------| +|`\n`|New line| +|`\r`|In Windows text files a combination of two characters `\r\n` represents a new break, while on non-Windows OS it's just `\n`. That's for historical reasons, most Windows software also understands `\n`. | +|`\'`, `\"`, \\`|Quotes| +|`\\`|Backslash| +|`\t`|Tab| +|`\b`, `\f`, `\v`| Backspace, Form Feed, Vertical Tab -- mentioned for completeness, coming from old times, not used nowadays (you can forget them right now). | + +As you can see, all special characters start with a backslash character `\`. It is also called an "escape character". + +Because it's so special, if we need to show an actual backslash `\` within the string, we need to double it: + +```js run +alert( `The backslash: \\` ); // The backslash: \ +``` + +So-called "escaped" quotes `\'`, `\"`, \\` are used to insert a quote into the same-quoted string. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio: @@ -107,9 +143,10 @@ Avete visto che abbiamo inserito un backslash `\'` prima dell'apice interno, alt Ovviamente, questo è valido per un apice uguale a quello utilizzato in apertura. Quindi, possiamo optare per una soluzione più elegante, ad esempio i doppi apici o i backticks: ```js run -alert( `I'm the Walrus!` ); // I'm the Walrus! +alert( "I'm the Walrus!" ); // I'm the Walrus! ``` +<<<<<<< HEAD Da notare che il backslash `\` ha l'unico scopo di aiutare JavaScript nella lettura della stringa, questo verrà poi rimosso. La stringa in memoria non avrà `\`. Lo avrete sicuramente notato con gli `alert` dei vari esempi sopra. Ma se volessimo realmente mostrare un backslash `\` dentro la stringa? @@ -119,6 +156,9 @@ E' possibile farlo, ma dobbiamo esplicitarlo con un doppio backslash `\\`: ```js run alert( `The backslash: \\` ); // The backslash: \ ``` +======= +Besides these special characters, there's also a special notation for Unicode codes `\u…`, it's rarely used and is covered in the optional chapter about [Unicode](info:unicode). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## String length @@ -133,33 +173,55 @@ Da notare che `\n` è contato come unico carattere "speciale", quindi la lunghez ```warn header="`length` è una proprietà" Alcune persone abituate ad altri linguaggi possono confondere al chiamata `str.length()` con `str.length`. Questo è un errore. +<<<<<<< HEAD Infatti `str.length` è una proprietà numerica, non una funzione. Non c'è alcun bisogno delle parentesi. +======= +Please note that `str.length` is a numeric property, not a function. There is no need to add parenthesis after it. Not `.length()`, but `.length`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` ## Accesso ai caratteri +<<<<<<< HEAD Per ottenere un carattere alla posizione `pos`, si utilizzano le parentesi quadre `[pos]` oppure la chiamata al metodo [str.charAt(pos)](mdn:js/String/charAt). Il primo carattere parte dalla posizione zero: +======= +To get a character at position `pos`, use square brackets `[pos]` or call the method [str.at(pos)](mdn:js/String/at). The first character starts from the zero position: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let str = `Hello`; // il primo carattere alert( str[0] ); // H -alert( str.charAt(0) ); // H +alert( str.at(0) ); // H // l'ultimo carattere alert( str[str.length - 1] ); // o +alert( str.at(-1) ); ``` +<<<<<<< HEAD L'utilizzo delle parentesi quadre è il modo più classico per accedere ad un carattere, mentre `charAt` esiste principalmente per ragioni storiche. L'unica differenza sta nel comportamento in casi di carattere non trovato, `[]` ritorna `undefined`, e `charAt` ritorna una stringa vuota: +======= +As you can see, the `.at(pos)` method has a benefit of allowing negative position. If `pos` is negative, then it's counted from the end of the string. + +So `.at(-1)` means the last character, and `.at(-2)` is the one before it, etc. + +The square brackets always return `undefined` for negative indexes, for instance: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let str = `Hello`; +<<<<<<< HEAD alert( str[1000] ); // undefined alert( str.charAt(1000) ); // '' (una stringa vuota) +======= +alert( str[-2] ); // undefined +alert( str.at(-2) ); // l +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` Possiamo iterare sui caratteri utilizzando `for..of`: @@ -208,7 +270,7 @@ alert( 'Interface'.toLowerCase() ); // interface Altrimenti, possiamo agire anche su un singolo carattere: -```js +```js run alert( 'Interface'[0].toLowerCase() ); // 'i' ``` @@ -305,6 +367,7 @@ if (str.indexOf("Widget") != -1) { } ``` +<<<<<<< HEAD #### Il trucco del NOT bit a bit Uno dei trucchi più utilizzati è l'operatore di [NOT bit a bit](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_NOT) `~`. Questo converte il numero ad un intero in 32bit (rimuovendo la parte decimale se presente) e successivamente inverte tutti i bit. @@ -343,6 +406,8 @@ Per essere precisi, numeri molto grandi vengono troncati a 32bit dall'operatore Attualmente questo trucco lo troviamo solamente nei codici vecchi, poiché JavaScript moderno fornisce un metodo dedicato, `.includes`(vedi sotto). +======= +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ### includes, startsWith, endsWith Un metodo più moderno come [str.includes(substr, pos)](mdn:js/String/includes) ritorna `true/false` basandosi solo sull'aver trovato in `str` la `substr`. @@ -365,8 +430,13 @@ alert( "Midget".includes("id", 3) ); // false, dalla posizione 3 non c'è "id" I metodi [str.startsWith](mdn:js/String/startsWith) e [str.endsWith](mdn:js/String/endsWith) fanno esattamente ciò che dicono i loro nomi: ```js run +<<<<<<< HEAD alert( "Widget".startsWith("Wid") ); // true, "Widget" inizia con "Wid" alert( "Widget".endsWith("get") ); // true, "Widget" finisce con "get" +======= +alert( "*!*Wid*/!*get".startsWith("Wid") ); // true, "Widget" starts with "Wid" +alert( "Wid*!*get*/!*".endsWith("get") ); // true, "Widget" ends with "get" +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` ## Estrarre una sotto-stringa @@ -401,9 +471,15 @@ Ci sono 3 metodi in JavaScript per estrarre una sotto-stringa: `substring`, `sub ``` `str.substring(start [, end])` +<<<<<<< HEAD : Ritorna la parte di stringa *compresa tra* `start` e `end`. E' molto simile a `slice`, ma consente di avere `start` maggiore di `end`. +======= +: Returns the part of the string *between* `start` and `end` (not including `end`). + + This is almost the same as `slice`, but it allows `start` to be greater than `end` (in this case it simply swaps `start` and `end` values). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio: @@ -439,19 +515,37 @@ Ci sono 3 metodi in JavaScript per estrarre una sotto-stringa: `substring`, `sub alert( str.substr(-4, 2) ); // gi, dalla quarta posizione prende 4 caratteri ``` +<<<<<<< HEAD Ricapitoliamo questi metodi per evitare confusione: +======= + This method resides in the [Annex B](https://tc39.es/ecma262/#sec-string.prototype.substr) of the language specification. It means that only browser-hosted Javascript engines should support it, and it's not recommended to use it. In practice, it's supported everywhere. + +Let's recap these methods to avoid any confusion: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 | metodo | selezione... | negativi | |--------|-----------|-----------| +<<<<<<< HEAD | `slice(start, end)` | da `start` a `end` (`end` escluso) | indici negativi ammessi | | `substring(start, end)` | tra `start` e `end` | valori negativi valgono come `0` | | `substr(start, length)` | da `start` per `length` caratteri | consente indice di `start` negativo | +======= +| `slice(start, end)` | from `start` to `end` (not including `end`) | allows negatives | +| `substring(start, end)` | between `start` and `end` (not including `end`)| negative values mean `0` | +| `substr(start, length)` | from `start` get `length` characters | allows negative `start` | +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 +<<<<<<< HEAD ```smart header="Quale scegliere?" Tutti i metodi esaminati possono portare a termine il lavoro. Formalmente, `substr` ha un piccolo inconveniente: non è descritto nelle specifiche del core JavaScript, ma in quelle di Annex B, che copre solo le caratteristiche utili nello sviluppo browser. Quindi ambienti diversi dal browser potrebbero non supportarla. Ma nella pratica viene utilizzata ovunque. L'autore della guida si trova spesso ad utilizzare il metodo `slice`. +======= +Of the other two variants, `slice` is a little bit more flexible, it allows negative arguments and shorter to write. + +So, for practical use it's enough to remember only `slice`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` ## Confronto tra stringhe @@ -474,6 +568,7 @@ Sebbene ci siano dei casi particolari. Questo potrebbe portare a strani risultati se provassimo ad ordinare le città per nome. Solitamente ci si aspetta di trovare `Zealand` dopo `Österreich`. +<<<<<<< HEAD Per capire cosa succede, dobbiamo guardare alla rappresentazione interna delle stringhe in JavaScript. Tutte le stringhe vengono codificate utilizzando [UTF-16](https://en.wikipedia.org/wiki/UTF-16). Cioè: ogni carattere ha un suo codice numerico. Ci sono alcuni metodi che consentono di ottenere il carattere dal codice (e viceversa). @@ -484,7 +579,20 @@ Tutte le stringhe vengono codificate utilizzando [UTF-16](https://en.wikipedia.o ```js run // lettere di timbro differente possiedono codici differenti alert( "z".codePointAt(0) ); // 122 +======= +To understand what happens, we should be aware that strings in Javascript are encoded using [UTF-16](https://en.wikipedia.org/wiki/UTF-16). That is: each character has a corresponding numeric code. + +There are special methods that allow to get the character for the code and back: + +`str.codePointAt(pos)` +: Returns a decimal number representing the code for the character at position `pos`: + + ```js run + // different case letters have different codes +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 alert( "Z".codePointAt(0) ); // 90 + alert( "z".codePointAt(0) ); // 122 + alert( "z".codePointAt(0).toString(16) ); // 7a (if we need a hexadecimal value) ``` `String.fromCodePoint(code)` @@ -492,6 +600,7 @@ Tutte le stringhe vengono codificate utilizzando [UTF-16](https://en.wikipedia.o ```js run alert( String.fromCodePoint(90) ); // Z +<<<<<<< HEAD ``` Possiamo anche aggiungere caratteri unicode tramite il loro codice utilizzando `\u` seguito dal codice esadecimale: @@ -499,6 +608,9 @@ Tutte le stringhe vengono codificate utilizzando [UTF-16](https://en.wikipedia.o ```js run // 90 è 5a nel sistema esadecimale alert( '\u005a' ); // Z +======= + alert( String.fromCodePoint(0x5a) ); // Z (we can also use a hex value as an argument) +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` Ora vediamo i caratteri con il codice compreso tra `65..220` (l'alfabeto latino e qualche extra) creando una stringa: @@ -510,6 +622,7 @@ for (let i = 65; i <= 220; i++) { str += String.fromCodePoint(i); } alert( str ); +// Output: // ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„ // ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜ ``` @@ -529,7 +642,11 @@ L'algoritmo più corretto da utilizzare per confrontare stringhe è più comples Quindi il browser deve sapere quale lingua utilizzare nel confronto. +<<<<<<< HEAD Fortunatamente, tutti i browser moderni (IE10 richiede una libreria esterna [Intl.js](https://github.com/andyearnshaw/Intl.js/)) supportano lo standard internazionale [ECMA-402](http://www.ecma-international.org/ecma-402/1.0/ECMA-402.pdf). +======= +Luckily, modern browsers support the internationalization standard [ECMA-402](https://www.ecma-international.org/publications-and-standards/standards/ecma-402/). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Questo fornisce uno speciale metodo per confrontare stringhe in lingue diverse, seguendo delle regole. @@ -547,6 +664,7 @@ alert( 'Österreich'.localeCompare('Zealand') ); // -1 Questo metodo in realtà ha due argomenti opzionali specificati nella [documentazione](mdn:js/String/localeCompare), che consentono di specificare la lingua (di default viene presa dall'ambiente) e impostare delle regole aggiuntive come il timbro delle lettere, oppure se `"a"` e `"á"` dovrebbero essere trattate ugualmente etc. +<<<<<<< HEAD ## Internamente, Unicode ```warn header="Apprendimento avanzato" @@ -653,6 +771,17 @@ Se volete approfondire il tema della normalizzazione e le sue varianti -- vengon ## Riepilogo +======= +## Summary + +- There are 3 types of quotes. Backticks allow a string to span multiple lines and embed expressions `${…}`. +- We can use special characters, such as a line break `\n`. +- To get a character, use: `[]` or `at` method. +- To get a substring, use: `slice` or `substring`. +- To lowercase/uppercase a string, use: `toLowerCase/toUpperCase`. +- To look for a substring, use: `indexOf`, or `includes/startsWith/endsWith` for simple checks. +- To compare strings according to the language, use: `localeCompare`, otherwise they are compared by character codes. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 - Ci sono 3 tipi di apici. Le backticks consentono stringhe multi-linea ed espressioni integrate. - Le stringhe in JavaScript vengono codificate usando UTF-16. @@ -665,8 +794,14 @@ Se volete approfondire il tema della normalizzazione e le sue varianti -- vengon Ci sono molti altri metodi utili per operare con le stringhe: +<<<<<<< HEAD - `str.trim()` -- rimuove gli spazi all'inizio e alla fine della stringa. - `str.repeat(n)` -- ripete la stringa `n` volte. - ...e molto altro. Guarda il [manuale](mdn:js/String) per maggiori dettagli. Le stringhe possiedono anche metodi per eseguire ricerche/rimpiazzi con le regular expression. Ma l'argomento merita un capitolo separato, quindi ci ritorneremo più avanti, . +======= +Strings also have methods for doing search/replace with regular expressions. But that's big topic, so it's explained in a separate tutorial section . + +Also, as of now it's important to know that strings are based on Unicode encoding, and hence there're issues with comparisons. There's more about Unicode in the chapter . +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/1-js/05-data-types/04-array/10-maximal-subarray/solution.md b/1-js/05-data-types/04-array/10-maximal-subarray/solution.md index 3fd599d9e..286f61faa 100644 --- a/1-js/05-data-types/04-array/10-maximal-subarray/solution.md +++ b/1-js/05-data-types/04-array/10-maximal-subarray/solution.md @@ -59,7 +59,11 @@ alert( getMaxSubSum([100, -9, 2, -3, 5]) ); // 100 La soluzione ha una complessità di [O(n2)](https://en.wikipedia.org/wiki/Big_O_notation). In altre parole, se l'array fosse 2 volte più grande, l'algoritmo lavorerebbe 4 volte più lentamente. +<<<<<<< HEAD Per grandi array (1000, 10000 o più elementi) questi algoritmi possono portare ad enormi attese. +======= +For big arrays (1000, 10000 or more items) such algorithms can lead to serious sluggishness. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 # Soluzione performante @@ -91,4 +95,8 @@ alert( getMaxSubSum([-1, -2, -3]) ); // 0 L'algoritmo richiede esattamente uno solo scorrimento dell'array, quindi la complessità è O(n). +<<<<<<< HEAD Potete trovare maggiori dettagli riguardo l'algoritmo qui: [Maximum subarray problem](http://en.wikipedia.org/wiki/Maximum_subarray_problem). Se ancora non vi risulta ovvio il funzionamento, esaminate più in dettaglio il codice fornito sopra. +======= +You can find more detailed information about the algorithm here: [Maximum subarray problem](http://en.wikipedia.org/wiki/Maximum_subarray_problem). If it's still not obvious why that works, then please trace the algorithm on the examples above, see how it works, that's better than any words. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/1-js/05-data-types/04-array/2-create-array/task.md b/1-js/05-data-types/04-array/2-create-array/task.md index fa23ed227..f48d73a45 100644 --- a/1-js/05-data-types/04-array/2-create-array/task.md +++ b/1-js/05-data-types/04-array/2-create-array/task.md @@ -6,11 +6,19 @@ importance: 5 Proviamo 5 operazioni su un array. +<<<<<<< HEAD 1. Create un array `styles` con gli elementi "Jazz" e "Blues". 2. Aggiungete "Rock-n-Roll" in coda. 3. Rimpiazzate l'elemento al centro con "Classics". Il codice che utilizzerete per trovare il centro dovrebbe funzionare con qualsiasi array, anche di lunghezza dispari. 4. Prelevate il primo elemento dell'array e mostratelo. 5. Aggiungete in testa `Rap` e `Reggae` . +======= +1. Create an array `styles` with items "Jazz" and "Blues". +2. Append "Rock-n-Roll" to the end. +3. Replace the value in the middle with "Classics". Your code for finding the middle value should work for any arrays with odd length. +4. Strip off the first value of the array and show it. +5. Prepend `Rap` and `Reggae` to the array. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Le evoluzioni dell'array: diff --git a/1-js/05-data-types/04-array/3-call-array-this/task.md b/1-js/05-data-types/04-array/3-call-array-this/task.md index 62cb0d410..11c9a4799 100644 --- a/1-js/05-data-types/04-array/3-call-array-this/task.md +++ b/1-js/05-data-types/04-array/3-call-array-this/task.md @@ -11,7 +11,7 @@ let arr = ["a", "b"]; arr.push(function() { alert( this ); -}) +}); arr[2](); // ? ``` diff --git a/1-js/05-data-types/04-array/article.md b/1-js/05-data-types/04-array/article.md index da0cc1329..2811fe361 100644 --- a/1-js/05-data-types/04-array/article.md +++ b/1-js/05-data-types/04-array/article.md @@ -92,6 +92,38 @@ let fruits = [ La "virgola pendente" rende più semplice inserire/rimuovere elementi, perché tutte le linee seguono la stessa struttura. ```` +## Get last elements with "at" + +[recent browser="new"] + +Let's say we want the last element of the array. + +Some programming languages allow the use of negative indexes for the same purpose, like `fruits[-1]`. + +Although, in JavaScript it won't work. The result will be `undefined`, because the index in square brackets is treated literally. + +We can explicitly calculate the last element index and then access it: `fruits[fruits.length - 1]`. + +```js run +let fruits = ["Apple", "Orange", "Plum"]; + +alert( fruits[fruits.length-1] ); // Plum +``` + +A bit cumbersome, isn't it? We need to write the variable name twice. + +Luckily, there's a shorter syntax: `fruits.at(-1)`: + +```js run +let fruits = ["Apple", "Orange", "Plum"]; + +// same as fruits[fruits.length-1] +alert( fruits.at(-1) ); // Plum +``` + +In other words, `arr.at(i)`: +- is exactly the same as `arr[i]`, if `i >= 0`. +- for negative values of `i`, it steps back from the end of the array. ## I metodi pop/push, shift/unshift @@ -121,9 +153,15 @@ Uno stack viene spesso illustrato come un pacco di carte: le nuove carte vengono Negli gli stack, l'ultimo elemento inserito viene prelevato per primo. Questo comportamento viene definito LIFO (Last-In-First-Out). Nel caso delle code, il comportamento viene chiamato FIFO (First-In-First-Out). +<<<<<<< HEAD Gli array in JavaScript possono implementare sia una queue che uno stack. C'è la possibilità di aggiungere/rimuovere elementi sia in cima che in coda. In informatica questa struttura dati si chiama [deque](https://en.wikipedia.org/wiki/Double-ended_queue). +======= +Arrays in JavaScript can work both as a queue and as a stack. They allow you to add/remove elements, both to/from the beginning or the end. + +In computer science, the data structure that allows this, is called [deque](https://en.wikipedia.org/wiki/Double-ended_queue). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 **Metodi che operano sulla coda di un array:** @@ -138,6 +176,8 @@ In informatica questa struttura dati si chiama [deque](https://en.wikipedia.org/ alert( fruits ); // Apple, Orange ``` + Both `fruits.pop()` and `fruits.at(-1)` return the last element of the array, but `fruits.pop()` also modifies the array by removing it. + `push` : Inserisce l'elemento in coda all'array: @@ -248,7 +288,11 @@ Perché è più veloce eseguire operazioni sulla coda degli array rispetto a que fruits.shift(); // prende 1 elemento dall'inizio ``` +<<<<<<< HEAD Non è sufficiente prelevare e rimuovere l'elemento con l'indice `0`. Gli altri elementi dovranno essere rinumerati. +======= +It's not enough to take and remove the element with the index `0`. Other elements need to be renumbered as well. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 L'operazione di `shift` deve seguire 3 passi: @@ -365,11 +409,19 @@ C'è un ulteriore sintassi per creare un array: let arr = *!*new Array*/!*("Apple", "Pear", "etc"); ``` +<<<<<<< HEAD Viene utilizzata raramente, le parentesi `[]` risultano più brevi. Anche se c'è una caratteristica interessante che va osservata. +======= +It's rarely used, because square brackets `[]` are shorter. Also, there's a tricky feature with it. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Se utilizziamo `new Array` con un solo argomento di tipo numerico, allora verrà creato un array *vuoto, ma con lunghezza data*. +<<<<<<< HEAD Quindi vediamo come ci si potrebbe sparare da soli al piede: +======= +Let's see how one can shoot themselves in the foot: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let arr = new Array(2); // creerà un array [2] ? @@ -394,7 +446,11 @@ let matrix = [ [7, 8, 9] ]; +<<<<<<< HEAD alert( matrix[1][1] ); // l'elemento centrale +======= +alert( matrix[0][1] ); // 2, the second value of the first inner array +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` ## toString @@ -441,7 +497,11 @@ Ricordando velocemente le regole: - Se uno dei due argomenti forniti all'operatore `==` è un oggetto, e l'altro è un tipo primitivo, allora l'oggetto viene convertito a primitivo, come spiegato nel capitolo . - ...Con l'eccezione di `null` e `undefined` che sono uguali solamente tra di loro. +<<<<<<< HEAD Il confronto stretto con l'operatore `===` è ancora più semplice, poiché non converte i tipi. +======= +The strict comparison `===` is even simpler, as it doesn't convert types. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Quindi, se confrontiamo array con `==`, non saranno mai equivalenti, a meno chè non confrontiamo due variabili che fanno riferimento allo stesso array. @@ -461,7 +521,11 @@ alert( 0 == [] ); // true alert('0' == [] ); // false ``` +<<<<<<< HEAD Qui, in entrambi i casi, stiamo confrontando un tipo primitivo con un array. Quindi l'array `[]` viene convertito in tipo primitivo per effettuare il confronto e diventa una stringa vuota `''`. +======= +Here, in both cases, we compare a primitive with an array object. So the array `[]` gets converted to primitive for the purpose of comparison and becomes an empty string `''`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Successivamente il processo di confronto procede come descritto nel capitolo : @@ -480,6 +544,7 @@ Molto semplice: non utilizzando l'operatore`==`. Invece, vanno confrontati con u Gli array sono uno speciale tipo di oggetto, studiati per immagazzinare e gestire collezioni ordinate di dati. +<<<<<<< HEAD - La dichiarazione: ```js @@ -491,11 +556,33 @@ Gli array sono uno speciale tipo di oggetto, studiati per immagazzinare e gestir ``` La chiamata a `new Array(number)` crea un array con la lunghezza data, ma senza elementi. +======= +The declaration: + +```js +// square brackets (usual) +let arr = [item1, item2...]; + +// new Array (exceptionally rare) +let arr = new Array(item1, item2...); +``` + +The call to `new Array(number)` creates an array with the given length, but without elements. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 - La proprietà `length` è la lunghezza dell'array; in realtà, per essere precisi, contiene l'indice dell'ultimo elemento più uno. Questo valore viene aggiornato automaticamente. - Se decrementiamo manualmente `length`, l'array viene troncato. +<<<<<<< HEAD Possiamo eseguire sugli arrays le seguenti operazioni: +======= +Getting the elements: + +- we can get element by its index, like `arr[0]` +- also we can use `at(i)` method that allows negative indexes. For negative values of `i`, it steps back from the end of the array. If `i >= 0`, it works same as `arr[i]`. + +We can use an array as a deque with the following operations: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 - `push(...items)` aggiunge `items` in coda. - `pop()` rimuove un elemento dalla coda e lo ritorna. diff --git a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/test.js b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/test.js index db32d9a11..241b74c6e 100644 --- a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/test.js +++ b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/test.js @@ -4,13 +4,13 @@ describe("filterRangeInPlace", function() { let arr = [5, 3, 8, 1]; - filterRangeInPlace(arr, 1, 4); + filterRangeInPlace(arr, 2, 5); - assert.deepEqual(arr, [3, 1]); + assert.deepEqual(arr, [5, 3]); }); it("doesn't return anything", function() { assert.isUndefined(filterRangeInPlace([1,2,3], 1, 4)); }); -}); \ No newline at end of file +}); diff --git a/1-js/05-data-types/05-array-methods/article.md b/1-js/05-data-types/05-array-methods/article.md index 115839ebe..19309d202 100644 --- a/1-js/05-data-types/05-array-methods/article.md +++ b/1-js/05-data-types/05-array-methods/article.md @@ -1,6 +1,10 @@ # Metodi per gli array +<<<<<<< HEAD Gli array forniscono una gran quantità di metodi. Per rendere le cose più semplici, in questo capitolo li abbiamo divisi per gruppi. +======= +Arrays provide a lot of methods. To make things easier, in this chapter, they are split into groups. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Aggiungere/rimuovere elementi @@ -32,11 +36,19 @@ alert( arr.length ); // 3 L'elemento viene rimosso, ma l'array ha ancora 3 elementi, possiamo vederlo tramite `arr.length == 3`. +<<<<<<< HEAD Non è una sorpresa, perché `delete obj.key` rimuove un valore dalla `key`. Questo è tutto quello che fa. Può andare bene per gli oggetti. Con gli array vorremmo che il resto degli elementi scalassero, andando ad occupare il posto che si è liberato. Per questo ci aspetteremmo di avere un array più corto. +======= +That's natural, because `delete obj.key` removes a value by the `key`. It's all it does. Fine for objects. But for arrays we usually want the rest of the elements to shift and occupy the freed place. We expect to have a shorter array now. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Per questo scopo sono stati sviluppati dei metodi dedicati. +<<<<<<< HEAD Il metodo [arr.splice](mdn:js/Array/splice) è un coltellino svizzero per array. Può fare qualsiasi cosa: aggiungere e rimuovere elementi, ovunque. +======= +The [arr.splice](mdn:js/Array/splice) method is a Swiss army knife for arrays. It can do everything: insert, remove and replace elements. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 La sintassi è: @@ -62,7 +74,11 @@ alert( arr ); // ["I", "JavaScript"] Facile, vero? Ha rimosso `1` elemento, a partire dall'elemento `1`. +<<<<<<< HEAD Nel prossimo esempio, rimuoviamo 3 elementi e li rimpiazziamo con altri due: +======= +In the next example, we remove 3 elements and replace them with the other two: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let arr = [*!*"I", "study", "JavaScript",*/!* "right", "now"]; @@ -84,7 +100,11 @@ let removed = arr.splice(0, 2); alert( removed ); // "I", "study" <-- array di elementi rimossi ``` +<<<<<<< HEAD Il metodo `splice` è anche in grado di inserire elementi senza alcuna rimozione. Per ottenere questo dobbiamo impostare `deleteCount` a `0`: +======= +The `splice` method is also able to insert the elements without any removals. For that, we need to set `deleteCount` to `0`: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let arr = ["I", "study", "JavaScript"]; @@ -114,7 +134,11 @@ alert( arr ); // 1,2,3,4,5 ### slice +<<<<<<< HEAD Il metodo [arr.slice](mdn:js/Array/slice) è più semplice di `arr.splice`. +======= +The method [arr.slice](mdn:js/Array/slice) is much simpler than the similar-looking `arr.splice`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 La sintassi è: @@ -124,7 +148,11 @@ arr.slice([start], [end]) Ritorna un nuovo array contente tutti gli elementi a partire da `"start"` fino ad `"end"` (`"end"` escluso). Sia `start` che `end` possono essere negativi; in tal caso si inizierà a contare dalla coda dell'array. +<<<<<<< HEAD Funziona come `str.slice`, ma crea dei sotto-array piuttosto che sotto-stringhe. +======= +It's similar to a string method `str.slice`, but instead of substrings, it makes subarrays. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio: @@ -206,7 +234,11 @@ Il metodo [arr.forEach](mdn:js/Array/forEach) consente di eseguire una funzione La sintassi: ```js arr.forEach(function(item, index, array) { +<<<<<<< HEAD // ... fa qualcosa con l'elemento +======= + // ... do something with an item +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 }); ``` @@ -234,6 +266,7 @@ Ora vedremo dei metodi per effettuare ricerche in un array. ### indexOf/lastIndexOf e include +<<<<<<< HEAD I metodi [arr.indexOf](mdn:js/Array/indexOf), [arr.lastIndexOf](mdn:js/Array/lastIndexOf) e [arr.includes](mdn:js/Array/includes) hanno la stessa sintassi, e fanno praticamente la stessa cosa della loro controparte per stringhe, ma operano su elementi invece che su caratteri: - `arr.indexOf(item, from)` cerca un `item` a partire dall'indirizzo `from`, e ritorna l'indirizzo in cui è stato trovato, altrimenti ritorna `-1`. @@ -241,6 +274,16 @@ I metodi [arr.indexOf](mdn:js/Array/indexOf), [arr.lastIndexOf](mdn:js/Array/las - `arr.includes(item, from)` -- cerca un `item` a partire dall'indice `from`, e ritorna `true` se lo trova. Ad esempio: +======= +The methods [arr.indexOf](mdn:js/Array/indexOf) and [arr.includes](mdn:js/Array/includes) have the similar syntax and do essentially the same as their string counterparts, but operate on items instead of characters: + +- `arr.indexOf(item, from)` -- looks for `item` starting from index `from`, and returns the index where it was found, otherwise `-1`. +- `arr.includes(item, from)` -- looks for `item` starting from index `from`, returns `true` if found. + +Usually, these methods are used with only one argument: the `item` to search. By default, the search is from the beginning. + +For instance: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let arr = [1, 0, false]; @@ -252,6 +295,7 @@ alert( arr.indexOf(null) ); // -1 alert( arr.includes(1) ); // true ``` +<<<<<<< HEAD Da notare che questi metodi usano il confronto `===`. Quindi, se cerchiamo `false`, troveremo esattamente `false` e non zero. Se vogliamo solo verificare la presenza di un elemento, senza voler conoscere l'indirizzo, è preferibile utilizzare il metodo `arr.includes`. @@ -262,11 +306,41 @@ Inoltre, una piccola differenza è che `includes` gestisce correttamente `NaN`, const arr = [NaN]; alert( arr.indexOf(NaN) ); // -1 (dovrebbe essere 0, ma l'uguaglianza === non funziona con NaN) alert( arr.includes(NaN) );// true (corretto) +======= +Please note that `indexOf` uses the strict equality `===` for comparison. So, if we look for `false`, it finds exactly `false` and not the zero. + +If we want to check if `item` exists in the array and don't need the index, then `arr.includes` is preferred. + +The method [arr.lastIndexOf](mdn:js/Array/lastIndexOf) is the same as `indexOf`, but looks for from right to left. + +```js run +let fruits = ['Apple', 'Orange', 'Apple'] + +alert( fruits.indexOf('Apple') ); // 0 (first Apple) +alert( fruits.lastIndexOf('Apple') ); // 2 (last Apple) ``` +````smart header="The `includes` method handles `NaN` correctly" +A minor, but noteworthy feature of `includes` is that it correctly handles `NaN`, unlike `indexOf`: + +```js run +const arr = [NaN]; +alert( arr.indexOf(NaN) ); // -1 (wrong, should be 0) +alert( arr.includes(NaN) );// true (correct) +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 +``` +That's because `includes` was added to JavaScript much later and uses the more up-to-date comparison algorithm internally. +```` + +<<<<<<< HEAD ### find e findIndex Immaginiamo di avere un array di oggetti. Come possiamo trovare un oggetto che soddisfi specifiche condizioni? +======= +### find and findIndex/findLastIndex + +Imagine we have an array of objects. How do we find an object with a specific condition? +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 In questi casi si utilizza il metodo [arr.find](mdn:js/Array/find). @@ -284,7 +358,11 @@ La funzione viene chiamata per ogni elemento dell'array: - `index` è il suo indice. - `array` è l'array stesso. +<<<<<<< HEAD Se la chiamata ritorna `true`, la ricerca viene interrotta e viene ritornato `item`. Se non viene trovato nulla verrà ritornato `undefined`. +======= +If it returns `true`, the search is stopped, the `item` is returned. If nothing is found, `undefined` is returned. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio, abbiamo un array di utenti, ognuno con i campi `id` e `name`. Cerchiamo quello con `id == 1`: @@ -300,11 +378,38 @@ let user = users.find(item => item.id == 1); alert(user.name); // John ``` +<<<<<<< HEAD Gli array di oggetti sono molto comuni, quindi il metodo `find` risulta molto utile. +======= +In real life, arrays of objects are a common thing, so the `find` method is very useful. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Da notare che nell'esempio noi forniamo a `find` un singolo argomento `item => item.id == 1`. Gli altri parametri di `find` sono raramente utilizzati. +<<<<<<< HEAD Il metodo [arr.findIndex](mdn:js/Array/findIndex) fa essenzialmente la stessa cosa, ma ritorna l'indice in cui è stata trovata la corrispondenza piuttosto di ritornare l'oggetto stesso; se l'oggetto non viene trovato ritorna `-1`. +======= +The [arr.findIndex](mdn:js/Array/findIndex) method has the same syntax but returns the index where the element was found instead of the element itself. The value of `-1` is returned if nothing is found. + +The [arr.findLastIndex](mdn:js/Array/findLastIndex) method is like `findIndex`, but searches from right to left, similar to `lastIndexOf`. + +Here's an example: + +```js run +let users = [ + {id: 1, name: "John"}, + {id: 2, name: "Pete"}, + {id: 3, name: "Mary"}, + {id: 4, name: "John"} +]; + +// Find the index of the first John +alert(users.findIndex(user => user.name == 'John')); // 0 + +// Find the index of the last John +alert(users.findLastIndex(user => user.name == 'John')); // 3 +``` +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ### filter @@ -388,7 +493,12 @@ Letteralmente, tutti gli elementi vengono convertiti in stringhe e confrontati. Per utilizzare un ordinamento arbitrario, dobbiamo fornire una funzione come argomento di `arr.sort()`. +<<<<<<< HEAD La funzione dovrebbe essere simile a questa: +======= +The function should compare two arbitrary values and return: + +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js function compare(a, b) { if (a > b) return 1; // se il primo valore è maggiore del secondo @@ -417,11 +527,19 @@ alert(arr); // *!*1, 2, 15*/!* Ora funziona come dovrebbe. +<<<<<<< HEAD Proviamo un attimo a capire cosa sta succedendo. L'array `arr` può contenere qualsiasi cosa, giusto? Può contenere numeri, stringhe, elementi HTML o qualsiasi altra cosa. Abbiamo quindi un insieme di *qualcosa*. Per poterlo ordinare abbiamo bisogno di una *funzione di ordinamento* che sappia ordinare gli elementi passati come argomenti. L'ordinamento di default è di tipo stringa. +======= +Let's step aside and think about what's happening. The `arr` can be an array of anything, right? It may contain numbers or strings or objects or whatever. We have a set of *some items*. To sort it, we need an *ordering function* that knows how to compare its elements. The default is a string order. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Il metodo `arr.sort(fn)` implementa un algoritmo di ordinamento. Non dovremmo preoccuparci di come funzioni esattamente (la maggior parte delle volte è un [quicksort](https://en.wikipedia.org/wiki/Quicksort) ottimizzato). Questo algoritmo attraverserà l'intero array e confronterà i suoi valori; tutto quello che dobbiamo fare sarà fornirgli una funzione `fn` che esegua il confronto. +<<<<<<< HEAD In ogni caso, se mai volessimo conoscere quali elementi vengono comparati -- nulla ci vieta di utilizzare `alert`: +======= +By the way, if we ever want to know which elements are compared -- nothing prevents us from alerting them: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run [1, -2, 15, 2, 0, 8].sort(function(a, b) { @@ -494,7 +612,11 @@ Vediamo una situazione reale. Stiamo scrivendo un'applicazione di messaggistica, Il metodo [str.split(delim)](mdn:js/String/split) fa esattamente questo. Divide la stringa in un array utilizzando il delimitatore `delim`. +<<<<<<< HEAD Nell'esempio sotto, utilizziamo come delimitatore una virgola seguita da uno spazio: +======= +In the example below, we split by a comma followed by a space: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let names = 'Bilbo, Gandalf, Nazgul'; @@ -560,9 +682,15 @@ Argomenti: - `index` -- la sua posizione. - `array` -- l'array. +<<<<<<< HEAD Quando la funzione è stata applicata, il risultato viene passato alla chiamata successiva. Sembra complicato, ma non lo è se pensate al primo argomento come un "accumulatore" che memorizza il risultato delle precedenti esecuzioni. E alla fine diventa il risultato di `reduce`. +======= +As the function is applied, the result of the previous function call is passed to the next one as the first argument. + +So, the first argument is essentially the accumulator that stores the combined result of all previous executions. And at the end, it becomes the result of `reduce`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Il modo più semplice per spiegarlo è tramite esempi. @@ -629,10 +757,14 @@ arr.reduce((sum, current) => sum + current); ``` +<<<<<<< HEAD Quindi è fortemente consigliato di specificare sempre un valore iniziale. Il metodo [arr.reduceRight](mdn:js/Array/reduceRight) fa esattamente la stessa cosa, ma da destra verso sinistra. +======= +The method [arr.reduceRight](mdn:js/Array/reduceRight) does the same but goes from right to left. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Array.isArray @@ -642,7 +774,11 @@ Quindi `typeof` non aiuta a distinguere un oggetto da un array: ```js run alert(typeof {}); // object +<<<<<<< HEAD alert(typeof []); // lo stesso +======= +alert(typeof []); // object (same) +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` ...Ma gli array vengono utilizzati cosi spesso che esiste un metodo dedicato per questo: [Array.isArray(value)](mdn:js/Array/isArray). Ritorna `true` se `value` è un array, `false` altrimenti. @@ -657,7 +793,11 @@ alert(Array.isArray([])); // true Quasi tutti i metodi degli array che richiedono una funzione -- come `find`, `filter`, `map`, fatta eccezione per `sort`, accettano un parametro opzionale `thisArg`. +<<<<<<< HEAD Questo parametro non è stato spiegato nella sezione sopra, perché viene raramente utilizzato. Studiamolo per completezza. +======= +That parameter is not explained in the sections above, because it's rarely used. But for completeness, we have to cover it. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Vediamo la sintassi di questi metodi: @@ -709,6 +849,7 @@ Una chiamata a `user.filter(army.canJoin, army)` può essere sostituita da Un breve riepilogo dei metodi per array: +<<<<<<< HEAD - Per aggiungere/rimuovere elementi: - `push(...items)` -- aggiunge elementi in coda, - `pop()` -- estrae un elemento dalla coda, @@ -717,6 +858,13 @@ Un breve riepilogo dei metodi per array: - `splice(pos, deleteCount, ...items)` -- all'indice `pos` cancella `deleteCount` elementi e al loro posto inserisce `items`. - `slice(start, end)` -- crea un nuovo array e copia al suo interno gli elementi da `start` fino ad `end` (escluso). - `concat(...items)` -- ritorna un nuovo array: copia tutti gli elementi di quello corrente e ci aggiunge `items`. Se uno degli `items` è un array, allora vengono presi anche i suoi elementi. +======= +- To search among elements: + - `indexOf/lastIndexOf(item, pos)` -- look for `item` starting from position `pos`, and return the index or `-1` if not found. + - `includes(value)` -- returns `true` if the array has `value`, otherwise `false`. + - `find/filter(func)` -- filter elements through the function, return first/all values that make it return `true`. + - `findIndex` is like `find`, but returns the index instead of a value. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 - Ricercare elementi: - `indexOf/lastIndexOf(item, pos)` -- cerca `item` a partire da `pos`, e ritorna l'indice, oppure `-1` se non lo trova. @@ -727,12 +875,17 @@ Un breve riepilogo dei metodi per array: - Per iterare sugli elementi: - `forEach(func)` -- invoca `func` su ogni elemento; non ritorna nulla. +<<<<<<< HEAD - Per modificare un array: - `map(func)` -- crea un nuovo array con i risultati della chiamata `func` su tutti i suoi elementi. - `sort(func)` -- ordina l'array "sul posto", e lo ritorna. - `reverse()` -- inverte l'array sul posto, e lo ritorna. - `split/join` -- converte una stringa in array e vice versa. - `reduce/reduceRight(func, initial)` -- calcola un singolo valore chiamando `func` per ogni elemento e passando un risultato temporaneo tra una chiamata e l'altra +======= +- Additionally: + - `Array.isArray(value)` checks `value` for being an array, if so returns `true`, otherwise `false`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 - Un altro metodo utile: - `Array.isArray(arr)` controlla che `arr` sia un array. @@ -747,7 +900,12 @@ I metodi elencati sono quelli utilizzati più spesso e sono in grado di coprire Questi metodi si comportano quasi come gli operatori `||` e `&&`: se `fn` ritorna un valore vero, `arr.some()` ritorna immediatamente `true` e conclude l'iterazione; se `fn` ritorna un valore falso, `arr.every()` ritorna immediatamente `false` e smette di iterare. +<<<<<<< HEAD Possiamo utilizzare `every` per confrontare gli array: +======= + We can use `every` to compare arrays: + +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run function arraysEqual(arr1, arr2) { return arr1.length === arr2.length && arr1.every((value, index) => value === arr2[index]); @@ -764,7 +922,11 @@ I metodi elencati sono quelli utilizzati più spesso e sono in grado di coprire Per la lista completa, vedere il [manuale](mdn:js/Array). +<<<<<<< HEAD A prima vista potrebbero sembrare molti metodi da ricordare. Ma in realtà è molto più semplice di quanto sembri. +======= +At first sight, it may seem that there are so many methods, quite difficult to remember. But actually, that's much easier. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Tenente sempre un occhio al riassunto fornito sopra. Provate anche a risolvere gli esercizi di questo capitolo. diff --git a/1-js/05-data-types/06-iterable/article.md b/1-js/05-data-types/06-iterable/article.md index fc03b3c7f..0e03890d1 100644 --- a/1-js/05-data-types/06-iterable/article.md +++ b/1-js/05-data-types/06-iterable/article.md @@ -27,10 +27,17 @@ let range = { Per rendere iterabile l'oggetto `range` (e poter quindi utilizzare correttamente `for..of`) abbiamo bisogno di aggiungervi un metodo chiamato `Symbol.iterator` (uno speciale simbolo integrato). +<<<<<<< HEAD 1. Quando `for..of` inizia, prova a chiamare questo metodo (o ritorna un errore se non lo trova). Il metodo deve ritornare un *iteratore* -- un oggetto con il metodo `next`. 2. La possibilità di avanzare di `for..of` funziona *solamente con l'oggetto ritornato*. 3. Quando `for..of` vuole il prossimo valore, chiama `next()` su quell'oggetto. 4. Il risultato di `next()` deve avere la forma `{done: Boolean, value: any}`, dove `done=true` significa che l'iterazione è completa, altrimenti `value` deve contenere il valore successivo. +======= +1. When `for..of` starts, it calls that method once (or errors if not found). The method must return an *iterator* -- an object with the method `next`. +2. Onward, `for..of` works *only with that returned object*. +3. When `for..of` wants the next value, it calls `next()` on that object. +4. The result of `next()` must have the form `{done: Boolean, value: any}`, where `done=true` means that the loop is finished, otherwise `value` is the next value. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Qui l'implementazione completa per `range`: @@ -43,11 +50,16 @@ let range = { // 1. la chiamata a for..of inizialmente chiama questo range[Symbol.iterator] = function() { +<<<<<<< HEAD // ...ritorna l'oggetto iteratore: // 2. Da qui in poi, for..of lavora solamente con questo iteratore, richiedendogli il prossimo valore +======= + // ...it returns the iterator object: + // 2. Onward, for..of works only with the iterator object below, asking it for next values +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 return { current: this.from, - last: this.to, + last: this.to, // 3. next() viene invocato ad ogni iterazione del ciclo for..of next() { @@ -175,7 +187,11 @@ Naturalmente, queste proprietà possono essere combinate. Ad esempio, le stringh Ma un oggetto iterabile potrebbe non essere array-like. E vice versa un array-like potrebbe non essere un oggetto iterabile. +<<<<<<< HEAD Ad esempio, l'esempio `range` utilizzato sopra è un oggetto iterabile, ma non array-like, poiché non possiede degli indici e la proprietà `length`. +======= +But an iterable may not be array-like. And vice versa an array-like may not be iterable. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Qui invece vediamo un esempio di oggetto array-like, ma che non è iterabile: @@ -217,8 +233,13 @@ alert(arr.pop()); // World (il metodo funziona) Si comporta allo stesso modo con un oggetto iterabile: +<<<<<<< HEAD ```js // assumiamo che il range venga preso dall'esempio sopra +======= +```js run +// assuming that range is taken from the example above +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 let arr = Array.from(range); alert(arr); // 1,2,3,4,5 (la conversione array toString funziona) ``` @@ -232,8 +253,13 @@ Il secondo argomento `mapFn` (opzionale) è una funzione da applicare ad ogni el Ad esempio: +<<<<<<< HEAD ```js // assumiamo che il range venga preso dall'esempio sopra +======= +```js run +// assuming that range is taken from the example above +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 // quadrato di ogni numero let arr = Array.from(range, num => num * num); @@ -269,7 +295,11 @@ for (let char of str) { alert(chars); ``` +<<<<<<< HEAD ...Ma è più breve. +======= +...But it is shorter. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Possiamo anche eseguire un surrogato di `slice`: diff --git a/1-js/05-data-types/07-map-set/article.md b/1-js/05-data-types/07-map-set/article.md index 5c8ba5d16..6d0a3b919 100644 --- a/1-js/05-data-types/07-map-set/article.md +++ b/1-js/05-data-types/07-map-set/article.md @@ -10,10 +10,15 @@ Queste però non sono sufficienti. Esistono ulteriori strutture dati, come `Map` ## Map +<<<<<<< HEAD [Map](mdn:js/Map) è una collezione di dati identificati da chiavi, proprio come un `Object` (Oggetto). La principale differenza è che `Map` accetta chiavi di qualsiasi tipo. +======= +[Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) is a collection of keyed data items, just like an `Object`. But the main difference is that `Map` allows keys of any type. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 I metodi e le proprietà sono: +<<<<<<< HEAD - `new Map()` -- crea la mappa. - `map.set(key, value)` -- memorizza il valore `value` con la chiave `key`. - `map.get(key)` -- ritorna il valore associato alla chiave `key`, `undefined` nel caos in cui `key` non esista. @@ -21,6 +26,15 @@ I metodi e le proprietà sono: - `map.delete(key)` -- rimuove il valore con la chiave `key`. - `map.clear()` -- rimuove tutti gli elementi. - `map.size` -- ritorna il numero di elementi contenuti. +======= +- [`new Map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/Map) -- creates the map. +- [`map.set(key, value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set) -- stores the value by the key. +- [`map.get(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get) -- returns the value by the key, `undefined` if `key` doesn't exist in map. +- [`map.has(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has) -- returns `true` if the `key` exists, `false` otherwise. +- [`map.delete(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete) -- removes the element (the key/value pair) by the key. +- [`map.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear) -- removes everything from the map. +- [`map.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size) -- returns the current element count. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio: @@ -98,15 +112,27 @@ map.set('1', 'str1') ``` ```` +<<<<<<< HEAD ## Iterare su Map Per iterare attraverso gli elementi di `Map`, esistono 3 metodi: +======= +## Iteration over Map +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 - `map.keys()` -- ritorna un oggetto per iterare sulle chiavi, - `map.values()` -- ritorna un oggetto per iterare sui valori, - `map.entries()` -- ritorna un oggetto per iterare sulle coppie `[key, value]`, ed è il metodo utilizzato di default nel ciclo `for..of`. +<<<<<<< HEAD Ad esempio: +======= +- [`map.keys()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/keys) -- returns an iterable for keys, +- [`map.values()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/values) -- returns an iterable for values, +- [`map.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries) -- returns an iterable for entries `[key, value]`, it's used by default in `for..of`. + +For instance: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let recipeMap = new Map([ @@ -159,7 +185,11 @@ let map = new Map([ alert( map.get('1') ); // str1 ``` +<<<<<<< HEAD Se abbiamo un semplice oggetto, e vogliamo utilizzarlo per creare una `Map`, possiamo utilizzare un metodo integrato degli oggetti [Object.entries(obj)](mdn:js/Object/entries) il quale ritorna un array di coppie chiave/valore nello stesso formato. +======= +If we have a plain object, and we'd like to create a `Map` from it, then we can use built-in method [Object.entries(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries) that returns an array of key/value pairs for an object exactly in that format. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Quindi possiamo creare una `Map` da un oggetto, così: @@ -230,16 +260,29 @@ L'espressione è equivalente, poiché `Object.fromEntries` si aspetta di ricever ## Set +<<<<<<< HEAD Un `Set` è un tipo di collezione speciale - "set di valori" (senza chiavi), dove ogni valore può apparire una sola volta. +======= +A [`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) is a special type collection - "set of values" (without keys), where each value may occur only once. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 I suoi metodi principali sono: +<<<<<<< HEAD - `new Set(iterable)` -- crea il set, e se gli viene fornito un oggetto `iterabile` (solitamente un array), ne copia i valori nel set. - `set.add(value)` -- aggiunge un valore, ritorna il set. - `set.delete(value)` -- rimuove il valore, ritorna `true` se `value` esiste, altrimenti `false`. - `set.has(value)` -- ritorna `true` se il valore esiste nel set, altrimenti `false`. - `set.clear()` -- rimuove tutti i valori dal set. - `set.size` -- ritorna il numero dei valori contenuti. +======= +- [`new Set([iterable])`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/Set) -- creates the set, and if an `iterable` object is provided (usually an array), copies values from it into the set. +- [`set.add(value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/add) -- adds a value, returns the set itself. +- [`set.delete(value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/delete) -- removes the value, returns `true` if `value` existed at the moment of the call, otherwise `false`. +- [`set.has(value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/has) -- returns `true` if the value exists in the set, otherwise `false`. +- [`set.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/clear) -- removes everything from the set. +- [`set.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/size) -- is the elements count. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 La principale caratteristica dei set è che ripetute chiamate di `set.add(value)` con lo stesso valore non fanno nulla. Questo è il motivo per cui in un `Set` ogni valore può comparire una sola volta. @@ -269,7 +312,11 @@ for (let user of set) { } ``` +<<<<<<< HEAD L'alternativa a `Set` potrebbe essere un array di visitatori, e un codice per verificare ogni inserimento ed evitare duplicati, utilizzando [arr.find](mdn:js/Array/find). Ma la performance sarebbe molto inferiore, perché questo metodo attraversa tutto l'array per verificare ogni elemento. `Set` è ottimizzato internamente per il controllo di unicità. +======= +The alternative to `Set` could be an array of users, and the code to check for duplicates on every insertion using [arr.find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find). But the performance would be much worse, because this method walks through the whole array checking every element. `Set` is much better optimized internally for uniqueness checks. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Iterare un Set @@ -288,20 +335,35 @@ set.forEach((value, valueAgain, set) => { Da notare una cosa divertente. La funzione callback fornita a `forEach` ha 3 argomenti: un `value`, poi *lo stesso valore* `valueAgain`, e poi l'oggetto riferito da `this`. Proprio così, lo stesso valore appare due volte nella lista degli argomenti. +<<<<<<< HEAD Questo accade per questioni di compatibilità con `Map`, in cui la funzione callback fornita al `forEach` possiede tre argomenti. E' un po' strano, ma in alcuni casi può aiutare rimpiazzare `Map` con `Set`, e vice versa. +======= +That's for compatibility with `Map` where the callback passed `forEach` has three arguments. Looks a bit strange, for sure. But this may help to replace `Map` with `Set` in certain cases with ease, and vice versa. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Sono supportati anche i metodi di iterazione di `Map`: +<<<<<<< HEAD - `set.keys()` -- ritorna un oggetto per iterare sui valori, - `set.values()` -- lo stesso di `set.keys()`, per compatibilità con `Map`, - `set.entries()` -- ritorna un oggetto per iterare sulle voci `[value, value]`, esiste per compatibilità con `Map`. +======= +- [`set.keys()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/keys) -- returns an iterable object for values, +- [`set.values()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/values) -- same as `set.keys()`, for compatibility with `Map`, +- [`set.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/entries) -- returns an iterable object for entries `[value, value]`, exists for compatibility with `Map`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Riepilogo +<<<<<<< HEAD `Map` è una collezione di valori identificati da chiave. +======= +[`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) -- is a collection of keyed values. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Metodi e proprietà: +<<<<<<< HEAD - `new Map([iterable])` -- crea la mappa, accetta un oggetto iterabile (opzionale, e.g. array) di coppie `[key,value]` per l'inizializzazione. - `map.set(key, value)` -- memorizza il valore con la chiave fornita. - `map.get(key)` -- ritorna il valore associato alla chiave, `undefined` se la `key` non è presente nella `Map`. @@ -309,21 +371,43 @@ Metodi e proprietà: - `map.delete(key)` -- rimuove il valore associato alla chiave. - `map.clear()` -- rimuove ogni elemento dalla mappa. - `map.size` -- ritorna il numero di elementi contenuti nella `map`. +======= +- [`new Map([iterable])`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/Map) -- creates the map, with optional `iterable` (e.g. array) of `[key,value]` pairs for initialization. +- [`map.set(key, value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set) -- stores the value by the key, returns the map itself. +- [`map.get(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get) -- returns the value by the key, `undefined` if `key` doesn't exist in map. +- [`map.has(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has) -- returns `true` if the `key` exists, `false` otherwise. +- [`map.delete(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete) -- removes the element by the key, returns `true` if `key` existed at the moment of the call, otherwise `false`. +- [`map.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear) -- removes everything from the map. +- [`map.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size) -- returns the current element count. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Le differenze da un `Object` standard: - Le chiavi possono essere di qualsiasi tipo, anche oggetti. - Possiede metodi aggiuntivi, come la proprietà `size`. +<<<<<<< HEAD `Set` è una collezione di valori unici. +======= +[`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) -- is a collection of unique values. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Metodi e proprietà: +<<<<<<< HEAD - `new Set([iterable])` -- crea un set, accetta un oggetto iterabile (opzionale, e.g. array) per l'inizializzazione. - `set.add(value)` -- aggiunge un valore (non fa nulla nel caso in cui il valore sia già contenuto nel set), e ritorna il set. - `set.delete(value)` -- rimuove il valore, ritorna `true` se `value` esiste, `false` altrimenti. - `set.has(value)` -- ritorna `true` se il valore esiste nel set, `false` altrimenti. - `set.clear()` -- rimuove tutti i valori dal set. - `set.size` -- ritorna il numero di valori contenuti. +======= +- [`new Set([iterable])`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/Set) -- creates the set, with optional `iterable` (e.g. array) of values for initialization. +- [`set.add(value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/add) -- adds a value (does nothing if `value` exists), returns the set itself. +- [`set.delete(value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/delete) -- removes the value, returns `true` if `value` existed at the moment of the call, otherwise `false`. +- [`set.has(value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/has) -- returns `true` if the value exists in the set, otherwise `false`. +- [`set.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/clear) -- removes everything from the set. +- [`set.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/size) -- is the elements count. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 L'iterazione su `Map` e `Set` segue sempre l'ordine di inserimento, quindi possono essere definite delle collezioni ordinate; non è però possibile riordinare gli elementi oppure ottenere un valore tramite il suo indice. diff --git a/1-js/05-data-types/08-weakmap-weakset/article.md b/1-js/05-data-types/08-weakmap-weakset/article.md index 737dc2ecf..bbb9b5bff 100644 --- a/1-js/05-data-types/08-weakmap-weakset/article.md +++ b/1-js/05-data-types/08-weakmap-weakset/article.md @@ -1,8 +1,18 @@ +<<<<<<< HEAD # WeakMap e WeakSet +======= + +# WeakMap and WeakSet +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Come abbiamo già visto nel capitolo , il motore JavaScript mantiene un valore in memoria fino a che questo risulta accessibile (e potrebbe potenzialmente essere utilizzato). +<<<<<<< HEAD Ad esempio: +======= +For instance: + +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js let john = { name: "John" }; @@ -54,13 +64,21 @@ john = null; // sovrascriviamo il riferimento */!* ``` +<<<<<<< HEAD `WeakMap` è fondamentalmente diverso sotto questo aspetto. Infatti non previene la garbage-collection degli oggetti utilizzati come chiave. +======= +[`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) is fundamentally different in this aspect. It doesn't prevent garbage-collection of key objects. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Vediamo cosa significa questo, utilizzando degli esempi. ## WeakMap +<<<<<<< HEAD La prima differenza tra `Map` e `WeakMap` è che le chiavi devono essere oggetti, non valori primitivi: +======= +The first difference between [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) and [`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) is that keys must be objects, not primitive values: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let weakMap = new WeakMap(); @@ -94,10 +112,10 @@ Confrontiamolo con l'esempio di `Map` visto sopra. Ora, se `john` esiste solo co `WeakMap` possiede solamente i seguenti metodi: -- `weakMap.get(key)` -- `weakMap.set(key, value)` -- `weakMap.delete(key)` -- `weakMap.has(key)` +- [`weakMap.set(key, value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/set) +- [`weakMap.get(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/get) +- [`weakMap.delete(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/delete) +- [`weakMap.has(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/has) Perché questa limitazione? Per ragioni tecniche. Se un oggetto ha perso tutti i riferimenti (come `john` nel codice sopra), allora verrà automaticamente eliminato. Ma tecnicamente non è specificato esattamente *quando avverrà la pulizia*. @@ -182,6 +200,7 @@ function process(obj) { let result = /* calcola il risultato per */ obj; cache.set(obj, result); + return result; } return cache.get(obj); @@ -221,6 +240,7 @@ function process(obj) { let result = /* calcola il risultato per */ obj; cache.set(obj, result); + return result; } return cache.get(obj); @@ -242,11 +262,19 @@ obj = null; ## WeakSet +<<<<<<< HEAD `WeakSet` si comporta in maniera simile: - E' analogo a `Set`, ma possiamo aggiungere solamente oggetti a `WeakSet` (non primitivi). - Un oggetto esiste in un set solamente finché rimane accessibile in un altro punto del codice. - Come `Set`, supporta `add`, `has` e `delete`, ma non `size`, `keys()` e nemmeno gli iteratori. +======= +[`WeakSet`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) behaves similarly: + +- It is analogous to `Set`, but we may only add objects to `WeakSet` (not primitives). +- An object exists in the set while it is reachable from somewhere else. +- Like `Set`, it supports [`add`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Weakset/add), [`has`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Weakset/has) and [`delete`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Weakset/delete), but not `size`, `keys()` and no iterations. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Il fatto che sia "weak" la rende utile come spazio di archiviazione aggiuntivo. Non per dati arbitrari, ma piuttosto per questioni di tipo "si/no". Il fatto di appartenere ad un `WeakSet` può significare qualcosa sull'oggetto. @@ -280,9 +308,15 @@ La maggior limitazione di `WeakMap` e `WeakSet` è l'assenza di iteratori, e la ## Riepilogo +<<<<<<< HEAD `WeakMap` è una collezione simile a `Map`, ma permette di utilizzare solamente oggetti come chiavi; inoltre, la rimozione di un oggetto rimuove anche il valore associato. `WeakSet` è una collezione simile a `Set`, che memorizza solamente oggetti, e li rimuove completamente una volta che diventano inaccessibili. +======= +[`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) is `Map`-like collection that allows only objects as keys and removes them together with associated value once they become inaccessible by other means. + +[`WeakSet`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) is `Set`-like collection that stores only objects and removes them once they become inaccessible by other means. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Il loro principale vantaggio è che possiedono un riferimento debole agli oggetti, in questo modo possono essere facilmente ripuliti dal garbage collector. diff --git a/1-js/05-data-types/10-destructuring-assignment/article.md b/1-js/05-data-types/10-destructuring-assignment/article.md index 02ddc8f65..1f12d0ed8 100644 --- a/1-js/05-data-types/10-destructuring-assignment/article.md +++ b/1-js/05-data-types/10-destructuring-assignment/article.md @@ -2,6 +2,7 @@ Le due strutture dati più utilizzate in JavaScript sono `Object` e `Array`. +<<<<<<< HEAD - Gli oggetti ci consentono di creare un'unica entità che memorizza elementi nel formato chiave-valore - Gli array ci consentono di raccogliere elementi in elenchi ordinati. @@ -10,13 +11,27 @@ A volte, quando li passiamo ad una funzione, potrebbe non essere necessario tutt *L'assegnamento di destrutturazione (Destructuring assignment)* è una speciale sintassi che ci consente di "spacchettare" oggetti o array in gruppi di variabili; questo a volte risulta molto conveniente. La destrutturazione funziona alla grande anche con funzioni complesse che hanno molti parametri, valori predefiniti e così via. Presto lo vedremo. +======= +- Objects allow us to create a single entity that stores data items by key. +- Arrays allow us to gather data items into an ordered list. + +However, when we pass these to a function, we may not need all of it. The function might only require certain elements or properties. + +*Destructuring assignment* is a special syntax that allows us to "unpack" arrays or objects into a bunch of variables, as sometimes that's more convenient. + +Destructuring also works well with complex functions that have a lot of parameters, default values, and so on. Soon we'll see that. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Destrutturazione di un array Ecco un esempio di come un array viene destrutturato in variabili: ```js +<<<<<<< HEAD // abbiamo un array con nome e cognome +======= +// we have an array with a name and surname +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 let arr = ["John", "Smith"] *!* @@ -40,8 +55,15 @@ alert(firstName); // John alert(surname); // Smith ``` +<<<<<<< HEAD Come puoi vedere, la sintassi è semplice. Ci sono però molti dettagli peculiari. Vediamo altri esempi, per capirlo meglio. +======= +As you can see, the syntax is simple. There are several peculiar details though. Let's see more examples to understand it better. + +````smart header="\"Destructuring\" does not mean \"destructive\"." +It's called "destructuring assignment," because it "destructurizes" by copying items into variables. However, the array itself is not modified. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ````smart header="\"Destrutturazione\" non significa \"distruzione\"." Viene chiamato "assegnamento di destrutturazione" perché "destruttura" copiando gli elementi all'interno di variabili. Ma l'array in sé non viene modificato. @@ -67,7 +89,11 @@ let [firstName, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic alert( title ); // Consul ``` +<<<<<<< HEAD Nel codice sopra, il secondo elemento viene saltato, il terzo viene assegnato a `title`, il resto degli elementi vengono ignorati (visto che per loro non ci sono variabili). +======= +In the code above, the second element of the array is skipped, the third one is assigned to `title`, and the rest of the array items are also skipped (as there are no variables for them). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```` ````smart header="Funziona con qualsiasi iterabile alla destra" @@ -78,13 +104,22 @@ Nel codice sopra, il secondo elemento viene saltato, il terzo viene assegnato a let [a, b, c] = "abc"; // ["a", "b", "c"] let [one, two, three] = new Set([1, 2, 3]); ``` +<<<<<<< HEAD Funziona, perché internamente un'assegnazione di destrutturazione lavora iterando sul valore a destra. E' una specie di "zucchero sintattico" per chiamare `for..of` sul valore a destra di `=`, assegnandone i valori. +======= +That works, because internally a destructuring assignment works by iterating over the right value. It's a kind of syntax sugar for calling `for..of` over the value to the right of `=` and assigning the values. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```` ````smart header="Assegna a qualsiasi cosa ci sia dalla parte sinistra" +<<<<<<< HEAD Possiamo inserire qualsiasi cosa "assegnabile" a sinistra. +======= +````smart header="Assign to anything at the left-side" +We can use any "assignables" on the left side. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio, la proprietà di un oggetto: ```js run @@ -97,11 +132,18 @@ alert(user.surname); // Smith ```` +<<<<<<< HEAD ````smart header="Eseguire cicli con .entries()" Nel capitolo precedente abbiamo visto il metodo [Object.entries(obj)](mdn:js/Object/entries). Possiamo utilizzarlo con la destrutturazione per eseguire cicli sulle coppie chiave/valore di un oggetto: +======= +````smart header="Looping with .entries()" +In the previous chapter, we saw the [Object.entries(obj)](mdn:js/Object/entries) method. + +We can use it with destructuring to loop over the keys-and-values of an object: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let user = { @@ -109,7 +151,11 @@ let user = { age: 30 }; +<<<<<<< HEAD // ciclo su chiavi/valori +======= +// loop over the keys-and-values +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 *!* for (let [key, value] of Object.entries(user)) { */!* @@ -177,13 +223,21 @@ Se vogliamo ottenere anche tutto ciò che segue, possiamo aggiungere un altro pa let [name1, name2, *!*...rest*/!*] = ["Julius", "Caesar", *!*"Consul", "of the Roman Republic"*/!*]; *!* +<<<<<<< HEAD // rest è un array con gli elementi a destra, partendo dal terzo +======= +// rest is an array of items, starting from the 3rd one +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 alert(rest[0]); // Consul alert(rest[1]); // of the Roman Republic alert(rest.length); // 2 */!* ``` +<<<<<<< HEAD +======= +The value of `rest` is the array of the remaining array elements. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 La variabile `rest` è un array con i valori rimanenti dell'array a destra. @@ -196,7 +250,11 @@ let [name1, name2, *!*...titles*/!*] = ["Julius", "Caesar", "Consul", "of the Ro ### Valori di default +<<<<<<< HEAD Se ci sono meno elementi nell'array delle variabili da assegnare, non ci sarà alcun errore. I valori assenti vengono considerati undefined: +======= +If the array is shorter than the list of variables on the left, there will be no errors. Absent values are considered undefined: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run *!* @@ -245,7 +303,11 @@ La sintassi è: let {var1, var2} = {var1:…, var2:…} ``` +<<<<<<< HEAD Abbiamo un oggetto alla destra dell'assegnazione, che vogliamo dividere in variabili. Nel lato sinistro abbiamo un "pattern" di proprietà corrispondenti. In questo semplice caso, abbiamo una lista di variabili raggruppate tra parentesi `{...}`. +======= +We should have an existing object on the right side, that we want to split into variables. The left side contains an object-like "pattern" for corresponding properties. In the simplest case, that's a list of variable names in `{...}`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio: @@ -265,9 +327,13 @@ alert(width); // 100 alert(height); // 200 ``` +<<<<<<< HEAD Le proprietà `options.title`, `options.width` e `options.height` vengono assegnate alle variabili corrispondenti. L'ordine non ha importanza. Questo codice funzionerebbe comunque: +======= +Properties `options.title`, `options.width` and `options.height` are assigned to the corresponding variables. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js @@ -432,9 +498,15 @@ alert( title ); // Menu ## Destrutturazione annidata +<<<<<<< HEAD Se un oggetto o un array contiene altri oggetti o array, possiamo utilizzare sequenze (pattern) di estrazione più complesse per andare più in profondità con l'estrazione. Nel codice sotto `options` possiede un ulteriore oggetto nella proprietà `size` ed un array nella proprietà `items`. Il pattern alla sinistra dell'assegnazione ha la stessa struttura: +======= +If an object or an array contains other nested objects and arrays, we can use more complex left-side patterns to extract deeper portions. + +In the code below `options` has another object in the property `size` and an array in the property `items`. The pattern on the left side of the assignment has the same structure to extract values from them: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let options = { @@ -443,7 +515,11 @@ let options = { height: 200 }, items: ["Cake", "Donut"], +<<<<<<< HEAD extra: true // qualche extra che non destruttureremo +======= + extra: true +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 }; // destructuring assignment split in multiple lines for clarity @@ -463,7 +539,11 @@ alert(item1); // Cake alert(item2); // Donut ``` +<<<<<<< HEAD L'intero oggetto `options` ad eccezione di `extra`, il quale non viene menzionato, viene assegnato alle corrispondenti variabili. +======= +All properties of `options` object except `extra` which is absent in the left part, are assigned to corresponding variables: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ![](destructuring-complex.svg) @@ -473,9 +553,15 @@ Nota che non ci sono variabili per `size` e `items`: prendiamo invece il loro co ## Parametri di funzione intelligenti +<<<<<<< HEAD Ci sono casi in cui una funzione può accettare più parametri, molti dei quali opzionali. Questo è vero specialmente per le interfacce utente. Immaginate una funzione che crea un menu. Può avere una larghezza, un'altezza, un titolo, una lista di elementi e molto altro. Vediamo un pessimo modo per scrivere questo tipo di funzioni: +======= +There are times when a function has many parameters, most of which are optional. That's especially true for user interfaces. Imagine a function that creates a menu. It may have a width, a height, a title, an item list and so on. + +Here's a bad way to write such a function: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js function showMenu(title = "Untitled", width = 200, height = 100, items = []) { @@ -483,7 +569,11 @@ function showMenu(title = "Untitled", width = 200, height = 100, items = []) { } ``` +<<<<<<< HEAD Nella vita reale, il problema è ricordarsi l'ordine degli argomenti. Solitamente gli IDE ci aiutano in questo, specialmente se il codice è ben documentato, eppure... Un ulteriore problema è quello di chiamare una funzione nel caso in cui molti parametri ci vadano bene di default. +======= +In real-life, the problem is how to remember the order of arguments. Usually, IDEs try to help us, especially if the code is well-documented, but still... Another problem is how to call a function when most parameters are ok by default. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Come qui? @@ -548,7 +638,13 @@ function({ }) ``` +<<<<<<< HEAD Da notare che la destrutturazione presuppone che `showMenu()` abbia un argomento. Se vogliamo tutti i valori di default, allora dovremmo specificare un oggetto vuoto: +======= +Then, for an object of parameters, there will be a variable `varName` for the property `incomingProperty`, with `defaultValue` by default. + +Please note that such destructuring assumes that `showMenu()` does have an argument. If we want all values by default, then we should specify an empty object: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js showMenu({}); // ok, tutti i valori sono di default @@ -575,7 +671,7 @@ Nel codice sopra, l'oggetto degli argomenti è `{}` di default, quindi ci sarà - L'assegnamento di destrutturazione ci consente di mappare un oggetto o un array passandolo a variabili. - La sintassi per gli oggetti: ```js - let {prop : varName = default, ...rest} = object + let {prop : varName = defaultValue, ...rest} = object ``` Questo significa che la proprietà `prop` dovrebbe andare nella variabile `varName` e, se non esiste alcuna proprietà, allora verrà utilizzato il valore di `default`. @@ -583,9 +679,13 @@ Nel codice sopra, l'oggetto degli argomenti è `{}` di default, quindi ci sarà - La sintassi per gli array: ```js - let [item1 = default, item2, ...rest] = array + let [item1 = defaultValue, item2, ...rest] = array ``` +<<<<<<< HEAD Il primo elemento va in `item1`; il secondo va in `item2`, tutti gli altri finiscono nell'array `rest`. +======= + The first item goes to `item1`; the second goes into `item2`, and all the rest makes the array `rest`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 - Per casi più complessi, la parte sinistra deve possedere la stessa struttura di quella destra. diff --git a/1-js/05-data-types/10-destructuring-assignment/destructuring-complex.svg b/1-js/05-data-types/10-destructuring-assignment/destructuring-complex.svg index 8f6bcc033..8a1ff1a93 100644 --- a/1-js/05-data-types/10-destructuring-assignment/destructuring-complex.svg +++ b/1-js/05-data-types/10-destructuring-assignment/destructuring-complex.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/1-js/05-data-types/11-date/1-new-date/solution.md b/1-js/05-data-types/11-date/1-new-date/solution.md index a3709e88f..16049287f 100644 --- a/1-js/05-data-types/11-date/1-new-date/solution.md +++ b/1-js/05-data-types/11-date/1-new-date/solution.md @@ -13,6 +13,6 @@ Potremmo anche creare una data da una stringa, così: ```js run //new Date(datastring) -let d2 = new Date("February 20, 2012 03:12:00"); +let d2 = new Date("2012-02-20T03:12"); alert( d2 ); ``` diff --git a/1-js/05-data-types/11-date/article.md b/1-js/05-data-types/11-date/article.md index e3df44c68..7a66dda21 100644 --- a/1-js/05-data-types/11-date/article.md +++ b/1-js/05-data-types/11-date/article.md @@ -58,7 +58,14 @@ Per creare un nuovo oggetto `Date`, chiamiamo `new Date()` con uno dei seguenti `new Date(year, month, date, hours, minutes, seconds, ms)` : Crea la data con le informazioni fornite. Solo i primi due argomenti sono obbligatori. +<<<<<<< HEAD Nota: +======= + - The `year` should have 4 digits. For compatibility, 2 digits are also accepted and considered `19xx`, e.g. `98` is the same as `1998` here, but always using 4 digits is strongly encouraged. + - The `month` count starts with `0` (Jan), up to `11` (Dec). + - The `date` parameter is actually the day of month, if absent then `1` is assumed. + - If `hours/minutes/seconds/ms` is absent, they are assumed to be equal `0`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 - Il campo `year` deve essere composto da 4 cifre: `2013` va bene, `98` non è corretto. - Il numero `month` inizia da `0` (Gennaio), fino a `11` (Dicembre). @@ -381,7 +388,11 @@ for (let i = 0; i < 10; i++) { I moderni motori JavaScript applicano molte ottimizzazioni. Potrebbero quindi "truccare" i risultati di un "test artificiale" a differenza del "normale utilizzo", specialmente se stiamo eseguendo bemchmark molto piccoli. Quindi se l'intenzione è quella di studiare le prestazioni, vale la pena studiare come funziona il motore JavaScript. Probabilmente non avrete più bisogno dei microbenchmark. +<<<<<<< HEAD Un buona libreria di articoli può essere trovata qui: . +======= +The great pack of articles about V8 can be found at . +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` ## Date.parse da una stringa @@ -412,7 +423,7 @@ Possiamo utilizzare questo metodo insieme a `new Date` per creare un oggetto dal ```js run let date = new Date( Date.parse('2012-01-26T13:51:50.417-07:00') ); -alert(date); +alert(date); ``` ## Riepilogo diff --git a/1-js/05-data-types/12-json/article.md b/1-js/05-data-types/12-json/article.md index 65dbc5eb0..f2badcddb 100644 --- a/1-js/05-data-types/12-json/article.md +++ b/1-js/05-data-types/12-json/article.md @@ -27,7 +27,11 @@ Fortunatamente, non c'è bisogno di scrivere del codice per gestire questa situa ## JSON.stringify +<<<<<<< HEAD [JSON](http://en.wikipedia.org/wiki/JSON) (JavaScript Object Notation) è un formato per rappresentare valori e oggetti. Viene descritto nello standard [RFC 4627](http://tools.ietf.org/html/rfc4627). Inizialmente fu creato per lavorare con JavaScript, ma molti altri linguaggi possiedono delle librerie per la sua gestione. Quindi JSON risulta semplice da usare per lo scambio di dati quando il client utilizza JavaScript e il server codifica in Ruby/PHP/Java/Altro. +======= +The [JSON](https://en.wikipedia.org/wiki/JSON) (JavaScript Object Notation) is a general format to represent values and objects. It is described as in [RFC 4627](https://tools.ietf.org/html/rfc4627) standard. Initially it was made for JavaScript, but many other languages have libraries to handle it as well. So it's easy to use JSON for data exchange when the client uses JavaScript and the server is written on Ruby/PHP/Java/Whatever. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 JavaScript fornisce i metodi: @@ -41,7 +45,7 @@ let student = { age: 30, isAdmin: false, courses: ['html', 'css', 'js'], - wife: null + spouse: null }; *!* @@ -58,7 +62,7 @@ alert(json); "age": 30, "isAdmin": false, "courses": ["html", "css", "js"], - "wife": null + "spouse": null } */ */!* @@ -403,7 +407,7 @@ Per decodificare una stringa in JSON, abbiamo bisogno del metodo [JSON.parse](md La sintassi: ```js -let value = JSON.parse(str, [reviver]); +let value = JSON.parse(str[, reviver]); ``` str @@ -449,7 +453,11 @@ let json = `{ Inoltre, JSON non supporta i commenti. Quindi l'aggiunta di un commento invaliderebbe il documento. +<<<<<<< HEAD Esiste un altro formato chiamato [JSON5](http://json5.org/), che accetta chiavi senza virgolette, commenti etc. Ma consiste in una libreria a se stante, non fa parte della specifica del linguaggio. +======= +There's another format named [JSON5](https://json5.org/), which allows unquoted keys, comments etc. But this is a standalone library, not in the specification of the language. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Il JSON classico è cosi restrittivo non per pigrizia degli sviluppatori, ma per consentire una facile, affidabile e rapida implementazione degli algoritmi di analisi. diff --git a/1-js/06-advanced-functions/01-recursion/01-sum-to/solution.md b/1-js/06-advanced-functions/01-recursion/01-sum-to/solution.md index 33251b26f..b4d2f4e72 100644 --- a/1-js/06-advanced-functions/01-recursion/01-sum-to/solution.md +++ b/1-js/06-advanced-functions/01-recursion/01-sum-to/solution.md @@ -37,4 +37,8 @@ P.S. Naturalmente, la formula risulta essere la soluzione più rapida. Arriva al La soluzione che utilizza il ciclo è la seconda in termini di velocità. Sia nella soluzione ricorsiva che in quella iterativa sommiamo gli stessi numeri. La ricorsione però coinvolge un gran numero di chiamate annidate e richiede una gestione dei contesti d'esecuzione. Richiede molte più risorse, questo la rende più lenta. +<<<<<<< HEAD P.P.S. Lo standard descrive un ottimizzazione: se la chiamata ricorsiva è l'ultima cosa che avviene nella funzione (come in `sumTo`), allora la funzione esterna non ha alcuna necessita di riprende l'esecuzione e non c'è quindi bisogno di memorizzare il contesto d'esecuzione In questo particolare caso `sumTo(100000)` viene risolta. Ma se il motore JavaScript non lo supporta, ci sarà un errore: "maximum stack size exceeded", che indica il raggiungimento del massimo numero di esecuzioni annidate. +======= +P.P.S. Some engines support the "tail call" optimization: if a recursive call is the very last one in the function, with no other calculations performed, then the outer function will not need to resume the execution, so the engine doesn't need to remember its execution context. That removes the burden on memory. But if the JavaScript engine does not support tail call optimization (most of them don't), there will be an error: maximum stack size exceeded, because there's usually a limitation on the total stack size. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/1-js/06-advanced-functions/01-recursion/article.md b/1-js/06-advanced-functions/01-recursion/article.md index 09241dc12..889a3aa72 100644 --- a/1-js/06-advanced-functions/01-recursion/article.md +++ b/1-js/06-advanced-functions/01-recursion/article.md @@ -61,7 +61,7 @@ Quando `pow(x, n)` viene chiamata, l'esecuzione si spezza in due rami: if n==1 = x / pow(x, n) = - \ + \ else = x * pow(x, n - 1) ``` @@ -277,7 +277,11 @@ La forma iterativa di `pow` utilizza un solo contesto d'esecuzione, modificando **Qualsiasi ricorsione può essere riscritta come un ciclo. La variante che utilizza un ciclo spesso può essere più efficace.** +<<<<<<< HEAD ...Qualche volta la traduzione potrebbe non essere banale, specialmente quando la funzione utilizza diverse sotto-chiamate ricorsive in base al verificarsi di certe condizioni, fonde i risultati delle diverse sotto-chiamate oppure quando le diramazioni diventano più complesse. In questi casi l'ottimizzazione potrebbe non essere necessaria o non valerne lo sforzo. +======= +...But sometimes the rewrite is non-trivial, especially when a function uses different recursive subcalls depending on conditions and merges their results or when the branching is more intricate. And the optimization may be unneeded and totally not worth the efforts. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 La ricorsione fornisce un codice più breve, più facile da capire e dimostrare. L'ottimizzazione non è sempre richiesta, spesso è meglio avere un buon codice, per questo viene molto utilizzata la ricorsione. @@ -524,7 +528,11 @@ Terminologia: list = { value, next -> list } ``` +<<<<<<< HEAD Gli elementi HTML o la definizione di dipartimento sono definizioni ricorsive: ogni ramo può avere altri rami. +======= + Trees like HTML elements tree or the department tree from this chapter are also naturally recursive: they have branches and every branch can have other branches. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Si possono utilizzare funzioni ricorsive per attraversare questo tipo di oggetti, come abbiamo visto nell'esempio `sumSalary`. diff --git a/1-js/06-advanced-functions/01-recursion/recursive-salaries.svg b/1-js/06-advanced-functions/01-recursion/recursive-salaries.svg index 61f32dbc0..bd874c5ba 100644 --- a/1-js/06-advanced-functions/01-recursion/recursive-salaries.svg +++ b/1-js/06-advanced-functions/01-recursion/recursive-salaries.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/1-js/06-advanced-functions/02-rest-parameters-spread/article.md b/1-js/06-advanced-functions/02-rest-parameters-spread/article.md index 140dc546f..785b1ca4d 100644 --- a/1-js/06-advanced-functions/02-rest-parameters-spread/article.md +++ b/1-js/06-advanced-functions/02-rest-parameters-spread/article.md @@ -23,7 +23,11 @@ function sum(a, b) { alert( sum(1, 2, 3, 4, 5) ); ``` +<<<<<<< HEAD In questo caso non ci saranno errori dovuti "all'eccesso" di argomenti. Ma ovviamente il risultato terrò conto solamente dei primi due. +======= +There will be no error because of "excessive" arguments. But of course in the result only the first two will be counted, so the result in the code above is `3`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 I parametri restanti possono essere menzionati nella definizione di una funzione con i tre punti `...`. Che significano letteralmente "raccogli gli altri parametri in un array". diff --git a/1-js/06-advanced-functions/03-closure/5-function-in-if/task.md b/1-js/06-advanced-functions/03-closure/5-function-in-if/task.md index 72d6f5ac1..001237d0e 100644 --- a/1-js/06-advanced-functions/03-closure/5-function-in-if/task.md +++ b/1-js/06-advanced-functions/03-closure/5-function-in-if/task.md @@ -1,5 +1,11 @@ +importance: 5 +<<<<<<< HEAD # Funzionie interna ad if +======= +--- +# Function in if +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Guardate il codice. Quale sarà il risultato della chiamata all'ultima riga? diff --git a/1-js/06-advanced-functions/03-closure/article.md b/1-js/06-advanced-functions/03-closure/article.md index 2e5294c51..d5faa625d 100644 --- a/1-js/06-advanced-functions/03-closure/article.md +++ b/1-js/06-advanced-functions/03-closure/article.md @@ -7,7 +7,11 @@ Sappiamo che una funzione può accedere alle variabili esterne, questa caratteri Cosa accade quando una variabile esterna cambia? La funzione utilizza il valore più recente o quello presente al momento della creazione della funzione? +<<<<<<< HEAD Inoltre, cosa accade quando una funzione viene spostata in un altro punto del codice e viene richiamata -- avrebbe accesso alle variabile esterne della nuova posizione? +======= +And what if a function is passed along as an argument and called from another place of code, will it get access to outer variables at the new place? +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 In questa situazione linguaggi diversi si comportano in maniera diversa, in questo capitolo ci occuperemo del comportamento di JavaScript. diff --git a/1-js/06-advanced-functions/04-var/article.md b/1-js/06-advanced-functions/04-var/article.md index 0d5faee4d..756e15fc1 100644 --- a/1-js/06-advanced-functions/04-var/article.md +++ b/1-js/06-advanced-functions/04-var/article.md @@ -56,7 +56,7 @@ alert(test); // ReferenceError: test is not defined La stessa cosa accade con i cicli, `var` non può essere locale ad un blocco/ciclo: -```js +```js run for (var i = 0; i < 10; i++) { var one = 1; // ... @@ -168,7 +168,7 @@ Lo dimostriamo con un esempio, come quello seguente: ```js run function sayHi() { - alert(phrase); + alert(phrase); *!* var phrase = "Hello"; diff --git a/1-js/06-advanced-functions/05-global-object/article.md b/1-js/06-advanced-functions/05-global-object/article.md index d8642cde9..3bcd746e7 100644 --- a/1-js/06-advanced-functions/05-global-object/article.md +++ b/1-js/06-advanced-functions/05-global-object/article.md @@ -24,7 +24,11 @@ var gVar = 5; alert(window.gVar); // 5 (diventa una proprietà dell'oggetto globale) ``` +<<<<<<< HEAD Non affidatevi a questo! Questo comportamento esiste solamente per retrocompatibilità. Gli script moderni utilizzano i moduli JavaScript, che si comportano in maniera differente. Li studieremo più avanti nel capitolo [moduli JavaScript](info:modules). +======= +Function declarations have the same effect (statements with `function` keyword in the main code flow, not function expressions). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Inoltre, la dichiarazione di variabili in stile moderno, tramite `let` e `const` non hanno questo tipo di comportamento: diff --git a/1-js/06-advanced-functions/06-function-object/article.md b/1-js/06-advanced-functions/06-function-object/article.md index 32f596558..663c27124 100644 --- a/1-js/06-advanced-functions/06-function-object/article.md +++ b/1-js/06-advanced-functions/06-function-object/article.md @@ -325,7 +325,11 @@ welcome(); // Hello, Guest (la chiamata annidata funziona correttamente) Ora funzione, perché il nome `"func"` è locale alla funzione. Non viene prelevato dall'esterno. Le specifiche garantisco che in questo modo si avrà sempre un riferimento alla funzione corrente. +<<<<<<< HEAD Il codice esterno continuerà ad utilizzare la variabile `sayHi` o `welcome`. E `func` servirà da "nome interno" della funzione. +======= +The outer code still has its variable `sayHi` or `welcome`. And `func` is an "internal function name", the way for the function to can call itself reliably. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```smart header="Tutto questo non vale per la dichiarazione di funzione" La caratteristica del "nome interno" è disponibile solamente per le espressioni di funzione, non per le dichiarazioni di funzione. Per le dichiarazioni di funzione, non c'è alcun modo per aggiungere un ulteriore "nome interno". diff --git a/1-js/06-advanced-functions/08-settimeout-setinterval/article.md b/1-js/06-advanced-functions/08-settimeout-setinterval/article.md index 9c141a88c..ecf3330bd 100644 --- a/1-js/06-advanced-functions/08-settimeout-setinterval/article.md +++ b/1-js/06-advanced-functions/08-settimeout-setinterval/article.md @@ -27,7 +27,11 @@ Di solito è una funzione. Per ragioni storiche, si può passare una stringa (st : Il ritardo in millisecondi (1000 ms = 1 secondo) prima dell'esecuzione, di base 0. `arg1`, `arg2`... +<<<<<<< HEAD : Gli argomenti della funzione (non supportati in IE9-) +======= +: Arguments for the function +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Per esempio, questo codice esegue `saluta()` dopo un secondo: @@ -102,7 +106,11 @@ Come possiamo vedere dall'output dell'`alert`, in un browser l'identificatore de Anche qui, non ci sono specifiche universali per questi metodi, quindi va bene così. +<<<<<<< HEAD Per i browser, i timer sono descritti nella [sezione Timers](https://www.w3.org/TR/html5/webappapis.html#timers) di HTML5 standard. +======= +For browsers, timers are described in the [timers section](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers) of HTML Living Standard. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## setInterval @@ -232,7 +240,11 @@ setTimeout(function() {...}, 100); Per `setInterval` la funzione resta in memoria fino a quando viene eseguito `clearInterval`. +<<<<<<< HEAD C'è un effetto collaterale. Una funzione si riferisce all'ambiente lessicale esterno, quindi, finché vive, vivono anche le variabili esterne. Queste possono richiedere molta più memoria della funzione stessa. Ne consegue che quando non ci serve più la funzione pianificata, è meglio cancellarla, anche se è molto piccola. +======= +There's a side effect. A function references the outer lexical environment, so, while it lives, outer variables live too. They may take much more memory than the function itself. So when we don't need the scheduled function anymore, it's better to cancel it, even if it's very small. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```` ## setTimeout con zero-delay (ritardo zero) @@ -255,8 +267,13 @@ La prima linea "mette in calendario" la chiamata dopo 0ms, ma la pianificazione Ci sono anche casi di utilizzo avanzato relativi ai browser del timeout zero-delay, li discuteremo nel capitolo . +<<<<<<< HEAD ````smart header="Zero-delay in effetti non è zero (in un browser)" In un browser c'è un limite a quanto spesso possono essere avviati i timer nidificati. L'[HTML5 standard](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers) dice: "dopo cinque timer nidificati, l'intervallo è costretto a essere di almeno 4 millisecondi". +======= +````smart header="Zero delay is in fact not zero (in a browser)" +In the browser, there's a limitation of how often nested timers can run. The [HTML Living Standard](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers) says: "after five nested timers, the interval is forced to be at least 4 milliseconds.". +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Vediamo cosa significa con l'esempio qui sotto. La chiamata `setTimeout` riprogramma se stessa con zero-delay. Ogni chiamata ricorda il tempo reale dall'esecuzione precedente nell'array `tempi`. Come sono realmente i ritardi? Vediamo: @@ -294,9 +311,16 @@ Per JavaScript lato server, questo limite non esiste e ci sono altri metodi per Da notare che tutti i metodi di pianificazione non *garantiscono* un ritardo preciso. +<<<<<<< HEAD Per esempio, il timer nel browser può rallentare per molte ragioni: - La CPU è sovraccarica. - La scheda del browser è sullo sfondo. - Il portatile ha la batteria scarica. +======= +For example, the in-browser timer may slow down for a lot of reasons: +- The CPU is overloaded. +- The browser tab is in the background mode. +- The laptop is on battery saving mode. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Tutto ciò può aumentare l'esecuzione minima del timer (il ritardo minimo) di 300ms o anche 1000ms a seconda del browser e le impostazioni di prestazione a livello dell'OS. diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.svg b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.svg index bd82f0245..e624ce020 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.svg +++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.svg @@ -1 +1 @@ -200ms1500ms1000ms0cf(a)f(b)f(c)500mstimecalls: after 1000ms \ No newline at end of file +200ms1500ms1000ms0cf(a)f(b)f(c)500mstimecalls: after 1000ms \ No newline at end of file diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md index 5a0c690b6..4fd703518 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md @@ -8,9 +8,15 @@ Creare un "throttling" decorator `throttle(f, ms)` -- che ritorna un wrapper. Quando viene chiamato più volte, passa la chiamata a `f` al massimo una volta ogni `ms` millisecondi. +<<<<<<< HEAD Rispetto al *debounce decorator* abbiamo un decorator completamente diverso: - `debounce` esegue la funzione una volta, dopo il periodo di "cooldown". Valido per processare il risultato finale. - `throttle` la esegue non più spesso dell'intervallo di tempo `ms`. Valido per aggiornamenti regolari ma non troppo frequenti. +======= +Compared to the debounce decorator, the behavior is completely different: +- `debounce` runs the function once after the "cooldown" period. Good for processing the final result. +- `throttle` runs it not more often than given `ms` time. Good for regular updates that shouldn't be very often. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 In altre parole, `throttle` è come una segretaria che accetta telefonate, ma le passa al capo (chiama `f`) non più di una volta ogni `ms` millisecondi. diff --git a/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md b/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md index 416e77a9a..febb27bda 100644 --- a/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md +++ b/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md @@ -1,5 +1,9 @@ +<<<<<<< HEAD L'errore si verifica perché `askPassword` riceve le funzioni `loginOk/loginFail` senza l'oggetto. +======= +The error occurs because `askPassword` gets functions `loginOk/loginFail` without the object. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Quando le chiamiamo, naturalmente assumono `this=undefined`. diff --git a/1-js/06-advanced-functions/10-bind/article.md b/1-js/06-advanced-functions/10-bind/article.md index 58e121006..9ea00aae2 100644 --- a/1-js/06-advanced-functions/10-bind/article.md +++ b/1-js/06-advanced-functions/10-bind/article.md @@ -202,7 +202,11 @@ for (let key in user) { } ``` +<<<<<<< HEAD Alcune librerie JavaScript forniscono utili funzioni per il *binding* di massa, ad esempio [_.bindAll(object, methodNames)](http://lodash.com/docs#bindAll) in lodash. +======= +JavaScript libraries also provide functions for convenient mass binding , e.g. [_.bindAll(object, methodNames)](https://lodash.com/docs#bindAll) in lodash. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```` ## Funzioni parziali diff --git a/1-js/07-object-properties/01-property-descriptors/article.md b/1-js/07-object-properties/01-property-descriptors/article.md index 1c69680fb..aad3b6407 100644 --- a/1-js/07-object-properties/01-property-descriptors/article.md +++ b/1-js/07-object-properties/01-property-descriptors/article.md @@ -122,8 +122,13 @@ user.name = "Pete"; // Error: Cannot assign to read only property 'name' Ora nessuno potrà modificare il nome dell'utente, a meno che non vada a sovrascrivere il valore degli attributi con `defineProperty`. +<<<<<<< HEAD ```smart header="Gli errori verranno mostrati solamente in strict mode" Se non siamo in "strict mode", e tentiamo di sovrascrivere una proprietà non-writable, non verrà mostrato alcun errore. Nonostante non venga mostrato l'errore, l'operazione fallirà comunque. Quindi le violazioni di attributi fuori dalla strict mode verranno silenziosamente ignorate. +======= +```smart header="Errors appear only in strict mode" +In non-strict mode, no errors occur when writing to non-writable properties and such. But the operation still won't succeed. Flag-violating actions are just silently ignored in non-strict. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` Qui vediamo lo stesso esempio, ma la proprietà viene creata dal nulla: @@ -315,7 +320,11 @@ for (let key in user) { ...Ma in questo modo non stiamo copiando gli attributi. Quindi per una clonazione più completa, l'utilizzo di `Object.defineProperties` è la scelta migliore. +<<<<<<< HEAD Un'altra differenza è che `for..in` ignora le proprietà di tipo `symbol`, mentre `Object.getOwnPropertyDescriptors` ritorna *tutti* i descrittori, inclusi quelli di tipo symbol. +======= +Another difference is that `for..in` ignores symbolic and non-enumerable properties, but `Object.getOwnPropertyDescriptors` returns *all* property descriptors including symbolic and non-enumerable ones. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Sigillare un oggetto globalmente diff --git a/1-js/07-object-properties/02-property-accessors/article.md b/1-js/07-object-properties/02-property-accessors/article.md index ce1760ef6..a551bfd10 100644 --- a/1-js/07-object-properties/02-property-accessors/article.md +++ b/1-js/07-object-properties/02-property-accessors/article.md @@ -5,7 +5,11 @@ Esistono due tipi di proprietà per gli oggetti. Il primo tipo sono le *data properties* (proprietà di tipo "dato"). Sappiamo già come utilizzarle, poiché tutte le proprietà viste fino ad ora erano *date properties*. +<<<<<<< HEAD Il secondo tipo di proprietà è qualcosa di nuovo. Sono definite *accessor properties* (proprietà accessorie). Sono essenzialmente funzioni che vengono eseguite quando viene letto o impostato un valore, ma al codice esterno appaiono come normali proprietà. +======= +The second type of property is something new. It's an *accessor property*. They are essentially functions that execute on getting and setting a value, but look like regular properties to an external code. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Getters e setters diff --git a/1-js/08-prototypes/01-prototype-inheritance/article.md b/1-js/08-prototypes/01-prototype-inheritance/article.md index 2a3f21fd4..603d5b7f3 100644 --- a/1-js/08-prototypes/01-prototype-inheritance/article.md +++ b/1-js/08-prototypes/01-prototype-inheritance/article.md @@ -131,9 +131,14 @@ Ci sono solamente due limitazioni: Inoltre, anche se dovrebbe essere già ovvio: può esserci solamente un `[[Prototype]]`. Un oggetto non può ereditare da più oggetti. +<<<<<<< HEAD ```smart header="`__proto__` è un getter/setter storico per `[[Prototype]]`" E' un errore comune tra i principianti quello di non conoscere la differenza tra questi due. +======= +```smart header="`__proto__` is a historical getter/setter for `[[Prototype]]`" +It's a common mistake of novice developers not to know the difference between these two. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Da notare che `__proto__` non è *la stessa cosa* della proprietà `[[Prototype]]`. E' solamente un getter/setter per `[[Prototype]]`. Più avanti vedremo alcune situazioni in cui questa differenza avrà importanza, ma per ora tenetelo solo a mente. diff --git a/1-js/08-prototypes/03-native-prototypes/article.md b/1-js/08-prototypes/03-native-prototypes/article.md index 3c88ea822..540e7d69c 100644 --- a/1-js/08-prototypes/03-native-prototypes/article.md +++ b/1-js/08-prototypes/03-native-prototypes/article.md @@ -2,7 +2,11 @@ La proprietà `"prototype"` viene largamente utilizzata da JavaScript stesso. Tutti i costruttori integrati ne fanno uso. +<<<<<<< HEAD Come prima cosa andremo ad analizzare questa proprietà nel dettaglio; in un secondo momento vedremo come utilizzarla per aggiungere nuove funzionalità agli oggetti integrati. +======= +First we'll look at the details, and then how to use it for adding new capabilities to built-in objects. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Object.prototype diff --git a/1-js/08-prototypes/03-native-prototypes/proto-constructor-animal-rabbit.svg b/1-js/08-prototypes/03-native-prototypes/proto-constructor-animal-rabbit.svg deleted file mode 100644 index ede4e1227..000000000 --- a/1-js/08-prototypes/03-native-prototypes/proto-constructor-animal-rabbit.svg +++ /dev/null @@ -1 +0,0 @@ -eats: truename: "White Rabbit"animalRabbitrabbit[[Prototype]]prototype \ No newline at end of file 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 27b0448ec..d0b406121 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 @@ -28,4 +28,8 @@ alert(dictionary); // "apple,__proto__" Possiamo crare una proprietà utilizzando un descriptor. Di default i flag vengono impostati a `false`. Quindi nel codice sopra, `dictionary.toString` è non-enumerable. +<<<<<<< HEAD Vedi il capitolo [property descriptors](info:property-descriptors) se hai bisogno di ripassare l'argomento. +======= +See the chapter [](info:property-descriptors) for review. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/1-js/08-prototypes/04-prototype-methods/article.md b/1-js/08-prototypes/04-prototype-methods/article.md index a89ebf6ff..074caa8cb 100644 --- a/1-js/08-prototypes/04-prototype-methods/article.md +++ b/1-js/08-prototypes/04-prototype-methods/article.md @@ -3,6 +3,7 @@ Nel primo capitolo di questa sezione, abbiamo menzionato il fatto che esistono metodi piu moderni per impostare il prototype. +<<<<<<< HEAD La proprietà `__proto__` viene considerata datata, e in un certo senso anche deprecata (negli standard JavaScript per i browser). Alcuni dei metodi più moderni sono: @@ -12,6 +13,20 @@ Alcuni dei metodi più moderni sono: - [Object.setPrototypeOf(obj, proto)](mdn:js/Object/setPrototypeOf) -- imposta il `[[Prototype]]` di `obj` a `proto`. Questi metodi dovrebbero sempre essere preferiti a `__proto__`. +======= +Setting or reading the prototype with `obj.__proto__` is considered outdated and somewhat deprecated (moved to the so-called "Annex B" of the JavaScript standard, meant for browsers only). + +The modern methods to get/set a prototype are: + +- [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`. + +The only usage of `__proto__`, that's not frowned upon, is as a property when creating a new object: `{ __proto__: ... }`. + +Although, there's a special method for this too: + +- [Object.create(proto[, descriptors])](mdn:js/Object/create) -- creates an empty object with given `proto` as `[[Prototype]]` and optional property descriptors. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio: @@ -22,7 +37,7 @@ let animal = { // creiamo un nuovo oggetto con animal come prototype *!* -let rabbit = Object.create(animal); +let rabbit = Object.create(animal); // same as {__proto__: animal} */!* alert(rabbit.eats); // true @@ -36,7 +51,13 @@ Object.setPrototypeOf(rabbit, {}); // cambia il prototype di rabbit a {} */!* ``` +<<<<<<< HEAD `Object.create` supporta un secondo argomento opzionale: il property descriptors (descrittori di proprietà). Possiamo fornire proprietà aggiuntive al nuovo oggetto, in questo modo: +======= +The `Object.create` method is a bit more powerful, as it has an optional second argument: property descriptors. + +We can provide additional properties to the new object there, like this: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run let animal = { @@ -57,19 +78,29 @@ I descrittori vanno forniti nel formato descritto nel capitolo >>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Motivazioni storiche. +<<<<<<< HEAD - La proprietà `"prototype"` di un costruttore è disponibile fin dai primi tempi in JavaScript. - Più tardi, nel 2012, è apparso nello standard `Object.create`. Il quale permette di creare oggetti fornendogli un prototype, ma non consente di impostarlo o di ottenerlo. Quindi i browser implementarono il metodo non-standard `__proto__`, come proprietà di accesso per impostare o otternere il prototype in qualsiasi momento. - Più tardi, nel 2015, `Object.setPrototypeOf` e `Object.getPrototypeOf` vennero aggiunti allo standard, con le stesse funzionalità di `__proto__`. Poiché `__proto__` era di fatto implementato ovunque, entrò in un fase di deprecazione, nella sezione Annex B dello standard, ovvero: opzionale per gli ambienti non-browser. @@ -77,6 +108,22 @@ Motivazioni storiche. Ad oggi abbiamo molti metodi a nostra disposizione. Perché `__proto__` è stato rimpiazzato dalle funzioni `getPrototypeOf/setPrototypeOf`? Questa è una domanda interessante; dobbiamo capire perché l'utilizzo di `__proto__` non è una buona pratica. Continuate a leggere per avere la risposta. +======= +The prototypal inheritance was in the language since its dawn, but the ways to manage it evolved over time. + +- The `prototype` property of a constructor function has worked since very ancient times. It's the oldest way to create objects with a given prototype. +- 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. Some browsers implemented the non-standard `__proto__` accessor that allowed the user to get/set a prototype at any time, to give more flexibility to developers. +- 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. +- Later, in the year 2022, it was officially allowed to use `__proto__` in object literals `{...}` (moved out of Annex B), but not as a getter/setter `obj.__proto__` (still in Annex B). + +Why was `__proto__` replaced by the functions `getPrototypeOf/setPrototypeOf`? + +Why was `__proto__` partially rehabilitated and its usage allowed in `{...}`, but not as a getter/setter? + +That's an interesting question, requiring us to understand why `__proto__` is bad. + +And soon we'll get the answer. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```warn header="Non cambiate il `[[Prototype]]` ad oggetti esistenti se la velocità è importante" Tecnicamente, possiamo impostare/ottenere il `[[Prototype]]` in qualsiasi momento. Ma solitamente lo impostiamo in fase di creazione dell'oggetto e successivamente non lo modifichiamo più: `rabbit` eredita da `animal`, e questo non dovrebbe cambiare. @@ -101,25 +148,58 @@ obj[key] = "some value"; alert(obj[key]); // [object Object], non "some value"! ``` +<<<<<<< HEAD In questo esempio, se l'utente digita `__proto__`, l'assegnazione è ignorata! Questo non dovrebbe sorprenderci. La proprietà `__proto__` è speciale: deve contenere un oggetto o `null`. Una stringa non può fungere da prototype. +======= +Here, if the user types in `__proto__`, the assignment in line 4 is ignored! + +That could surely be surprising for a non-developer, but pretty understandable for us. The `__proto__` property is special: it must be either an object or `null`. A string can not become a prototype. That's why assigning a string to `__proto__` is ignored. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ma il nostro *intento* non è quello di implementare questo comportamento, giusto? Vogliamo semplicemente memorizzare una coppia chiave/valore, ma utilizzando come chiave il termine `"__proto__"` questo non viene memorizzato correttamente. Quindi, questo è un bug! +<<<<<<< HEAD In questo caso le conseguenze non sono così terribili. Ma in altri casi potremmo assegnarli oggetti, andando a modificare il valore del prototype. Risultato: l'esecuzione fallirà in maniera imprevedibile. +======= +Here the consequences are not terrible. But in other cases we may be storing objects instead of strings in `obj`, and then the prototype will indeed be changed. As a result, the execution will go wrong in totally unexpected ways. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ancora peggio -- solitamente gli sviluppatori non pensano affatto a questa eventualità. Questo lo rende un bug veramente difficile da trovare e può portare a diverse vulnerabilità, specialmente se il codice viene eseguito server-side. +<<<<<<< HEAD Questi comportamenti inaspettati accadono anche se proviamo ad assegnare la chiave `toString`, la quale è una funzione di default, e lo stesso vale per gli altri metodi integrati. +======= +Unexpected things also may happen when assigning to `obj.toString`, as it's a built-in object method. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Come possiamo evitare questo problema? +<<<<<<< HEAD Come prima cosa, possiamo semplicemente utilizzare `Map` per la memorizzazione dei valori al posto di un oggetto, in questo modo non avremo problemi. Ma `Object` potrebbe esserci utile, perché i creatori del linguaggio hanno pensato a questo problema molto tempo fa. `__proto__` non è una proprietà di un oggetto, ma una proprietà di accesso per `Object.prototype`: +======= +First, we can just switch to using `Map` for storage instead of plain objects, then everything's fine: + +```js run +let map = new Map(); + +let key = prompt("What's the key?", "__proto__"); +map.set(key, "some value"); + +alert(map.get(key)); // "some value" (as intended) +``` + +...But `Object` syntax is often more appealing, as it's more concise. + +Fortunately, we *can* use objects, because language creators gave thought to that problem long ago. + +As we know, `__proto__` is not a property of an object, but an accessor property of `Object.prototype`: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ![](object-prototype-2.svg) @@ -132,6 +212,7 @@ Ora, se il nostro scopo è quello di utilizzare un oggetto come array associativ ```js run *!* let obj = Object.create(null); +// or: obj = { __proto__: null } */!* let key = prompt("What's the key?", "__proto__"); @@ -173,6 +254,7 @@ alert(Object.keys(chineseDictionary)); // hello,bye ## Riepilogo +<<<<<<< HEAD I metodi moderni per impostare e leggere il prototype sono: - [Object.create(proto, [descriptors])](mdn:js/Object/create) -- crea un oggetto vuoto utilizzando `proto` come `[[Prototype]]` (può essere anche `null`) e dei property descriptors (descrittori di proprietà). @@ -184,11 +266,25 @@ La proprietà integrata `__proto__`, utilizzata come getter/setter, non è sicur Le alternative disponibili sono: usare `Object.create(null)` per creare un "very plain" object, senza `__proto__`, o in alternativa, utilizzare `Map`. Inoltre, `Object.create` consente di creare una shallow-copy ('copia non profonda') di un oggetto, compresi i suoi property descriptors: +======= +- To create an object with the given prototype, use: -```js -let clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj)); -``` + - literal syntax: `{ __proto__: ... }`, allows to specify multiple properties + - or [Object.create(proto[, descriptors])](mdn:js/Object/create), allows to specify property descriptors. + + The `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)); + ``` + +- Modern methods to get/set the prototype are: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 + - [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). + +<<<<<<< HEAD Abbiamo anche chiarito che `__proto__` è un getter/setter per `[[Prototype]]` e risiede in `Object.prototype`, proprio come gli altri metodi. Possiamo creare un oggetto senza prototype utilizzando `Object.create(null)`. Questo tipo di oggetti vengono utilizzati come "puri dizionari", e non causano problemi nel caso in cui venga utilizzata `"__proto__"` come chiave. @@ -202,3 +298,12 @@ Altri metodi: - [obj.hasOwnProperty(key)](mdn:js/Object/hasOwnProperty): ritorna `true` se `obj` possiede una sua chiave `key` (non ereditata). Tutti i metodi che ritornano le proprietà di un oggetto (come `Object.keys` e le altre) -- ritornano le proprietà "possedute". Se vogliamo ottenere anche le proprietà ereditate dobbiamo utilizzare un ciclo `for..in`. +======= +- Getting/setting the prototype using the built-in `__proto__` getter/setter isn't recommended, it's now in the Annex B of the specification. + +- We also covered prototype-less objects, created with `Object.create(null)` or `{__proto__: null}`. + + These objects are used as dictionaries, to store any (possibly user-generated) keys. + + Normally, objects inherit built-in methods and `__proto__` getter/setter from `Object.prototype`, making corresponding keys "occupied" and potentially causing side effects. With `null` prototype, objects are truly empty. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/1-js/09-classes/02-class-inheritance/article.md b/1-js/09-classes/02-class-inheritance/article.md index 362f19038..1affb8735 100644 --- a/1-js/09-classes/02-class-inheritance/article.md +++ b/1-js/09-classes/02-class-inheritance/article.md @@ -105,7 +105,11 @@ class Rabbit extends Animal { } ``` +<<<<<<< HEAD ...Normalmente però non vogliamo rimpiazzare completamente il metodo ereditato, ma piuttosto costruire su di esso, modificarlo leggermente o estendere le sue funzionalità. Nel nostro metodo compiamo delle azioni, ma ad un certo punto richiamiamo il metodo ereditato. +======= +Usually, however, we don't want to totally replace a parent method, but rather to build on top of it to tweak or extend its functionality. We do something in our method, but call the parent method before/after it or in the process. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Le classi forniscono la parola chiave `"super"` per questo scopo. @@ -158,7 +162,12 @@ Ora `Rabbit` contiene il metodo `stop`, che richiama al suo interno il metodo `s ````smart header="Le funzioni a freccia (Arrow functions) non hanno `super`" Come accennato nel capitolo , all'interno delle funzioni a freccia (arrow functions)non si può utilizzare la parola `super` +<<<<<<< HEAD Se acceduto, esso viene preso dalla funzione esterna. Per esempio: +======= +If accessed, it's taken from the outer function. For instance: + +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js class Rabbit extends Animal { stop() { @@ -175,9 +184,13 @@ setTimeout(function() { super.stop() }, 1000); ``` ```` +<<<<<<< HEAD ## Sovrascrivere il costruttore Sovrascrivere un costruttore è leggermente più complicato. +======= +## Overriding constructor +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Finora, `Rabbit` non ha avuto il suo metodo`constructor`. @@ -278,11 +291,15 @@ alert(rabbit.earLength); // 10 */!* ``` +<<<<<<< HEAD ### Sovrascrivere i campi di una classe ```warn header="Nota avanzata" Questa nota assume che voi abbiate una certa esperienza con le classi, anche in altri linguaggi di programmazione. +======= +### Overriding class fields: a tricky note +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Fornisce una spiegazione più dettagliata del linguaggio e ne illustra il comportamento che potrebbe essere fonte di errori (anche se molto rari). @@ -367,14 +384,22 @@ Nel nostro caso, `Rabbit` è la classe derivata. Non c'è alcun `constructor()` Quindi, `new Rabbit()` invoca `super()`, che esegue il costruttore genitore, e (per le regole che segue la classe derivata) solamente dopo vengono inizializzati i suoi campi dati. Al momento dell'esecuzione del costruttore genitore, non esiste alcun capo dato in `Rabbit`, questo è il motivo per cui vengono utilizzati i campi dati di `Animal`. +<<<<<<< HEAD Abbiamo quindi una sottile differenza di trattamento tra i campi dati ed i metodi in JavaScript. +======= +This subtle difference between fields and methods is specific to JavaScript. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Fortunatamente, questo comportamento si verifica solamente se un campo dati va a sovrascrivere quelli della classe genitore. Potrebbe essere difficile da capire come comportamento, per questo lo abbiamo spiegato. Se dovesse verificarsi questo problema, si possono utilizzare i metodi invece dei campi dati. +<<<<<<< HEAD ## Super: internamente, [[HomeObject]] +======= +## Super: internals, [[HomeObject]] +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```warn header="Informazioni avanzate" Se state leggendo il tutorial per la prima volta - questa sezione può essere saltata. diff --git a/1-js/09-classes/03-static-properties-methods/3-class-extend-object/solution.md b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/solution.md index 80da8ac11..962e59801 100644 --- a/1-js/09-classes/03-static-properties-methods/3-class-extend-object/solution.md +++ b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/solution.md @@ -21,14 +21,22 @@ alert( rabbit.hasOwnProperty('name') ); // true Ma non è tutto. +<<<<<<< HEAD Anche dopo questo fix, c'è ancora un grande differenza tra `"class Rabbit extends Object"` e `class Rabbit`. +======= +Even after the fix, there's still an important difference between `"class Rabbit extends Object"` and `class Rabbit`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Come già sappiamo, la sintassi "extends" imposta due prototype: 1. Tra `"prototype"` del costruttore (per i metodi). 2. Tra i costruttori stessi (per i metodi statici). +<<<<<<< HEAD Nel nostro caso, `class Rabbit extends Object` significa: +======= +In the case of `class Rabbit extends Object` it means: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run class Rabbit extends Object {} @@ -37,7 +45,11 @@ alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true alert( Rabbit.__proto__ === Object ); // (2) true ``` +<<<<<<< HEAD In questo modo, tramite `Rabbit` abbiamo accesso ai metodi statici di `Object`, come nell'esempio: +======= +So `Rabbit` now provides access to the static methods of `Object` via `Rabbit`, like this: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run class Rabbit extends Object {} @@ -67,7 +79,11 @@ alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // Error Quindi `Rabbit`, in questo caso, non fornisce l'accesso ai metodi statici di `Object`. +<<<<<<< HEAD In ogni caso, `Function.prototype` possiede metodi "generici", come `call`, `bind` etc. Questi saranno disponibili in entrambi i casi, grazie al costruttore di `Object`, `Object.__proto__ === Function.prototype`. +======= +By the way, `Function.prototype` also 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`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Come mostrato in figura: diff --git a/1-js/09-classes/03-static-properties-methods/article.md b/1-js/09-classes/03-static-properties-methods/article.md index 00a83b419..9f8510420 100644 --- a/1-js/09-classes/03-static-properties-methods/article.md +++ b/1-js/09-classes/03-static-properties-methods/article.md @@ -1,9 +1,15 @@ # Proprietà e metodi statici +<<<<<<< HEAD Possiamo anche assegnare metodi alle classi stesse, non solamente al loro `"prototype"`. Questi metodi sono detti *statici*. All'interno della classe, questi vengono preceduti dalla keyword `static`, come possiamo vedere nell'esempio: +======= +We can also assign a method to the class as a whole. Such methods are called *static*. + +In a class declaration, they are prepended by `static` keyword, like this: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run class User { @@ -31,9 +37,17 @@ User.staticMethod(); // true Il valore di `this` nella chiamata `User.staticMethod()` è rappresentato dal costruttore dell classe `User` (la regola dell' "oggetto prima del punto"). +<<<<<<< HEAD Solitamente, i metodi statici vengono utilizzati per rappresentare funzioni che appartengono alla classe, ma non ad un oggetto in particolare. Ad esempio, potremmo avere degli oggetti di tipo `Article` e necessitare di una funzione per confrontarli. Una soluzione naturale sarebbe quella di aggiungere il metodo `Article.compare`, come nell'esempio: +======= +Usually, static methods are used to implement functions that belong to the class as a whole, but not to any particular object of it. + +For instance, we have `Article` objects and need a function to compare them. + +A natural solution would be to add `Article.compare` static method: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run class Article { @@ -63,9 +77,17 @@ articles.sort(Article.compare); alert( articles[0].title ); // CSS ``` +<<<<<<< HEAD Qui `Article.compare` sta "al di sopra" degli articoli, poiché ha lo scopo di confrontarli. Non è un metodo di un articolo, ma piuttosto dell'intera classe. Un altro esempio comune è quello del "factory method" (un particolare design pattern). Immaginiamo di avere bisogno di diverse modalità di creazione di un articolo: +======= +Here `Article.compare` method stands "above" articles, as a means to compare them. It's not a method of an article, but rather of the whole class. + +Another example would be a so-called "factory" method. + +Let's say, we need multiple ways to create an article: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 1. Creazione con i parametri forniti (`title`, `date` etc). 2. Creazione di un articolo vuoto con la data di oggi. @@ -73,7 +95,11 @@ Un altro esempio comune è quello del "factory method" (un particolare design pa Il primo metodo può essere implementato tramite il costruttore. Mentre per il secondo, possiamo creare un metodo statico appartenente alla classe. +<<<<<<< HEAD Come `Article.createTodays()` nell'esempio: +======= +Such as `Article.createTodays()` here: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run class Article { @@ -100,12 +126,32 @@ Ora, ogni volta in cui avremo bisogno di crare un "today's digest", possiamo inv I metodi statici vengono utilizzati anche nelle classi database-related (relative a database), per poter cercare/salvare/rimuovere elementi dal database, come nell'esempio: ```js +<<<<<<< HEAD // assumiamo che Article sia una classe speciale per la gestione degli articoli // metodo statico per la rimozione di un articolo: Article.remove({id: 12345}); ``` ## Proprietà statiche +======= +// assuming Article is a special class for managing articles +// static method to remove the article by id: +Article.remove({id: 12345}); +``` + +````warn header="Static methods aren't available for individual objects" +Static methods are callable on classes, not on individual objects. + +E.g. such code won't work: + +```js +// ... +article.createTodays(); /// Error: article.createTodays is not a function +``` +```` + +## Static properties +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 [recent browser=Chrome] diff --git a/1-js/09-classes/07-mixins/article.md b/1-js/09-classes/07-mixins/article.md index 67494fb7c..f8641d3c3 100644 --- a/1-js/09-classes/07-mixins/article.md +++ b/1-js/09-classes/07-mixins/article.md @@ -101,9 +101,13 @@ Da notare che l'invocazione al metodo padre `super.say()` da `sayHiMixin` (alla ![](mixin-inheritance.svg) +<<<<<<< HEAD Questo accade perché i metodi `sayHi` e `sayBye` sono stati creati in `sayHiMixin`. Quindi, anche dopo essere stati copiati, le loro proprietà `[[HomeObject]]` fanno riferimento a `sayHiMixin`, come mostrato nella figura. Poiché `super` ricerca i metodi in `[[HomeObject]].[[Prototype]]`, ciò significa che ricerca `sayHiMixin.[[Prototype]]`, non `User.[[Prototype]]`. +======= +As `super` looks for parent methods in `[[HomeObject]].[[Prototype]]`, that means it searches `sayHiMixin.[[Prototype]]`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## EventMixin diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md index 2ee1adff4..90e47f56b 100644 --- a/1-js/10-error-handling/1-try-catch/article.md +++ b/1-js/10-error-handling/1-try-catch/article.md @@ -642,7 +642,11 @@ Ad esempio: Il ruolo del gestore globale `window.onerror` non è quello di risolvere l'esecuzione dello the script -- cosa probabilmente impossibile nel'eventualità di errori di programmazione, ma d'inviare messaggi di errore agli sviluppatori. +<<<<<<< HEAD Esistono anche dei web-services che forniscono servizi di error-logging, come o . +======= +There are also web-services that provide error-logging for such cases, like or . +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Funziona all'incirca così: diff --git a/1-js/10-error-handling/2-custom-errors/article.md b/1-js/10-error-handling/2-custom-errors/article.md index 7b903b7ee..099b43829 100644 --- a/1-js/10-error-handling/2-custom-errors/article.md +++ b/1-js/10-error-handling/2-custom-errors/article.md @@ -38,7 +38,7 @@ class Error { Ora ereditiamo `ValidationError` da esso e proviamolo in azione: -```js run untrusted +```js run *!* class ValidationError extends Error { */!* diff --git a/1-js/11-async/01-callbacks/article.md b/1-js/11-async/01-callbacks/article.md index 5078db06e..0de4a9ad6 100644 --- a/1-js/11-async/01-callbacks/article.md +++ b/1-js/11-async/01-callbacks/article.md @@ -78,7 +78,13 @@ function loadScript(src, *!*callback*/!*) { } ``` +<<<<<<< HEAD Ora se volessimo chiamare nuove funzioni dallo script, dovremmo scriverlo nella callback: +======= +The `onload` event is described in the article , it basically executes a function after the script is loaded and executed. + +Now if we want to call new functions from the script, we should write that in the callback: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js loadScript('/my/script.js', function() { @@ -102,8 +108,13 @@ function loadScript(src, callback) { *!* loadScript('https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js', script => { +<<<<<<< HEAD alert(`Cool, the ${script.src} is loaded`); alert( _ ); // funzione dichiarata nello script caricato +======= + alert(`Cool, the script ${script.src} is loaded`); + alert( _ ); // _ is a function declared in the loaded script +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 }); */!* ``` @@ -197,9 +208,15 @@ Quindi la singola funzione `callback` è usata sia per riportare gli errori che ## Piramide del fato (Pyramid of Doom) +<<<<<<< HEAD Ad una prima occhiata, è un modo pratico di programmare in modo asincrono. Ed infatti lo è. Per una, forse due, chiamate annidate sembra che funzioni. Ma per molte azioni asincrone che si susseguono una dopo l'altra avremo codice come questo: +======= +At first glance, it looks like a viable approach to asynchronous coding. And indeed it is. For one or maybe two nested calls it looks fine. + +But for multiple asynchronous actions that follow one after another, we'll have code like this: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js loadScript('1.js', function(error, script) { @@ -229,10 +246,17 @@ loadScript('1.js', function(error, script) { }); ``` +<<<<<<< HEAD Nel codice sopra: 1. Carichiamo `1.js`, poi se non ci sono errori. 2. Carichiamo `2.js`, poi se non ci sono errori. 3. Carichiamo `3.js`, poi se non ci sono errori -- facciamo qualcos'altro `(*)`. +======= +In the code above: +1. We load `1.js`, then if there's no error... +2. We load `2.js`, then if there's no error... +3. We load `3.js`, then if there's no error -- do something else `(*)`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Mano a mano che le chiamate diventano più annidate, il codice diventa più profondo e via via più complicato da gestire, specialmente se abbiamo codice reale invece di `...`, che può includere più cicli, condizioni e così via. @@ -300,7 +324,11 @@ function step3(error, script) { } ``` +<<<<<<< HEAD Visto? Fa la stessa cosa, e non ci sono annidamenti profondi perché abbiamo reso ogni azione una funzione separata di primo livello. +======= +See? It does the same thing, and there's no deep nesting now because we made every action a separate top-level function. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Funziona ma il codice sembra un foglio di lavoro diviso. È difficile da leggere e probabilmente hai notato che bisogna saltare con lo sguardo tra i vari pezzi quando lo si legge. Non è conveniente, in particolare se il lettore non è familiare con il codice e non sa dove saltare con lo sguardo. @@ -308,4 +336,8 @@ Inoltre, le funzioni chiamate `step*` sono tutte usate una sola volta, sono crea Ci piacerebbe avere qualcosa di meglio. +<<<<<<< HEAD Fortunatamente, ci sono altri modi di evitare queste piramidi. Uno dei modi migliori è di usare le "promise" descritte nel capitolo successivo. +======= +Luckily, there are other ways to avoid such pyramids. One of the best ways is to use "promises", described in the next chapter. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/1-js/11-async/02-promise-basics/article.md b/1-js/11-async/02-promise-basics/article.md index b050e8721..c2a59635d 100644 --- a/1-js/11-async/02-promise-basics/article.md +++ b/1-js/11-async/02-promise-basics/article.md @@ -34,7 +34,14 @@ L'oggetto `promise` restituito ha le seguenti proprietà interne: - `state` — inizialmente "pending", poi cambia in "fulfilled" se viene invocato `resolve` o in "rejected" se viene invocato `reject`. - `result` — inizialmente `undefined`, poi cambia in `value` se viene invocato `resolve(value)` o in `error` se viene invocato `reject(error)`. +<<<<<<< HEAD Quindi l'esecutore, alla fine, mette la promise in uno di questi stati: +======= +- `state` — initially `"pending"`, then changes to either `"fulfilled"` when `resolve` is called or `"rejected"` when `reject` is called. +- `result` — initially `undefined`, then changes to `value` when `resolve(value)` is called or `error` when `reject(error)` is called. + +So the executor eventually moves `promise` to one of these states: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ![](promise-resolve-reject.svg) @@ -42,7 +49,7 @@ Più avanti vedremo come questi cambiamenti diventano noti ai "fan". Qui vediamo un esempio di costruzione di una Promise ed un semplice esecutore ritardato (tramite `setTimeout`): -```js run +```js let promise = new Promise(function(resolve, reject) { // la funzione è eseguita automaticamente quando la promise è costruita @@ -56,7 +63,11 @@ Possiamo vedere due cose eseguendo il codice sopra: 1. L'esecutore è chiamato automaticamente ed immediatamente (da `new Promise`). 2. L'esecutore riceve due argomenti: `resolve` e `reject` — queste funzioni sono predefinite dal motore JavaScript. Quindi non abbiamo bisogno di crearle. Dovremo invece scrivere l'esecutore per chiamarle quando è il momento. +<<<<<<< HEAD Dopo un secondo di "elaborazione" l'esecutore chiama `resolve("done")` per produrre il risultato. Questo cambia lo stato dell'oggetto `promise`: +======= + After one second of "processing", the executor calls `resolve("done")` to produce the result. This changes the state of the `promise` object: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ![](promise-resolve-1.svg) @@ -125,9 +136,15 @@ Questo va bene. Abbiamo immediatamente una Promise soddisfatta, non c'è niente Le proprietà `state` e `result` dell'oggetto Promise sono interne. Non possiamo accedervi direttamente dal nostro "codice consumatore". Possiamo usare i metodi `.then`/`.catch`/`.finally` per questo. Questi metodi sono descritti sotto. ```` +<<<<<<< HEAD ## Consumatori (consumers): then, catch, finally Un oggetto Promise fa da collegamento tra l'esecutore (il "codice produttore" o "cantante") e le funzioni consumatore (i "fan"), che riceveranno il risultato o un errore. Le funzioni consumatori possono essere registrate (subscribed) usando i metodi `.then`, `.catch` e `.finally`. +======= +## Consumers: then, catch + +A Promise object serves as a link between the executor (the "producing code" or "singer") and the consuming functions (the "fans"), which will receive the result or error. Consuming functions can be registered (subscribed) using the methods `.then` and `.catch`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ### then @@ -142,9 +159,15 @@ promise.then( ); ``` +<<<<<<< HEAD Il primo argomento di `.then` è una funzione che esegue quando una promise viene risolta, e ne riceve il risultato. Il secondo argomento di `.then` è una funzione che esegue quando una promise viene rifiutata e riceve l'errore. +======= +The first argument of `.then` is a function that runs when the promise is resolved and receives the result. + +The second argument of `.then` is a function that runs when the promise is rejected and receives the error. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Per esempio, ecco una reazione ad una promise soddisfatta: @@ -210,10 +233,11 @@ promise.catch(alert); // mostra "Error: Whoops!" dopo 1 secondo La chiamata `.catch(f)` è completamente analoga a `.then(null, f)`, è solo un'abbreviazione. -### finally +## Cleanup: finally Proprio come c'è la clausola `finally` in un regolare `try {...} catch {...}`, c'è `finally` nelle promise. +<<<<<<< HEAD La chiamata `.finally(f)` è simile a `.then(f, f)` nel senso che viene sempre eseguita quando la promise è ferma (settled): che sia soddisfatta o respinta. `finally` è un buon handler per fare pulizia, ad esempio fermare i nostri indicatori di caricamento, dato che non sono più necessari, indipendentemente dall'esito. @@ -227,30 +251,77 @@ new Promise((resolve, reject) => { *!* // viene eseguito quando la promise è ferma (settled), non conta se con successo o no .finally(() => ferma l'indicatore di caricamento) +======= +The call `.finally(f)` is similar to `.then(f, f)` in the sense that `f` runs always, when the promise is settled: be it resolve or reject. + +The idea of `finally` is to set up a handler for performing cleanup/finalizing after the previous operations are complete. + +E.g. stopping loading indicators, closing no longer needed connections, etc. + +Think of it as a party finisher. Irresepective of whether a party was good or bad, how many friends were in it, we still need (or at least should) do a cleanup after it. + +The code may look like this: + +```js +new Promise((resolve, reject) => { + /* do something that takes time, and then call resolve or maybe reject */ +}) +*!* + // runs when the promise is settled, doesn't matter successfully or not + .finally(() => stop loading indicator) + // so the loading indicator is always stopped before we go on +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 */!* .then(result => show result, err => mostra l'errore) ``` +<<<<<<< HEAD Tuttavia non è esattamente un alias. Ci sono diverse importanti differenze: 1. Un handler `finally` non ha argomenti. In `finally` non sappiamo se la promise ha successo oppure no. Questo va bene, dato che il nostro compito è solitamente quello di eseguire procedure di finalizzazione "generiche". 2. Finally passa risultati ed errori al prossimo handler. Per esempio, qui il risultato è passato da `finally` a `then`: +======= +Please note that `finally(f)` isn't exactly an alias of `then(f,f)` though. + +There are important differences: + +1. A `finally` handler has no arguments. In `finally` we don't know whether the promise is successful or not. That's all right, as our task is usually to perform "general" finalizing procedures. + + Please take a look at the example above: as you can see, the `finally` handler has no arguments, and the promise outcome is handled by the next handler. +2. A `finally` handler "passes through" the result or error to the next suitable handler. + + For instance, here the result is passed through `finally` to `then`: + +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run new Promise((resolve, reject) => { - setTimeout(() => resolve("result"), 2000) + setTimeout(() => resolve("value"), 2000); }) +<<<<<<< HEAD .finally(() => alert("Promise ready")) .then(result => alert(result)); // <-- .then gestisce il risultato ``` Ed ecco un errore nella promise, passata da `finally` a `catch`: +======= + .finally(() => alert("Promise ready")) // triggers first + .then(result => alert(result)); // <-- .then shows "value" + ``` + + As you can see, the `value` returned by the first promise is passed through `finally` to the next `then`. + + That's very convenient, because `finally` is not meant to process a promise result. As said, it's a place to do generic cleanup, no matter what the outcome was. + + And here's an example of an error, for us to see how it's passed through `finally` to `catch`: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run new Promise((resolve, reject) => { throw new Error("error"); }) +<<<<<<< HEAD .finally(() => alert("Promise ready")) .catch(err => alert(err)); // <-- .catch gestisce l'oggetto errore ``` @@ -263,6 +334,30 @@ Tuttavia non è esattamente un alias. Ci sono diverse importanti differenze: ````smart header="Sulle promise ferme gli handler vengono eseguiti immediatamente" Se una promise è pending, gli handler `.then/catch/finally` aspettano il risultato. Altrimenti, se una promise è già ferma, vengono eseguiti immediatamente: +======= + .finally(() => alert("Promise ready")) // triggers first + .catch(err => alert(err)); // <-- .catch shows the error + ``` + +3. A `finally` handler also shouldn't return anything. If it does, the returned value is silently ignored. + + The only exception to this rule is when a `finally` handler throws an error. Then this error goes to the next handler, instead of any previous outcome. + +To summarize: + +- A `finally` handler doesn't get the outcome of the previous handler (it has no arguments). This outcome is passed through instead, to the next suitable handler. +- If a `finally` handler returns something, it's ignored. +- When `finally` throws an error, then the execution goes to the nearest error handler. + +These features are helpful and make things work just the right way if we use `finally` how it's supposed to be used: for generic cleanup procedures. + +````smart header="We can attach handlers to settled promises" +If a promise is pending, `.then/catch/finally` handlers wait for its outcome. + +Sometimes, it might be that a promise is already settled when we add a handler to it. + +In such case, these handlers just run immediately: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run // una promise risolta immediatamente @@ -276,11 +371,19 @@ La cosa buona è: un handler `.then` è garantito per l'esecuzione sia che la pr ```` +<<<<<<< HEAD Ora, vediamo esempi più pratici di come le promise possano aiutarci a scrivere codice asincrono. ## Esempio: loadScript [#loadscript] Abbiamo la funzione `loadScript` per caricare uno script dal capitolo precedente. +======= +## Example: loadScript [#loadscript] + +Next, let's see more practical examples of how promises can help us write asynchronous code. + +We've got the `loadScript` function for loading a script from the previous chapter. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ecco la variante basata sulle callback, giusto per ricordarcene: diff --git a/1-js/11-async/02-promise-basics/promise-reject-1.svg b/1-js/11-async/02-promise-basics/promise-reject-1.svg index 1ed00b191..777e47739 100644 --- a/1-js/11-async/02-promise-basics/promise-reject-1.svg +++ b/1-js/11-async/02-promise-basics/promise-reject-1.svg @@ -1 +1 @@ -new Promise(executor)state: "pending" result: undefinedreject(error)state: "rejected" result: error \ No newline at end of file +new Promise(executor)state: "pending" result: undefinedreject(error)state: "rejected" result: error \ No newline at end of file diff --git a/1-js/11-async/02-promise-basics/promise-resolve-1.svg b/1-js/11-async/02-promise-basics/promise-resolve-1.svg index bb0b918db..f1f34eaee 100644 --- a/1-js/11-async/02-promise-basics/promise-resolve-1.svg +++ b/1-js/11-async/02-promise-basics/promise-resolve-1.svg @@ -1 +1 @@ -new Promise(executor)state: "pending" result: undefinedresolve("done")state: "fulfilled" result: "done" \ No newline at end of file +new Promise(executor)state: "pending" result: undefinedresolve("done")state: "fulfilled" result: "done" \ No newline at end of file diff --git a/1-js/11-async/03-promise-chaining/article.md b/1-js/11-async/03-promise-chaining/article.md index 6a884a3c6..75d7ddd19 100644 --- a/1-js/11-async/03-promise-chaining/article.md +++ b/1-js/11-async/03-promise-chaining/article.md @@ -72,7 +72,11 @@ promise.then(function(result) { }); ``` +<<<<<<< HEAD Quello che abbiamo fatto è giusto aggiungere diversi gestori (handler) ad una promise. I gestori (handler) si passano il risultato tra loro, al contrario lo processano indipendentemente. +======= +What we did here is just adding several handlers to one promise. They don't pass the result to each other; instead they process it independently. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ecco una figura (da paragonare con il concatenamento di sopra): @@ -120,7 +124,11 @@ new Promise(function(resolve, reject) { }); ``` +<<<<<<< HEAD Qui il primo `.then` mostra `1` e ritorna `new Promise(…)` nella linea `(*)`. Dopo un secondo la promise ritorata risolve (resolves), ed il risultato (l'argomento di `resolve`, che è `result*2`) viene passato al secondo gestore (handler) `.then` nella linea `(**)`. Infine mostra `2` e fa la stessa cosa. +======= +Here the first `.then` shows `1` and returns `new Promise(…)` in the line `(*)`. After one second it resolves, and the result (the argument of `resolve`, here it's `result * 2`) is passed on to the handler of the second `.then`. That handler is in the line `(**)`, it shows `2` and does the same thing. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Quindi l'output è ancora 1 -> 2 -> 4, ma ora con un secondo di ritardo tra le chiamate `alert`. @@ -226,7 +234,11 @@ Questa feature permette di integrare oggetti custom con le catene di promise sen ## Esempio più grande: fetch +<<<<<<< HEAD Nella programmazione frontend le promise sono spesso usate per le richieste di rete. Vediamone un esempio esteso. +======= +In frontend programming, promises are often used for network requests. So let's see an extended example of that. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Useremo il metodo [fetch](info:fetch) per caricare le informazioni sull'utente dal server remoto. Il metodo è abbastanza complesso, ha diversi parametri opzionali che studieremo in [separate chapters](info:fetch), ma l'utilizzo base è semplice: diff --git a/1-js/11-async/04-promise-error-handling/article.md b/1-js/11-async/04-promise-error-handling/article.md index c43e86f89..8bd563df0 100644 --- a/1-js/11-async/04-promise-error-handling/article.md +++ b/1-js/11-async/04-promise-error-handling/article.md @@ -299,6 +299,7 @@ Solitamente questi errori sono irrecuperabili, quindi la cosa migliore da fare In ambienti esterni al browser come Node.js ci sono altri modi simili di tracciare gli errori non gestiti. +<<<<<<< HEAD ## Riepilogo - `.catch` gestisce i respingimenti (rejections) delle promise di tutti i tipi: che sia una chiamata `reject()`, o un errore sollevato in un gestore (handler). @@ -345,3 +346,10 @@ Qui nella linea `(1)` indichiamo il caricamento oscurando il documento. Il metod Quando la promise è ferma (settled), che sia un fetch con successo o un errore, `finally` viene lanciato nella linea `(2)` ferma l'indicatore. C'è un piccolo trucco per i browser `(*)` nel ritornare una promise con timeout zero da `finally`. Questo perché alcuni browser (come Chrome) hanno bisogno "di un po' di tempo" fuori dai gestori (handlers) per diegnare cambiamenti al documento. Questo assicura che l'indicazione è visivamente ferma prima di andare avanti nella catena. +======= +- `.catch` handles errors in promises of all kinds: be it a `reject()` call, or an error thrown in a handler. +- `.then` also catches errors in the same manner, if given the second argument (which is the error handler). +- We should place `.catch` exactly in places where we want to handle errors and know how to handle them. The handler should analyze errors (custom error classes help) and rethrow unknown ones (maybe they are programming mistakes). +- It's ok not to use `.catch` at all, if there's no way to recover from an error. +- In any case we should have the `unhandledrejection` event handler (for browsers, and analogs for other environments) to track unhandled errors and inform the user (and probably our server) about them, so that our app never "just dies". +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/1-js/11-async/05-promise-api/article.md b/1-js/11-async/05-promise-api/article.md index f9e7e074f..66b84c344 100644 --- a/1-js/11-async/05-promise-api/article.md +++ b/1-js/11-async/05-promise-api/article.md @@ -13,10 +13,14 @@ Ecco a cosa serve `Promise.all`. La sintassi è: ```js -let promise = Promise.all([...promises...]); +let promise = Promise.all(iterable); ``` +<<<<<<< HEAD `Promise.all` accetta un array di promise (tecnicamente si può usare qualsiasi iterabile, ma solitamente si usa un array) e ritorna una nuova promise. +======= +`Promise.all` takes an iterable (usually, an array of promises) and returns a new promise. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 La nuova promise si risolve quando tutte le promise elencate vengono risolte, e l'array dei loro risultati diventa il risultato finale. @@ -249,7 +253,7 @@ Promise.any([ ]).catch(error => { console.log(error.constructor.name); // AggregateError console.log(error.errors[0]); // Error: Ouch! - console.log(error.errors[1]); // Error: Error + console.log(error.errors[1]); // Error: Error! }); ``` diff --git a/1-js/11-async/06-promisify/article.md b/1-js/11-async/06-promisify/article.md index b1d64e851..fbcf5db08 100644 --- a/1-js/11-async/06-promisify/article.md +++ b/1-js/11-async/06-promisify/article.md @@ -23,7 +23,17 @@ function loadScript(src, callback) { // loadScript('path/script.js', (err, script) => {...}) ``` +<<<<<<< HEAD Trasformiamolo in una promise. La nuova funzione `loadScriptPromise(src)` farà lo stesso, ma accetta solo `src` (senza callback) e ritorna una promise. +======= +The function loads a script with the given `src`, and then calls `callback(err)` in case of an error, or `callback(null, script)` in case of successful loading. That's a widespread agreement for using callbacks, we saw it before. + +Let's promisify it. + +We'll make a new function `loadScriptPromise(src)`, that does the same (loads the script), but returns a promise instead of using callbacks. + +In other words, we pass it only `src` (no `callback`) and get a promise in return, that resolves with `script` when the load is successful, and rejects with the error otherwise. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Here it is: ```js @@ -111,7 +121,11 @@ In alcuni casi, `err` può essere del tutto assente: `callback(result)`, o c'è Ci sono anche moduli con delle funzioni per trasformare in promise un po' più flessibili, ad esempio [es6-promisify](https://github.com/digitaldesignlabs/es6-promisify). In Node.js è presente una funzione `util.promisify`. ```smart +<<<<<<< HEAD La trasformazione in promise (promisification) è un ottimo approccio, specialmente quando si utilizza `async/await` (nel prossimo capitolo), ma non è un sostituto totale per le callback. +======= +Promisification is a great approach, especially when you use `async/await` (covered later in the chapter ), but not a total replacement for callbacks. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ricorda, una promise può avere un solo risultato, ma una callback può tecnicamente essere chiamata più volte. diff --git a/1-js/11-async/08-async-await/01-rewrite-async/solution.md b/1-js/11-async/08-async-await/01-rewrite-async/solution.md index ef777affb..147e4750c 100644 --- a/1-js/11-async/08-async-await/01-rewrite-async/solution.md +++ b/1-js/11-async/08-async-await/01-rewrite-async/solution.md @@ -13,7 +13,7 @@ async function loadJson(url) { // (1) throw new Error(response.status); } -loadJson('no-such-user.json') +loadJson('https://javascript.info/no-such-user.json') .catch(alert); // Error: 404 (4) ``` diff --git a/1-js/11-async/08-async-await/01-rewrite-async/task.md b/1-js/11-async/08-async-await/01-rewrite-async/task.md index a04b4ff94..0c31737da 100644 --- a/1-js/11-async/08-async-await/01-rewrite-async/task.md +++ b/1-js/11-async/08-async-await/01-rewrite-async/task.md @@ -15,6 +15,6 @@ function loadJson(url) { }); } -loadJson('no-such-user.json') +loadJson('https://javascript.info/no-such-user.json') .catch(alert); // Error: 404 ``` diff --git a/1-js/11-async/08-async-await/04-promise-all-failure/solution.md b/1-js/11-async/08-async-await/04-promise-all-failure/solution.md new file mode 100644 index 000000000..9fda8e000 --- /dev/null +++ b/1-js/11-async/08-async-await/04-promise-all-failure/solution.md @@ -0,0 +1,113 @@ + +The root of the problem is that `Promise.all` immediately rejects when one of its promises rejects, but it do nothing to cancel the other promises. + +In our case, the second query fails, so `Promise.all` rejects, and the `try...catch` block catches this error.Meanwhile, other promises are *not affected* - they independently continue their execution. In our case, the third query throws an error of its own after a bit of time. And that error is never caught, we can see it in the console. + +The problem is especially dangerous in server-side environments, such as Node.js, when an uncaught error may cause the process to crash. + +How to fix it? + +An ideal solution would be to cancel all unfinished queries when one of them fails. This way we avoid any potential errors. + +However, the bad news is that service calls (such as `database.query`) are often implemented by a 3rd-party library which doesn't support cancellation. Then there's no way to cancel a call. + +As an alternative, we can write our own wrapper function around `Promise.all` which adds a custom `then/catch` handler to each promise to track them: results are gathered and, if an error occurs, all subsequent promises are ignored. + +```js +function customPromiseAll(promises) { + return new Promise((resolve, reject) => { + const results = []; + let resultsCount = 0; + let hasError = false; // we'll set it to true upon first error + + promises.forEach((promise, index) => { + promise + .then(result => { + if (hasError) return; // ignore the promise if already errored + results[index] = result; + resultsCount++; + if (resultsCount === promises.length) { + resolve(results); // when all results are ready - successs + } + }) + .catch(error => { + if (hasError) return; // ignore the promise if already errored + hasError = true; // wops, error! + reject(error); // fail with rejection + }); + }); + }); +} +``` + +This approach has an issue of its own - it's often undesirable to `disconnect()` when queries are still in the process. + +It may be important that all queries complete, especially if some of them make important updates. + +So we should wait until all promises are settled before going further with the execution and eventually disconnecting. + +Here's another implementation. It behaves similar to `Promise.all` - also resolves with the first error, but waits until all promises are settled. + +```js +function customPromiseAllWait(promises) { + return new Promise((resolve, reject) => { + const results = new Array(promises.length); + let settledCount = 0; + let firstError = null; + + promises.forEach((promise, index) => { + Promise.resolve(promise) + .then(result => { + results[index] = result; + }) + .catch(error => { + if (firstError === null) { + firstError = error; + } + }) + .finally(() => { + settledCount++; + if (settledCount === promises.length) { + if (firstError !== null) { + reject(firstError); + } else { + resolve(results); + } + } + }); + }); + }); +} +``` + +Now `await customPromiseAllWait(...)` will stall the execution until all queries are processed. + +This is a more reliable approach, as it guarantees a predictable execution flow. + +Lastly, if we'd like to process all errors, we can use either use `Promise.allSettled` or write a wrapper around it to gathers all errors in a single [AggregateError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError) object and rejects with it. + +```js +// wait for all promises to settle +// return results if no errors +// throw AggregateError with all errors if any +function allOrAggregateError(promises) { + return Promise.allSettled(promises).then(results => { + const errors = []; + const values = []; + + results.forEach((res, i) => { + if (res.status === 'fulfilled') { + values[i] = res.value; + } else { + errors.push(res.reason); + } + }); + + if (errors.length > 0) { + throw new AggregateError(errors, 'One or more promises failed'); + } + + return values; + }); +} +``` diff --git a/1-js/11-async/08-async-await/04-promise-all-failure/task.md b/1-js/11-async/08-async-await/04-promise-all-failure/task.md new file mode 100644 index 000000000..74571c43e --- /dev/null +++ b/1-js/11-async/08-async-await/04-promise-all-failure/task.md @@ -0,0 +1,79 @@ + +# Dangerous Promise.all + +`Promise.all` is a great way to parallelize multiple operations. It's especially useful when we need to make parallel requests to multiple services. + +However, there's a hidden danger. We'll see an example in this task and explore how to avoid it. + +Let's say we have a connection to a remote service, such as a database. + +There're two functions: `connect()` and `disconnect()`. + +When connected, we can send requests using `database.query(...)` - an async function which usually returns the result but also may throw an error. + +Here's a simple implementation: + +```js +let database; + +function connect() { + database = { + async query(isOk) { + if (!isOk) throw new Error('Query failed'); + } + }; +} + +function disconnect() { + database = null; +} + +// intended usage: +// connect() +// ... +// database.query(true) to emulate a successful call +// database.query(false) to emulate a failed call +// ... +// disconnect() +``` + +Now here's the problem. + +We wrote the code to connect and send 3 queries in parallel (all of them take different time, e.g. 100, 200 and 300ms), then disconnect: + +```js +// Helper function to call async function `fn` after `ms` milliseconds +function delay(fn, ms) { + return new Promise((resolve, reject) => { + setTimeout(() => fn().then(resolve, reject), ms); + }); +} + +async function run() { + connect(); + + try { + await Promise.all([ + // these 3 parallel jobs take different time: 100, 200 and 300 ms + // we use the `delay` helper to achieve this effect +*!* + delay(() => database.query(true), 100), + delay(() => database.query(false), 200), + delay(() => database.query(false), 300) +*/!* + ]); + } catch(error) { + console.log('Error handled (or was it?)'); + } + + disconnect(); +} + +run(); +``` + +Two of these queries happen to be unsuccessful, but we're smart enough to wrap the `Promise.all` call into a `try..catch` block. + +However, this doesn't help! This script actually leads to an uncaught error in console! + +Why? How to avoid it? \ No newline at end of file diff --git a/1-js/11-async/08-async-await/article.md b/1-js/11-async/08-async-await/article.md index f88a7fd98..60dda9140 100644 --- a/1-js/11-async/08-async-await/article.md +++ b/1-js/11-async/08-async-await/article.md @@ -135,7 +135,13 @@ let user = await response.json(); console.log(user); ``` +<<<<<<< HEAD Possiamo "avvolgerlo" wrap in una funzione async anonima, come qui: +======= +If we're not using modules, or [older browsers](https://caniuse.com/mdn-javascript_operators_await_top_level) must be supported, there's a universal recipe: wrapping into an anonymous async function. + +Like this: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js (async () => { diff --git a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md index af2ad0eed..4355d0cfc 100644 --- a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md +++ b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md @@ -3,7 +3,7 @@ function* pseudoRandom(seed) { let value = seed; while(true) { - value = value * 16807 % 2147483647 + value = value * 16807 % 2147483647; yield value; } diff --git a/1-js/12-generators-iterators/1-generators/generateSequence-2.svg b/1-js/12-generators-iterators/1-generators/generateSequence-2.svg index 4c64e983e..7478543a4 100644 --- a/1-js/12-generators-iterators/1-generators/generateSequence-2.svg +++ b/1-js/12-generators-iterators/1-generators/generateSequence-2.svg @@ -1 +1 @@ -{value: 1, done: false} \ No newline at end of file +{value: 1, done: false} \ No newline at end of file diff --git a/1-js/12-generators-iterators/1-generators/generateSequence-3.svg b/1-js/12-generators-iterators/1-generators/generateSequence-3.svg index 0af8e9efd..d32b114f9 100644 --- a/1-js/12-generators-iterators/1-generators/generateSequence-3.svg +++ b/1-js/12-generators-iterators/1-generators/generateSequence-3.svg @@ -1 +1 @@ -{value: 2, done: false} \ No newline at end of file +{value: 2, done: false} \ No newline at end of file diff --git a/1-js/13-modules/01-modules-intro/article.md b/1-js/13-modules/01-modules-intro/article.md index 5981f8056..5c48e27bb 100644 --- a/1-js/13-modules/01-modules-intro/article.md +++ b/1-js/13-modules/01-modules-intro/article.md @@ -9,11 +9,19 @@ Ma gli script man mano diventarono più grandi e complessi, di conseguenza la co Per esempio: +<<<<<<< HEAD - [AMD](https://en.wikipedia.org/wiki/Asynchronous_module_definition) -- uno dei più vecchi sistemi per la gestione di moduli, inizialmente implementato dalla libreria [require.js](http://requirejs.org/). - [CommonJS](http://wiki.commonjs.org/wiki/Modules/1.1) -- il sistema per la gestione di moduli creato per node.js server. - [UMD](https://github.com/umdjs/umd) -- un'altro sistema di gestione di moduli, che è stato suggerito come metodo universale, compativile sia con AMD sia con CommonJS. Ormai tutti questi sistemi vengono lentamente abbandonati, anche se ancora possono essere trovati in vecchi script. +======= +- [AMD](https://en.wikipedia.org/wiki/Asynchronous_module_definition) -- one of the most ancient module systems, initially implemented by the library [require.js](https://requirejs.org/). +- [CommonJS](https://wiki.commonjs.org/wiki/Modules/1.1) -- the module system created for Node.js server. +- [UMD](https://github.com/umdjs/umd) -- one more module system, suggested as a universal one, compatible with AMD and CommonJS. + +Now these all slowly became a part of history, but we still can find them in old scripts. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Il sistema per la gestione dei moduli nel linguaggio è stato standardizzato nel 2015, e si è gradualmente evoluto da quel momento in poi. Ora è supportato da tutti i browser principali e all'interno di node.js, da adesso in poi sarà questo il sistema che studieremo. @@ -183,7 +191,11 @@ alert(admin.name); // Pete Come puoi vedere, quando `1.js` cambia la proprietà `name` nell'`admin` importato, allora anche `2.js` può vedere il nuovo `admin.name`. +<<<<<<< HEAD Questo è il motivo per cui il modulo viene eseguito solo una volta. Le esportazioni vengono generate e quindi condivise tra gli importatori, quindi se qualcosa cambia l'oggetto `admin`, gli altri moduli lo vedranno. +======= +That's exactly because the module is executed only once. Exports are generated, and then they are shared between importers, so if something changes the `admin` object, other importers will see that. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 **Questo comportamento in realtà è molto utile, perché ci permette di *configurare* i moduli.** @@ -274,7 +286,11 @@ In altre parole: - I moduli attendono fino al momento in cui l'HTML è pronto (anche se sono molto piccoli e possono essere elaborati più velocemente dell'HTML), e poi vengono eseguiti. - L'ordine relativo degli script viene mantenuto: gli script che appaiono prima nel documento vengono eseguiti per primi. +<<<<<<< HEAD Come conseguenza, i moduli "vedono" sempre la pagina HTML completamente caricata, inclusi gli elementi sotto di essi. +======= +As a side effect, module scripts always "see" the fully loaded HTML-page, including HTML elements below them. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio: diff --git a/1-js/13-modules/02-import-export/article.md b/1-js/13-modules/02-import-export/article.md index 4278d4739..f30275a26 100644 --- a/1-js/13-modules/02-import-export/article.md +++ b/1-js/13-modules/02-import-export/article.md @@ -46,7 +46,7 @@ Inoltre, possiamo inserire `export` separatamente. In questo caso, prima dichiariamo e successivamente esportiamo: -```js +```js // 📁 say.js function sayHi(user) { alert(`Hello, ${user}!`); @@ -93,6 +93,7 @@ A prima vista, "importa tutto" sembra una cosa comoda, veloce da scrivere, quind Ecco alcune ragioni valide. +<<<<<<< HEAD 1. Gli strumenti moderni di build ([webpack](http://webpack.github.io) ed altri) impacchettano i moduli in modo da ottimizzarli, velocizzarne il caricamento e rimuovere le cose inutili. Ipotizziamo di aggiungere una libreria di terze parti `say.js` al nostro progetto, che contiene molte funzioni: @@ -112,6 +113,16 @@ Ecco alcune ragioni valide. 2. Elencare esplicitamente ciò che vogliamo importare ci fornisce nomi più brevi: `sayHi()` piuttosto di `say.sayHi()`. 3. Elencare esplicitamente ciò che vogliamo importare ci fornisce una migliore visione della struttura del codice: cosa viene utilizzato e dove. Rende la manutenibilità e il refactoring del codice più semplice. +======= +1. Explicitly listing what to import gives shorter names: `sayHi()` instead of `say.sayHi()`. +2. Explicit list of imports gives better overview of the code structure: what is used and where. It makes code support and refactoring easier. + +```smart header="Don't be afraid to import too much" +Modern build tools, such as [webpack](https://webpack.js.org/) and others, bundle modules together and optimize them to speedup loading. They also remove unused imports. + +For instance, if you `import * as library` from a huge code library, and then use only few methods, then unused ones [will not be included](https://github.com/webpack/webpack/tree/main/examples/harmony-unused#examplejs) into the optimized bundle. +``` +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Import "as" @@ -224,7 +235,7 @@ Senza `default`, questo export genererebbe un errore: export class { // Errore! (non-default export richiedono un nome) constructor() {} } -``` +``` ### Il nome di "default" @@ -326,7 +337,7 @@ Immaginiamo di scrivere un "package" (pacchetto): una cartella contenente molti La struttura dei file potrebbe essere qualcosa del genere: ``` auth/ - index.js + index.js user.js helpers.js tests/ @@ -372,7 +383,7 @@ La sintassi `export ... from ...` è semplicemente una notazione più breve per ```js // 📁 auth/index.js -// re-export login/logout +// re-export login/logout export {login, logout} from './helpers.js'; // re-export il default export as User @@ -380,7 +391,11 @@ export {default as User} from './user.js'; ... ``` +<<<<<<< HEAD Un'importante differenza tra `export ... from` e `import/export`, è che i moduli ri-esportati non sono disponibili nel file corrente. Quindi, guardando l'esempio sopra `auth/index.js`, non possiamo utilizzare le funzioni ri-esportate `login/logout`. +======= +The notable difference of `export ... from` compared to `import/export` is that re-exported modules aren't available in the current file. So inside the above example of `auth/index.js` we can't use re-exported `login/logout` functions. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ### Re-exporting il default export @@ -399,11 +414,19 @@ Potremmo incontrare due problemi: 1. `export User from './user.js'` non funziona. Genererebbe un errore sintattico. +<<<<<<< HEAD Per ri-esportare il default export, dobbiamo scrivere `export {default as User}`, come nell'esempio sopra. +======= + To re-export the default export, we have to write `export {default as User}`, as in the example above. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 2. `export * from './user.js'` ri-esporta solamente i named exports, ma ignora quelli di default. +<<<<<<< HEAD Nel caso in cui volessimo ri-esportare sia i named che i defaul export, allora avremmo bisogno di due istruzioni: +======= + If we'd like to re-export both named and default exports, then two statements are needed: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js export * from './user.js'; // per ri-esportare i named exports export {default} from './user.js'; // per ri-esportare i default export @@ -430,7 +453,11 @@ Import: - Importare Named exports: - `import {x [as y], ...} from "module"` +<<<<<<< HEAD - Importare il default export: +======= +- Importing the default export: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 - `import x from "module"` - `import {default as x} from "module"` - Importare tutto: diff --git a/1-js/99-js-misc/01-proxy/proxy-inherit-admin.svg b/1-js/99-js-misc/01-proxy/proxy-inherit-admin.svg index bc6c4ce2f..3fba64606 100644 --- a/1-js/99-js-misc/01-proxy/proxy-inherit-admin.svg +++ b/1-js/99-js-misc/01-proxy/proxy-inherit-admin.svg @@ -1 +1 @@ -_name: "Guest" name: getter_name: "Admin"user (proxied)original useradmin[[Prototype]] \ No newline at end of file +_name: "Guest" name: getter_name: "Admin"user (proxied)original useradmin[[Prototype]] \ No newline at end of file diff --git a/1-js/99-js-misc/01-proxy/proxy.svg b/1-js/99-js-misc/01-proxy/proxy.svg index 157e350f4..6b2224cfd 100644 --- a/1-js/99-js-misc/01-proxy/proxy.svg +++ b/1-js/99-js-misc/01-proxy/proxy.svg @@ -1 +1 @@ -test: 5proxytargetget proxy.test5 \ No newline at end of file +test: 5proxytargetget proxy.test5 \ No newline at end of file diff --git a/1-js/99-js-misc/04-reference-type/article.md b/1-js/99-js-misc/04-reference-type/article.md index 934daf5f0..5f527b46d 100644 --- a/1-js/99-js-misc/04-reference-type/article.md +++ b/1-js/99-js-misc/04-reference-type/article.md @@ -59,7 +59,7 @@ Se spostiamo queste istruzioni in righe separate, allora `this` verrà sicuramen let user = { name: "John", hi() { alert(this.name); } -} +}; *!* // dividiamo l'accesso e l'invocazione in due righe @@ -87,7 +87,11 @@ Il risultato dell'accesso alla proprietà `user.hi` non è una funzione, ma un v (user, "hi", true) ``` +<<<<<<< HEAD Quando le parentesi `()` vengono invocate in un tipo Reference, queste ricevono tutte le informazioni riguardo l'oggetto ed il metodo, e possono quindi impostare correttamente il valore di `this` (`=user` in questo caso). +======= +When parentheses `()` are called on the Reference Type, they receive the full information about the object and its method, and can set the right `this` (`user` in this case). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Il tipo Reference è uno speciale tipo "intermedio" utilizzato internamente, con lo scopo di passare le informazioni dal punto `.` all'invocazione con le parentesi `()`. diff --git a/1-js/99-js-misc/06-unicode/article.md b/1-js/99-js-misc/06-unicode/article.md new file mode 100644 index 000000000..4f144f824 --- /dev/null +++ b/1-js/99-js-misc/06-unicode/article.md @@ -0,0 +1,172 @@ + +# Unicode, String internals + +```warn header="Advanced knowledge" +The section goes deeper into string internals. This knowledge will be useful for you if you plan to deal with emoji, rare mathematical or hieroglyphic characters, or other rare symbols. +``` + +As we already know, JavaScript strings are based on [Unicode](https://en.wikipedia.org/wiki/Unicode): each character is represented by a byte sequence of 1-4 bytes. + +JavaScript allows us to insert a character into a string by specifying its hexadecimal Unicode code with one of these three notations: + +- `\xXX` + + `XX` must be two hexadecimal digits with a value between `00` and `FF`, then `\xXX` is the character whose Unicode code is `XX`. + + Because the `\xXX` notation supports only two hexadecimal digits, it can be used only for the first 256 Unicode characters. + + These first 256 characters include the Latin alphabet, most basic syntax characters, and some others. For example, `"\x7A"` is the same as `"z"` (Unicode `U+007A`). + + ```js run + alert( "\x7A" ); // z + alert( "\xA9" ); // ©, the copyright symbol + ``` + +- `\uXXXX` + `XXXX` must be exactly 4 hex digits with the value between `0000` and `FFFF`, then `\uXXXX` is the character whose Unicode code is `XXXX`. + + Characters with Unicode values greater than `U+FFFF` can also be represented with this notation, but in this case, we will need to use a so called surrogate pair (we will talk about surrogate pairs later in this chapter). + + ```js run + alert( "\u00A9" ); // ©, the same as \xA9, using the 4-digit hex notation + alert( "\u044F" ); // я, the Cyrillic alphabet letter + alert( "\u2191" ); // ↑, the arrow up symbol + ``` + +- `\u{X…XXXXXX}` + + `X…XXXXXX` must be a hexadecimal value of 1 to 6 bytes between `0` and `10FFFF` (the highest code point defined by Unicode). This notation allows us to easily represent all existing Unicode characters. + + ```js run + alert( "\u{20331}" ); // 佫, a rare Chinese character (long Unicode) + alert( "\u{1F60D}" ); // 😍, a smiling face symbol (another long Unicode) + ``` + +## Surrogate pairs + +All frequently used characters have 2-byte codes (4 hex digits). Letters in most European languages, numbers, and the basic unified CJK ideographic sets (CJK -- from Chinese, Japanese, and Korean writing systems), have a 2-byte representation. + +Initially, JavaScript was based on UTF-16 encoding that only allowed 2 bytes per character. But 2 bytes only allow 65536 combinations and that's not enough for every possible symbol of Unicode. + +So rare symbols that require more than 2 bytes are encoded with a pair of 2-byte characters called "a surrogate pair". + +As a side effect, the length of such symbols is `2`: + +```js run +alert( '𝒳'.length ); // 2, MATHEMATICAL SCRIPT CAPITAL X +alert( '😂'.length ); // 2, FACE WITH TEARS OF JOY +alert( '𩷶'.length ); // 2, a rare Chinese character +``` + +That's because surrogate pairs did not exist at the time when JavaScript was created, and thus are not correctly processed by the language! + +We actually have a single symbol in each of the strings above, but the `length` property shows a length of `2`. + +Getting a symbol can also be tricky, because most language features treat surrogate pairs as two characters. + +For example, here we can see two odd characters in the output: + +```js run +alert( '𝒳'[0] ); // shows strange symbols... +alert( '𝒳'[1] ); // ...pieces of the surrogate pair +``` + +Pieces of a surrogate pair have no meaning without each other. So the alerts in the example above actually display garbage. + +Technically, surrogate pairs are also detectable by their codes: if a character has the code in the interval of `0xd800..0xdbff`, then it is the first part of the surrogate pair. The next character (second part) must have the code in interval `0xdc00..0xdfff`. These intervals are reserved exclusively for surrogate pairs by the standard. + +So the methods [String.fromCodePoint](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint) and [str.codePointAt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt) were added in JavaScript to deal with surrogate pairs. + +They are essentially the same as [String.fromCharCode](mdn:js/String/fromCharCode) and [str.charCodeAt](mdn:js/String/charCodeAt), but they treat surrogate pairs correctly. + +One can see the difference here: + +```js run +// charCodeAt is not surrogate-pair aware, so it gives codes for the 1st part of 𝒳: + +alert( '𝒳'.charCodeAt(0).toString(16) ); // d835 + +// codePointAt is surrogate-pair aware +alert( '𝒳'.codePointAt(0).toString(16) ); // 1d4b3, reads both parts of the surrogate pair +``` + +That said, if we take from position 1 (and that's rather incorrect here), then they both return only the 2nd part of the pair: + +```js run +alert( '𝒳'.charCodeAt(1).toString(16) ); // dcb3 +alert( '𝒳'.codePointAt(1).toString(16) ); // dcb3 +// meaningless 2nd half of the pair +``` + +You will find more ways to deal with surrogate pairs later in the chapter . There are probably special libraries for that too, but nothing famous enough to suggest here. + +````warn header="Takeaway: splitting strings at an arbitrary point is dangerous" +We can't just split a string at an arbitrary position, e.g. take `str.slice(0, 4)` and expect it to be a valid string, e.g.: + +```js run +alert( 'hi 😂'.slice(0, 4) ); // hi [?] +``` + +Here we can see a garbage character (first half of the smile surrogate pair) in the output. + +Just be aware of it if you intend to reliably work with surrogate pairs. May not be a big problem, but at least you should understand what happens. +```` + +## Diacritical marks and normalization + +In many languages, there are symbols that are composed of the base character with a mark above/under it. + +For instance, the letter `a` can be the base character for these characters: `àáâäãåā`. + +Most common "composite" characters have their own code in the Unicode table. But not all of them, because there are too many possible combinations. + +To support arbitrary compositions, the Unicode standard allows us to use several Unicode characters: the base character followed by one or many "mark" characters that "decorate" it. + +For instance, if we have `S` followed by the special "dot above" character (code `\u0307`), it is shown as Ṡ. + +```js run +alert( 'S\u0307' ); // Ṡ +``` + +If we need an additional mark above the letter (or below it) -- no problem, just add the necessary mark character. + +For instance, if we append a character "dot below" (code `\u0323`), then we'll have "S with dots above and below": `Ṩ`. + +For example: + +```js run +alert( 'S\u0307\u0323' ); // Ṩ +``` + +This provides great flexibility, but also an interesting problem: two characters may visually look the same, but be represented with different Unicode compositions. + +For instance: + +```js run +let s1 = 'S\u0307\u0323'; // Ṩ, S + dot above + dot below +let s2 = 'S\u0323\u0307'; // Ṩ, S + dot below + dot above + +alert( `s1: ${s1}, s2: ${s2}` ); + +alert( s1 == s2 ); // false though the characters look identical (?!) +``` + +To solve this, there exists a "Unicode normalization" algorithm that brings each string to the single "normal" form. + +It is implemented by [str.normalize()](mdn:js/String/normalize). + +```js run +alert( "S\u0307\u0323".normalize() == "S\u0323\u0307".normalize() ); // true +``` + +It's funny that in our situation `normalize()` actually brings together a sequence of 3 characters to one: `\u1e68` (S with two dots). + +```js run +alert( "S\u0307\u0323".normalize().length ); // 1 + +alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true +``` + +In reality, this is not always the case. The reason is that the symbol `Ṩ` is "common enough", so Unicode creators included it in the main table and gave it the code. + +If you want to learn more about normalization rules and variants -- they are described in the appendix of the Unicode standard: [Unicode Normalization Forms](https://www.unicode.org/reports/tr15/), but for most practical purposes the information from this section is enough. diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/article.md b/1-js/99-js-misc/07-weakref-finalizationregistry/article.md new file mode 100644 index 000000000..777bf703c --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/article.md @@ -0,0 +1,483 @@ + +# WeakRef and FinalizationRegistry + +```warn header="\"Hidden\" features of the language" +This article covers a very narrowly focused topic, that most developers extremely rarely encounter in practice (and may not even be aware of its existence). + +We recommend skipping this chapter if you have just started learning JavaScript. +``` + +Recalling the basic concept of the *reachability principle* from the chapter, +we can note that the JavaScript engine is guaranteed to keep values in memory that are accessible or in use. + +For example: + + +```js +// the user variable holds a strong reference to the object +let user = { name: "John" }; + +// let's overwrite the value of the user variable +user = null; + +// the reference is lost and the object will be deleted from memory + +``` + +Or a similar, but slightly more complicated code with two strong references: + +```js +// the user variable holds a strong reference to the object +let user = { name: "John" }; + +// copied the strong reference to the object into the admin variable +*!* +let admin = user; +*/!* + +// let's overwrite the value of the user variable +user = null; + +// the object is still reachable through the admin variable +``` +The object `{ name: "John" }` would only be deleted from memory if there were no strong references to it (if we also overwrote the value of the `admin` variable). + +In JavaScript, there is a concept called `WeakRef`, which behaves slightly differently in this case. + + +````smart header="Terms: \"Strong reference\", \"Weak reference\"" +**Strong reference** - is a reference to an object or value, that prevents them from being deleted by the garbage collector. Thereby, keeping the object or value in memory, to which it points. + +This means, that the object or value remains in memory and is not collected by the garbage collector as long, as there are active strong references to it. + +In JavaScript, ordinary references to objects are strong references. For example: + +```js +// the user variable holds a strong reference to this object +let user = { name: "John" }; +``` +**Weak reference** - is a reference to an object or value, that does *not* prevent them from being deleted by the garbage collector. +An object or value can be deleted by the garbage collector if, the only remaining references to them are weak references. +```` + +## WeakRef + + +````warn header="Note of caution" +Before we dive into it, it is worth noting that the correct use of the structures discussed in this article requires very careful thought, and they are best avoided if possible. +```` + +`WeakRef` - is an object, that contains a weak reference to another object, called `target` or `referent`. + +The peculiarity of `WeakRef` is that it does not prevent the garbage collector from deleting its referent-object. In other words, a `WeakRef` object does not keep the `referent` object alive. + +Now let's take the `user` variable as the "referent" and create a weak reference from it to the `admin` variable. +To create a weak reference, you need to use the `WeakRef` constructor, passing in the target object (the object you want a weak reference to). + +In our case — this is the `user` variable: + + +```js +// the user variable holds a strong reference to the object +let user = { name: "John" }; + +// the admin variable holds a weak reference to the object +*!* +let admin = new WeakRef(user); +*/!* + +``` + +The diagram below depicts two types of references: a strong reference using the `user` variable and a weak reference using the `admin` variable: + +![](weakref-finalizationregistry-01.svg) + +Then, at some point, we stop using the `user` variable - it gets overwritten, goes out of scope, etc., while keeping the `WeakRef` instance in the `admin` variable: + +```js +// let's overwrite the value of the user variable +user = null; +``` + +A weak reference to an object is not enough to keep it "alive". When the only remaining references to a referent-object are weak references, the garbage collector is free to destroy this object and use its memory for something else. + +However, until the object is actually destroyed, the weak reference may return it, even if there are no more strong references to this object. +That is, our object becomes a kind of "[Schrödinger's cat](https://en.wikipedia.org/wiki/Schr%C3%B6dinger%27s_cat)" – we cannot know for sure whether it's "alive" or "dead": + +![](weakref-finalizationregistry-02.svg) + +At this point, to get the object from the `WeakRef` instance, we will use its `deref()` method. + +The `deref()` method returns the referent-object that the `WeakRef` points to, if the object is still in memory. If the object has been deleted by the garbage collector, then the `deref()` method will return `undefined`: + + +```js +let ref = admin.deref(); + +if (ref) { + // the object is still accessible: we can perform any manipulations with it +} else { + // the object has been collected by the garbage collector +} +``` + +## WeakRef use cases + +`WeakRef` is typically used to create caches or [associative arrays](https://en.wikipedia.org/wiki/Associative_array) that store resource-intensive objects. +This allows one to avoid preventing these objects from being collected by the garbage collector solely based on their presence in the cache or associative array. + +One of the primary examples - is a situation when we have numerous binary image objects (for instance, represented as `ArrayBuffer` or `Blob`), and we want to associate a name or path with each image. +Existing data structures are not quite suitable for these purposes: + +- Using `Map` to create associations between names and images, or vice versa, will keep the image objects in memory since they are present in the `Map` as keys or values. +- `WeakMap` is ineligible for this goal either: because the objects represented as `WeakMap` keys use weak references, and are not protected from deletion by the garbage collector. + +But, in this situation, we need a data structure that would use weak references in its values. + +For this purpose, we can use a `Map` collection, whose values are `WeakRef` instances referring to the large objects we need. +Consequently, we will not keep these large and unnecessary objects in memory longer than they should be. + +Otherwise, this is a way to get the image object from the cache if it is still reachable. +If it has been garbage collected, we will re-generate or re-download it again. + +This way, less memory is used in some situations. + +## Example №1: using WeakRef for caching + +Below is a code snippet that demonstrates the technique of using `WeakRef`. + +In short, we use a `Map` with string keys and `WeakRef` objects as their values. +If the `WeakRef` object has not been collected by the garbage collector, we get it from the cache. +Otherwise, we re-download it again and put it in the cache for further possible reuse: + +```js +function fetchImg() { + // abstract function for downloading images... +} + +function weakRefCache(fetchImg) { // (1) + const imgCache = new Map(); // (2) + + return (imgName) => { // (3) + const cachedImg = imgCache.get(imgName); // (4) + + if (cachedImg?.deref()) { // (5) + return cachedImg?.deref(); + } + + const newImg = fetchImg(imgName); // (6) + imgCache.set(imgName, new WeakRef(newImg)); // (7) + + return newImg; + }; +} + +const getCachedImg = weakRefCache(fetchImg); +``` + +Let's delve into the details of what happened here: +1. `weakRefCache` - is a higher-order function that takes another function, `fetchImg`, as an argument. In this example, we can neglect a detailed description of the `fetchImg` function, since it can be any logic for downloading images. +2. `imgCache` - is a cache of images, that stores cached results of the `fetchImg` function, in the form of string keys (image name) and `WeakRef` objects as their values. +3. Return an anonymous function that takes the image name as an argument. This argument will be used as a key for the cached image. +4. Trying to get the cached result from the cache, using the provided key (image name). +5. If the cache contains a value for the specified key, and the `WeakRef` object has not been deleted by the garbage collector, return the cached result. +6. If there is no entry in the cache with the requested key, or `deref()` method returns `undefined` (meaning that the `WeakRef` object has been garbage collected), the `fetchImg` function downloads the image again. +7. Put the downloaded image into the cache as a `WeakRef` object. + +Now we have a `Map` collection, where the keys - are image names as strings, and values - are `WeakRef` objects containing the images themselves. + +This technique helps to avoid allocating a large amount of memory for resource-intensive objects, that nobody uses anymore. +It also saves memory and time in case of reusing cached objects. + +Here is a visual representation of what this code looks like: + +![](weakref-finalizationregistry-03.svg) + +But, this implementation has its drawbacks: over time, `Map` will be filled with strings as keys, that point to a `WeakRef`, whose referent-object has already been garbage collected: + +![](weakref-finalizationregistry-04.svg) + +One way to handle this problem - is to periodically scavenge the cache and clear out "dead" entries. +Another way - is to use finalizers, which we will explore next. + + +## Example №2: Using WeakRef to track DOM objects + +Another use case for `WeakRef` - is tracking DOM objects. + +Let's imagine a scenario where some third-party code or library interacts with elements on our page as long as they exist in the DOM. +For example, it could be an external utility for monitoring and notifying about the system's state (commonly so-called "logger" – a program that sends informational messages called "logs"). + +Interactive example: + +[codetabs height=420 src="weakref-dom"] + +When the "Start sending messages" button is clicked, in the so-called "logs display window" (an element with the `.window__body` class), messages (logs) start to appear. + +But, as soon as this element is deleted from the DOM, the logger should stop sending messages. +To reproduce the removal of this element, just click the "Close" button in the top right corner. + +In order not to complicate our work, and not to notify third-party code every time our DOM-element is available, and when it is not, it will be enough to create a weak reference to it using `WeakRef`. + +Once the element is removed from the DOM, the logger will notice it and stop sending messages. + +Now let's take a closer look at the source code (*tab `index.js`*): + +1. Get the DOM-element of the "Start sending messages" button. +2. Get the DOM-element of the "Close" button. +3. Get the DOM-element of the logs display window using the `new WeakRef()` constructor. This way, the `windowElementRef` variable holds a weak reference to the DOM-element. +4. Add an event listener on the "Start sending messages" button, responsible for starting the logger when clicked. +5. Add an event listener on the "Close" button, responsible for closing the logs display window when clicked. +6. Use `setInterval` to start displaying a new message every second. +7. If the DOM-element of the logs display window is still accessible and kept in memory, create and send a new message. +8. If the `deref()` method returns `undefined`, it means that the DOM-element has been deleted from memory. In this case, the logger stops displaying messages and clears the timer. +9. `alert`, which will be called, after the DOM-element of the logs display window is deleted from memory (i.e. after clicking the "Close" button). **Note, that deletion from memory may not happen immediately, as it depends only on the internal mechanisms of the garbage collector.** + + We cannot control this process directly from the code. However, despite this, we still have the option to force garbage collection from the browser. + + In Google Chrome, for example, to do this, you need to open the developer tools (`key:Ctrl` + `key:Shift` + `key:J` on Windows/Linux or `key:Option` + `key:⌘` + `key:J` on macOS), go to the "Performance" tab, and click on the bin icon button – "Collect garbage": + + ![](google-chrome-developer-tools.png) + +
+ This functionality is supported in most modern browsers. After the actions are taken, the alert will trigger immediately. + +## FinalizationRegistry + +Now it is time to talk about finalizers. Before we move on, let's clarify the terminology: + +**Cleanup callback (finalizer)** - is a function that is executed, when an object, registered in the `FinalizationRegistry`, is deleted from memory by the garbage collector. + +Its purpose - is to provide the ability to perform additional operations, related to the object, after it has been finally deleted from memory. + +**Registry** (or `FinalizationRegistry`) - is a special object in JavaScript that manages the registration and unregistration of objects and their cleanup callbacks. + +This mechanism allows registering an object to track and associate a cleanup callback with it. +Essentially it is a structure that stores information about registered objects and their cleanup callbacks, and then automatically invokes those callbacks when the objects are deleted from memory. + +To create an instance of the `FinalizationRegistry`, it needs to call its constructor, which takes a single argument - the cleanup callback (finalizer). + +Syntax: + +```js +function cleanupCallback(heldValue) { + // cleanup callback code +} + +const registry = new FinalizationRegistry(cleanupCallback); +``` + +Here: + +- `cleanupCallback` - a cleanup callback that will be automatically called when a registered object is deleted from memory. +- `heldValue` - the value that is passed as an argument to the cleanup callback. If `heldValue` is an object, the registry keeps a strong reference to it. +- `registry` - an instance of `FinalizationRegistry`. + +`FinalizationRegistry` methods: + +- `register(target, heldValue [, unregisterToken])` - used to register objects in the registry. + + `target` - the object being registered for tracking. If the `target` is garbage collected, the cleanup callback will be called with `heldValue` as its argument. + + Optional `unregisterToken` – an unregistration token. It can be passed to unregister an object before the garbage collector deletes it. Typically, the `target` object is used as `unregisterToken`, which is the standard practice. +- `unregister(unregisterToken)` - the `unregister` method is used to unregister an object from the registry. It takes one argument - `unregisterToken` (the unregister token that was obtained when registering the object). + +Now let's move on to a simple example. Let's use the already-known `user` object and create an instance of `FinalizationRegistry`: + +```js +let user = { name: "John" }; + +const registry = new FinalizationRegistry((heldValue) => { + console.log(`${heldValue} has been collected by the garbage collector.`); +}); +``` + +Then, we will register the object, that requires a cleanup callback by calling the `register` method: + +```js +registry.register(user, user.name); +``` + +The registry does not keep a strong reference to the object being registered, as this would defeat its purpose. If the registry kept a strong reference, then the object would never be garbage collected. + +If the object is deleted by the garbage collector, our cleanup callback may be called at some point in the future, with the `heldValue` passed to it: + +```js +// When the user object is deleted by the garbage collector, the following message will be printed in the console: +"John has been collected by the garbage collector." +``` + +There are also situations where, even in implementations that use a cleanup callback, there is a chance that it will not be called. + +For example: +- When the program fully terminates its operation (for example, when closing a tab in a browser). +- When the `FinalizationRegistry` instance itself is no longer reachable to JavaScript code. + If the object that creates the `FinalizationRegistry` instance goes out of scope or is deleted, the cleanup callbacks registered in that registry might also not be invoked. + +## Caching with FinalizationRegistry + +Returning to our *weak* cache example, we can notice the following: +- Even though the values wrapped in the `WeakRef` have been collected by the garbage collector, there is still an issue of "memory leakage" in the form of the remaining keys, whose values have been collected by the garbage collector. + +Here is an improved caching example using `FinalizationRegistry`: + +```js +function fetchImg() { + // abstract function for downloading images... +} + +function weakRefCache(fetchImg) { + const imgCache = new Map(); + + *!* + const registry = new FinalizationRegistry((imgName) => { // (1) + const cachedImg = imgCache.get(imgName); + if (cachedImg && !cachedImg.deref()) imgCache.delete(imgName); + }); + */!* + + return (imgName) => { + const cachedImg = imgCache.get(imgName); + + if (cachedImg?.deref()) { + return cachedImg?.deref(); + } + + const newImg = fetchImg(imgName); + imgCache.set(imgName, new WeakRef(newImg)); + *!* + registry.register(newImg, imgName); // (2) + */!* + + return newImg; + }; +} + +const getCachedImg = weakRefCache(fetchImg); +``` + +1. To manage the cleanup of "dead" cache entries, when the associated `WeakRef` objects are collected by the garbage collector, we create a `FinalizationRegistry` cleanup registry. + + The important point here is, that in the cleanup callback, it should be checked, if the entry was deleted by the garbage collector and not re-added, in order not to delete a "live" entry. +2. Once the new value (image) is downloaded and put into the cache, we register it in the finalizer registry to track the `WeakRef` object. + +This implementation contains only actual or "live" key/value pairs. +In this case, each `WeakRef` object is registered in the `FinalizationRegistry`. +And after the objects are cleaned up by the garbage collector, the cleanup callback will delete all `undefined` values. + +Here is a visual representation of the updated code: + +![](weakref-finalizationregistry-05.svg) + +A key aspect of the updated implementation is that finalizers allow parallel processes to be created between the "main" program and cleanup callbacks. +In the context of JavaScript, the "main" program - is our JavaScript-code, that runs and executes in our application or web page. + +Hence, from the moment an object is marked for deletion by the garbage collector, and to the actual execution of the cleanup callback, there may be a certain time gap. +It is important to understand that during this time gap, the main program can make any changes to the object or even bring it back to memory. + +That's why, in the cleanup callback, we must check to see if an entry has been added back to the cache by the main program to avoid deleting "live" entries. +Similarly, when searching for a key in the cache, there is a chance that the value has been deleted by the garbage collector, but the cleanup callback has not been executed yet. + +Such situations require special attention if you are working with `FinalizationRegistry`. + +## Using WeakRef and FinalizationRegistry in practice + +Moving from theory to practice, imagine a real-life scenario, where a user synchronizes their photos on a mobile device with some cloud service +(such as [iCloud](https://en.wikipedia.org/wiki/ICloud) or [Google Photos](https://en.wikipedia.org/wiki/Google_Photos)), +and wants to view them from other devices. In addition to the basic functionality of viewing photos, such services offer a lot of additional features, for example: + +- Photo editing and video effects. +- Creating "memories" and albums. +- Video montage from a series of photos. +- ...and much more. + +Here, as an example, we will use a fairly primitive implementation of such a service. +The main point - is to show a possible scenario of using `WeakRef` and `FinalizationRegistry` together in real life. + +Here is what it looks like: + +![](weakref-finalizationregistry-demo-01.png) + +
+On the left side, there is a cloud library of photos (they are displayed as thumbnails). +We can select the images we need and create a collage, by clicking the "Create collage" button on the right side of the page. +Then, the resulting collage can be downloaded as an image. +

+ +To increase page loading speed, it would be reasonable to download and display photo thumbnails in *compressed* quality. +But, to create a collage from selected photos, download and use them in *full-size* quality. + +Below, we can see, that the intrinsic size of the thumbnails is 240x240 pixels. +The size was chosen on purpose to increase loading speed. +Moreover, we do not need full-size photos in preview mode. + +![](weakref-finalizationregistry-demo-02.png) + +
+Let's assume, that we need to create a collage of 4 photos: we select them, and then click the "Create collage" button. +At this stage, the already known to us weakRefCache function checks whether the required image is in the cache. +If not, it downloads it from the cloud and puts it in the cache for further use. +This happens for each selected image: +

+ +![](weakref-finalizationregistry-demo-03.gif) + +
+ +Paying attention to the output in the console, you can see, which of the photos were downloaded from the cloud - this is indicated by FETCHED_IMAGE. +Since this is the first attempt to create a collage, this means, that at this stage the "weak cache" was still empty, and all the photos were downloaded from the cloud and put in it. + +But, along with the process of downloading images, there is also a process of memory cleanup by the garbage collector. +This means, that the object stored in the cache, which we refer to, using a weak reference, is deleted by the garbage collector. +And our finalizer executes successfully, thereby deleting the key, by which the image was stored in the cache. +CLEANED_IMAGE notifies us about it: + +![](weakref-finalizationregistry-demo-04.jpg) + +
+Next, we realize that we do not like the resulting collage, and decide to change one of the images and create a new one. +To do this, just deselect the unnecessary image, select another one, and click the "Create collage" button again: +

+ +![](weakref-finalizationregistry-demo-05.gif) + +
+But this time not all images were downloaded from the network, and one of them was taken from the weak cache: the CACHED_IMAGE message tells us about it. +This means that at the time of collage creation, the garbage collector had not yet deleted our image, and we boldly took it from the cache, +thereby reducing the number of network requests and speeding up the overall time of the collage creation process: +

+ +![](weakref-finalizationregistry-demo-06.jpg) + +
+Let's "play around" a little more, by replacing one of the images again and creating a new collage: +

+ +![](weakref-finalizationregistry-demo-07.gif) + +
+This time the result is even more impressive. Of the 4 images selected, 3 of them were taken from the weak cache, and only one had to be downloaded from the network. +The reduction in network load was about 75%. Impressive, isn't it? +

+ +![](weakref-finalizationregistry-demo-08.jpg) + +
+ +Of course, it is important to remember, that such behavior is not guaranteed, and depends on the specific implementation and operation of the garbage collector. + +Based on this, a completely logical question immediately arises: why do not we use an ordinary cache, where we can manage its entities ourselves, instead of relying on the garbage collector? +That's right, in the vast majority of cases there is no need to use `WeakRef` and `FinalizationRegistry`. + +Here, we simply demonstrated an alternative implementation of similar functionality, using a non-trivial approach with interesting language features. +Still, we cannot rely on this example, if we need a constant and predictable result. + +You can [open this example in the sandbox](sandbox:weakref-finalizationregistry). + +## Summary + +`WeakRef` - designed to create weak references to objects, allowing them to be deleted from memory by the garbage collector if there are no longer strong references to them. +This is beneficial for addressing excessive memory usage and optimizing the utilization of system resources in applications. + +`FinalizationRegistry` - is a tool for registering callbacks, that are executed when objects that are no longer strongly referenced, are destroyed. +This allows releasing resources associated with the object or performing other necessary operations before deleting the object from memory. \ No newline at end of file diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/google-chrome-developer-tools.png b/1-js/99-js-misc/07-weakref-finalizationregistry/google-chrome-developer-tools.png new file mode 100644 index 000000000..021637342 Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/google-chrome-developer-tools.png differ diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-dom.view/index.css b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-dom.view/index.css new file mode 100644 index 000000000..f6df812d0 --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-dom.view/index.css @@ -0,0 +1,49 @@ +.app { + display: flex; + flex-direction: column; + gap: 16px; +} + +.start-messages { + width: fit-content; +} + +.window { + width: 100%; + border: 2px solid #464154; + overflow: hidden; +} + +.window__header { + position: sticky; + padding: 8px; + display: flex; + justify-content: space-between; + align-items: center; + background-color: #736e7e; +} + +.window__title { + margin: 0; + font-size: 24px; + font-weight: 700; + color: white; + letter-spacing: 1px; +} + +.window__button { + padding: 4px; + background: #4f495c; + outline: none; + border: 2px solid #464154; + color: white; + font-size: 16px; + cursor: pointer; +} + +.window__body { + height: 250px; + padding: 16px; + overflow: scroll; + background-color: #736e7e33; +} \ No newline at end of file diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-dom.view/index.html b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-dom.view/index.html new file mode 100644 index 000000000..7f93af4c7 --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-dom.view/index.html @@ -0,0 +1,28 @@ + + + + + + + WeakRef DOM Logger + + + + +
+ +
+
+

Messages:

+ +
+
+ No messages. +
+
+
+ + + + + diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-dom.view/index.js b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-dom.view/index.js new file mode 100644 index 000000000..ea55b4478 --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-dom.view/index.js @@ -0,0 +1,24 @@ +const startMessagesBtn = document.querySelector('.start-messages'); // (1) +const closeWindowBtn = document.querySelector('.window__button'); // (2) +const windowElementRef = new WeakRef(document.querySelector(".window__body")); // (3) + +startMessagesBtn.addEventListener('click', () => { // (4) + startMessages(windowElementRef); + startMessagesBtn.disabled = true; +}); + +closeWindowBtn.addEventListener('click', () => document.querySelector(".window__body").remove()); // (5) + + +const startMessages = (element) => { + const timerId = setInterval(() => { // (6) + if (element.deref()) { // (7) + const payload = document.createElement("p"); + payload.textContent = `Message: System status OK: ${new Date().toLocaleTimeString()}`; + element.deref().append(payload); + } else { // (8) + alert("The element has been deleted."); // (9) + clearInterval(timerId); + } + }, 1000); +}; \ No newline at end of file diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-01.svg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-01.svg new file mode 100644 index 000000000..2a507dbcd --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-01.svg @@ -0,0 +1,32 @@ + + + + + + + + user + + name: "John" + Object + + <global> + + + + + + + + + + + + + + + + admin + + + \ No newline at end of file diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-02.svg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-02.svg new file mode 100644 index 000000000..6cc199a12 --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-02.svg @@ -0,0 +1,33 @@ + + + + + + + + + + <global> + + + name: "John" + Object + + + + + + + + + + + + admin + + + + + + + \ No newline at end of file diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-03.svg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-03.svg new file mode 100644 index 000000000..949a14f9f --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-03.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + key + value + image-01.jpg + image-02.jpg + image-03.jpg + + + + + + + + + + + + + + WeakRef object + + + + + + + + + + + + + + + + WeakRef object + + + + + + + + + + + + + + + + + + + WeakRef object + + + + + + + \ No newline at end of file diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-04.svg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-04.svg new file mode 100644 index 000000000..1177d6580 --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-04.svg @@ -0,0 +1,77 @@ + + + + + + + name: "John" + Object + + admin + + + + + + + + + key + value + image-01.jpg + image-02.jpg + image-03.jpg + + + + + + + + + + + + + + WeakRef object + + + + + + + + + + + + + + + + WeakRef object + + + + + undefined + undefined + + + + + + + + + + + + + + + WeakRef object + + + \ No newline at end of file diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-05.svg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-05.svg new file mode 100644 index 000000000..e738f8e7e --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-05.svg @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + image-02.jpg + image-03.jpg + + key + value + image-01.jpg + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WeakRef object + + + + + + + + + + + + + + + + WeakRef object + + + + + undefined + undefined + Deleted by FinalizationRegistry cleanup callback + + + + + + + + + + + + + + + WeakRef object + + + + \ No newline at end of file diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-01.png b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-01.png new file mode 100644 index 000000000..fc33a023a Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-01.png differ diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-02.png b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-02.png new file mode 100644 index 000000000..7d8bb01e8 Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-02.png differ diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-03.gif b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-03.gif new file mode 100644 index 000000000..b81966dda Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-03.gif differ diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-04.jpg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-04.jpg new file mode 100644 index 000000000..ba60f1e86 Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-04.jpg differ diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-05.gif b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-05.gif new file mode 100644 index 000000000..d34bda4d7 Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-05.gif differ diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-06.jpg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-06.jpg new file mode 100644 index 000000000..b2655540f Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-06.jpg differ diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-07.gif b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-07.gif new file mode 100644 index 000000000..51f874518 Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-07.gif differ diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-08.jpg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-08.jpg new file mode 100644 index 000000000..5f98aec14 Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-08.jpg differ diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.css b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.css new file mode 100644 index 000000000..e6c9e3960 --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.css @@ -0,0 +1,285 @@ +:root { + --mineralGreen: 60, 98, 85; + --viridianGreen: 97, 135, 110; + --swampGreen: 166, 187, 141; + --fallGreen: 234, 231, 177; + --brinkPink: #FA7070; + --silverChalice: 178, 178, 178; + --white: 255, 255, 255; + --black: 0, 0, 0; + + --topBarHeight: 64px; + --itemPadding: 32px; + --containerGap: 8px; +} + +@keyframes zoom-in { + 0% { + transform: scale(1, 1); + } + + 100% { + transform: scale(1.30, 1.30); + } +} + +body, html { + margin: 0; + padding: 0; +} + +.app { + min-height: 100vh; + background-color: rgba(var(--viridianGreen), 0.5); +} + +.header { + height: var(--topBarHeight); + padding: 0 24px; + display: flex; + justify-content: space-between; + align-items: center; + background-color: rgba(var(--mineralGreen), 1); +} + +.header-text { + color: white; +} + +.container { + display: flex; + gap: 24px; + padding: var(--itemPadding); +} + +.item { + width: 50%; +} + +.item--scrollable { + overflow-y: scroll; + height: calc(100vh - var(--topBarHeight) - (var(--itemPadding) * 2)); +} + +.thumbnails-container { + display: flex; + flex-wrap: wrap; + gap: 8px; + justify-content: center; + align-items: center; +} + +.thumbnail-item { + width: calc(25% - var(--containerGap)); + cursor: pointer; + position: relative; +} + +.thumbnail-item:hover { + z-index: 1; + animation: zoom-in 0.1s forwards; +} + +.thumbnail-item--selected { + outline: 3px solid rgba(var(--fallGreen), 1); + outline-offset: -3px; +} + +.badge { + width: 16px; + height: 16px; + display: flex; + justify-content: center; + align-items: center; + padding: 4px; + position: absolute; + right: 8px; + bottom: 8px; + border-radius: 50%; + border: 2px solid rgba(var(--fallGreen), 1); + background-color: rgba(var(--swampGreen), 1); +} + +.check { + display: inline-block; + transform: rotate(45deg); + border-bottom: 2px solid white; + border-right: 2px solid white; + width: 6px; + height: 12px; +} + +.img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.actions { + display: flex; + flex-wrap: wrap; + justify-content: center; + align-content: center; + padding: 0 0 16px 0; + gap: 8px; +} + +.select { + padding: 16px; + cursor: pointer; + font-weight: 700; + color: rgba(var(--black), 1); + border: 2px solid rgba(var(--swampGreen), 0.5); + background-color: rgba(var(--swampGreen), 1); +} + +.select:disabled { + cursor: not-allowed; + background-color: rgba(var(--silverChalice), 1); + color: rgba(var(--black), 0.5); + border: 2px solid rgba(var(--black), 0.25); +} + +.btn { + outline: none; + padding: 16px; + cursor: pointer; + font-weight: 700; + color: rgba(var(--black), 1); + border: 2px solid rgba(var(--black), 0.5); +} + +.btn--primary { + background-color: rgba(var(--mineralGreen), 1); +} + +.btn--primary:hover:not([disabled]) { + background-color: rgba(var(--mineralGreen), 0.85); +} + +.btn--secondary { + background-color: rgba(var(--viridianGreen), 0.5); +} + +.btn--secondary:hover:not([disabled]) { + background-color: rgba(var(--swampGreen), 0.25); +} + +.btn--success { + background-color: rgba(var(--fallGreen), 1); +} + +.btn--success:hover:not([disabled]) { + background-color: rgba(var(--fallGreen), 0.85); +} + +.btn:disabled { + cursor: not-allowed; + background-color: rgba(var(--silverChalice), 1); + color: rgba(var(--black), 0.5); + border: 2px solid rgba(var(--black), 0.25); +} + +.previewContainer { + margin-bottom: 16px; + display: flex; + width: 100%; + height: 40vh; + overflow: scroll; + border: 3px solid rgba(var(--black), 1); +} + +.previewContainer--disabled { + background-color: rgba(var(--black), 0.1); + cursor: not-allowed; +} + +.canvas { + margin: auto; + display: none; +} + +.canvas--ready { + display: block; +} + +.spinnerContainer { + display: flex; + gap: 8px; + flex-direction: column; + align-content: center; + align-items: center; + margin: auto; +} + +.spinnerContainer--hidden { + display: none; +} + +.spinnerText { + margin: 0; + color: rgba(var(--mineralGreen), 1); +} + +.spinner { + display: inline-block; + width: 50px; + height: 50px; + margin: auto; + border: 3px solid rgba(var(--mineralGreen), 0.3); + border-radius: 50%; + border-top-color: rgba(var(--mineralGreen), 0.9); + animation: spin 1s ease-in-out infinite; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +.loggerContainer { + display: flex; + flex-direction: column; + gap: 8px; + padding: 0 8px 8px 8px; + width: 100%; + min-height: 30vh; + max-height: 30vh; + overflow: scroll; + border-left: 3px solid rgba(var(--black), 0.25); +} + +.logger-title { + display: flex; + align-items: center; + padding: 8px; + position: sticky; + height: 40px; + min-height: 40px; + top: 0; + left: 0; + background-color: rgba(var(--viridianGreen), 1); + font-size: 24px; + font-weight: 700; + margin: 0; +} + +.logger-item { + font-size: 14px; + padding: 8px; + border: 2px solid #5a5a5a; + color: white; +} + +.logger--primary { + background-color: #13315a; +} + +.logger--success { + background-color: #385a4e; +} + +.logger--error { + background-color: #5a1a24; +} \ No newline at end of file diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.html b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.html new file mode 100644 index 000000000..7ce52f927 --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.html @@ -0,0 +1,49 @@ + + + + + + + Photo Library Collage + + + + +
+
+

+ Photo Library Collage +

+
+
+
+ +
+
+
+
+
+ + + + +
+
+
+
+

+
+ +
+
+

Logger:

+
+
+
+
+
+ + + + + diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.js b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.js new file mode 100644 index 000000000..983b34d9a --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.js @@ -0,0 +1,228 @@ +import { + createImageFile, + loadImage, + weakRefCache, + LAYOUTS, + images, + THUMBNAIL_PARAMS, + stateObj, +} from "./utils.js"; + +export const state = new Proxy(stateObj, { + set(target, property, value) { + const previousValue = target[property]; + + target[property] = value; + + if (previousValue !== value) { + handleStateChange(target); + } + + return true; + }, +}); + +// Elements. +const thumbnailsContainerEl = document.querySelector(".thumbnails-container"); +const selectEl = document.querySelector(".select"); +const previewContainerEl = document.querySelector(".previewContainer"); +const canvasEl = document.querySelector(".canvas"); +const createCollageBtn = document.querySelector(".btn-create-collage"); +const startOverBtn = document.querySelector(".btn-start-over"); +const downloadBtn = document.querySelector(".btn-download"); +const spinnerContainerEl = document.querySelector(".spinnerContainer"); +const spinnerTextEl = document.querySelector(".spinnerText"); +const loggerContainerEl = document.querySelector(".loggerContainer"); + +// Renders. +// Render thumbnails previews. +images.forEach((img) => { + const thumbnail = document.createElement("div"); + thumbnail.classList.add("thumbnail-item"); + + thumbnail.innerHTML = ` + + `; + + thumbnail.addEventListener("click", (e) => handleSelection(e, img)); + + thumbnailsContainerEl.appendChild(thumbnail); +}); +// Render layouts select. +LAYOUTS.forEach((layout) => { + const option = document.createElement("option"); + option.value = JSON.stringify(layout); + option.innerHTML = layout.name; + selectEl.appendChild(option); +}); + +const handleStateChange = (state) => { + if (state.loading) { + selectEl.disabled = true; + createCollageBtn.disabled = true; + startOverBtn.disabled = true; + downloadBtn.disabled = true; + previewContainerEl.classList.add("previewContainer--disabled"); + spinnerContainerEl.classList.remove("spinnerContainer--hidden"); + spinnerTextEl.innerText = "Loading..."; + canvasEl.classList.remove("canvas--ready"); + } else if (!state.loading) { + selectEl.disabled = false; + createCollageBtn.disabled = false; + startOverBtn.disabled = false; + downloadBtn.disabled = false; + previewContainerEl.classList.remove("previewContainer--disabled"); + spinnerContainerEl.classList.add("spinnerContainer--hidden"); + canvasEl.classList.add("canvas--ready"); + } + + if (!state.selectedImages.size) { + createCollageBtn.disabled = true; + document.querySelectorAll(".badge").forEach((item) => item.remove()); + } else if (state.selectedImages.size && !state.loading) { + createCollageBtn.disabled = false; + } + + if (!state.collageRendered) { + downloadBtn.disabled = true; + } else if (state.collageRendered) { + downloadBtn.disabled = false; + } +}; +handleStateChange(state); + +const handleSelection = (e, imgName) => { + const imgEl = e.currentTarget; + + imgEl.classList.toggle("thumbnail-item--selected"); + + if (state.selectedImages.has(imgName)) { + state.selectedImages.delete(imgName); + state.selectedImages = new Set(state.selectedImages); + imgEl.querySelector(".badge")?.remove(); + } else { + state.selectedImages = new Set(state.selectedImages.add(imgName)); + + const badge = document.createElement("div"); + badge.classList.add("badge"); + badge.innerHTML = ` +
+ `; + imgEl.prepend(badge); + } +}; + +// Make a wrapper function. +let getCachedImage; +(async () => { + getCachedImage = await weakRefCache(loadImage); +})(); + +const calculateGridRows = (blobsLength) => + Math.ceil(blobsLength / state.currentLayout.columns); + +const drawCollage = (images) => { + state.drawing = true; + + let context = canvasEl.getContext("2d"); + + /** + * Calculate canvas dimensions based on the current layout. + * */ + context.canvas.width = + state.currentLayout.itemWidth * state.currentLayout.columns; + context.canvas.height = + calculateGridRows(images.length) * state.currentLayout.itemHeight; + + let currentRow = 0; + let currentCanvasDx = 0; + let currentCanvasDy = 0; + + for (let i = 0; i < images.length; i++) { + /** + * Get current row of the collage. + * */ + if (i % state.currentLayout.columns === 0) { + currentRow += 1; + currentCanvasDx = 0; + + if (currentRow > 1) { + currentCanvasDy += state.currentLayout.itemHeight; + } + } + + context.drawImage( + images[i], + 0, + 0, + images[i].width, + images[i].height, + currentCanvasDx, + currentCanvasDy, + state.currentLayout.itemWidth, + state.currentLayout.itemHeight, + ); + + currentCanvasDx += state.currentLayout.itemWidth; + } + + state.drawing = false; + state.collageRendered = true; +}; + +const createCollage = async () => { + state.loading = true; + + const images = []; + + for (const image of state.selectedImages.values()) { + const blobImage = await getCachedImage(image.img); + + const url = URL.createObjectURL(blobImage); + const img = await createImageFile(url); + + images.push(img); + URL.revokeObjectURL(url); + } + + state.loading = false; + + drawCollage(images); +}; + +/** + * Clear all settled data to start over. + * */ +const startOver = () => { + state.selectedImages = new Set(); + state.collageRendered = false; + const context = canvasEl.getContext("2d"); + context.clearRect(0, 0, canvasEl.width, canvasEl.height); + + document + .querySelectorAll(".thumbnail-item--selected") + .forEach((item) => item.classList.remove("thumbnail-item--selected")); + + loggerContainerEl.innerHTML = '

Logger:

'; +}; + +const downloadCollage = () => { + const date = new Date(); + const fileName = `Collage-${date.getDay()}-${date.getMonth()}-${date.getFullYear()}.png`; + const img = canvasEl.toDataURL("image/png"); + const link = document.createElement("a"); + link.download = fileName; + link.href = img; + link.click(); + link.remove(); +}; + +const changeLayout = ({ target }) => { + state.currentLayout = JSON.parse(target.value); +}; + +// Listeners. +selectEl.addEventListener("change", changeLayout); +createCollageBtn.addEventListener("click", createCollage); +startOverBtn.addEventListener("click", startOver); +downloadBtn.addEventListener("click", downloadCollage); diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/utils.js b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/utils.js new file mode 100644 index 000000000..f0140c116 --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/utils.js @@ -0,0 +1,321 @@ +const loggerContainerEl = document.querySelector(".loggerContainer"); + +export const images = [ + { + img: "https://images.unsplash.com/photo-1471357674240-e1a485acb3e1", + }, + { + img: "https://images.unsplash.com/photo-1589118949245-7d38baf380d6", + }, + { + img: "https://images.unsplash.com/photo-1527631746610-bca00a040d60", + }, + { + img: "https://images.unsplash.com/photo-1500835556837-99ac94a94552", + }, + { + img: "https://images.unsplash.com/photo-1503220317375-aaad61436b1b", + }, + { + img: "https://images.unsplash.com/photo-1501785888041-af3ef285b470", + }, + { + img: "https://images.unsplash.com/photo-1528543606781-2f6e6857f318", + }, + { + img: "https://images.unsplash.com/photo-1523906834658-6e24ef2386f9", + }, + { + img: "https://images.unsplash.com/photo-1539635278303-d4002c07eae3", + }, + { + img: "https://images.unsplash.com/photo-1533105079780-92b9be482077", + }, + { + img: "https://images.unsplash.com/photo-1516483638261-f4dbaf036963", + }, + { + img: "https://images.unsplash.com/photo-1502791451862-7bd8c1df43a7", + }, + { + img: "https://plus.unsplash.com/premium_photo-1663047367140-91adf819d007", + }, + { + img: "https://images.unsplash.com/photo-1506197603052-3cc9c3a201bd", + }, + { + img: "https://images.unsplash.com/photo-1517760444937-f6397edcbbcd", + }, + { + img: "https://images.unsplash.com/photo-1518684079-3c830dcef090", + }, + { + img: "https://images.unsplash.com/photo-1505832018823-50331d70d237", + }, + { + img: "https://images.unsplash.com/photo-1524850011238-e3d235c7d4c9", + }, + { + img: "https://plus.unsplash.com/premium_photo-1661277758451-b5053309eea1", + }, + { + img: "https://images.unsplash.com/photo-1541410965313-d53b3c16ef17", + }, + { + img: "https://images.unsplash.com/photo-1528702748617-c64d49f918af", + }, + { + img: "https://images.unsplash.com/photo-1502003148287-a82ef80a6abc", + }, + { + img: "https://plus.unsplash.com/premium_photo-1661281272544-5204ea3a481a", + }, + { + img: "https://images.unsplash.com/photo-1503457574462-bd27054394c1", + }, + { + img: "https://images.unsplash.com/photo-1499363536502-87642509e31b", + }, + { + img: "https://images.unsplash.com/photo-1551918120-9739cb430c6d", + }, + { + img: "https://plus.unsplash.com/premium_photo-1661382219642-43e54f7e81d7", + }, + { + img: "https://images.unsplash.com/photo-1497262693247-aa258f96c4f5", + }, + { + img: "https://images.unsplash.com/photo-1525254134158-4fd5fdd45793", + }, + { + img: "https://plus.unsplash.com/premium_photo-1661274025419-4c54107d5c48", + }, + { + img: "https://images.unsplash.com/photo-1553697388-94e804e2f0f6", + }, + { + img: "https://images.unsplash.com/photo-1574260031597-bcd9eb192b4f", + }, + { + img: "https://images.unsplash.com/photo-1536323760109-ca8c07450053", + }, + { + img: "https://images.unsplash.com/photo-1527824404775-dce343118ebc", + }, + { + img: "https://images.unsplash.com/photo-1612278675615-7b093b07772d", + }, + { + img: "https://images.unsplash.com/photo-1522010675502-c7b3888985f6", + }, + { + img: "https://images.unsplash.com/photo-1501555088652-021faa106b9b", + }, + { + img: "https://plus.unsplash.com/premium_photo-1669223469435-27e091439169", + }, + { + img: "https://images.unsplash.com/photo-1506012787146-f92b2d7d6d96", + }, + { + img: "https://images.unsplash.com/photo-1511739001486-6bfe10ce785f", + }, + { + img: "https://images.unsplash.com/photo-1553342385-111fd6bc6ab3", + }, + { + img: "https://images.unsplash.com/photo-1516546453174-5e1098a4b4af", + }, + { + img: "https://images.unsplash.com/photo-1527142879-95b61a0b8226", + }, + { + img: "https://images.unsplash.com/photo-1520466809213-7b9a56adcd45", + }, + { + img: "https://images.unsplash.com/photo-1516939884455-1445c8652f83", + }, + { + img: "https://images.unsplash.com/photo-1545389336-cf090694435e", + }, + { + img: "https://plus.unsplash.com/premium_photo-1669223469455-b7b734c838f4", + }, + { + img: "https://images.unsplash.com/photo-1454391304352-2bf4678b1a7a", + }, + { + img: "https://images.unsplash.com/photo-1433838552652-f9a46b332c40", + }, + { + img: "https://images.unsplash.com/photo-1506125840744-167167210587", + }, + { + img: "https://images.unsplash.com/photo-1522199873717-bc67b1a5e32b", + }, + { + img: "https://images.unsplash.com/photo-1495904786722-d2b5a19a8535", + }, + { + img: "https://images.unsplash.com/photo-1614094082869-cd4e4b2905c7", + }, + { + img: "https://images.unsplash.com/photo-1474755032398-4b0ed3b2ae5c", + }, + { + img: "https://images.unsplash.com/photo-1501554728187-ce583db33af7", + }, + { + img: "https://images.unsplash.com/photo-1515859005217-8a1f08870f59", + }, + { + img: "https://images.unsplash.com/photo-1531141445733-14c2eb7d4c1f", + }, + { + img: "https://images.unsplash.com/photo-1500259783852-0ca9ce8a64dc", + }, + { + img: "https://images.unsplash.com/photo-1510662145379-13537db782dc", + }, + { + img: "https://images.unsplash.com/photo-1573790387438-4da905039392", + }, + { + img: "https://images.unsplash.com/photo-1512757776214-26d36777b513", + }, + { + img: "https://images.unsplash.com/photo-1518855706573-84de4022b69b", + }, + { + img: "https://images.unsplash.com/photo-1500049242364-5f500807cdd7", + }, + { + img: "https://images.unsplash.com/photo-1528759335187-3b683174c86a", + }, +]; +export const THUMBNAIL_PARAMS = "w=240&h=240&fit=crop&auto=format"; + +// Console styles. +export const CONSOLE_BASE_STYLES = [ + "font-size: 12px", + "padding: 4px", + "border: 2px solid #5a5a5a", + "color: white", +].join(";"); +export const CONSOLE_PRIMARY = [ + CONSOLE_BASE_STYLES, + "background-color: #13315a", +].join(";"); +export const CONSOLE_SUCCESS = [ + CONSOLE_BASE_STYLES, + "background-color: #385a4e", +].join(";"); +export const CONSOLE_ERROR = [ + CONSOLE_BASE_STYLES, + "background-color: #5a1a24", +].join(";"); + +// Layouts. +export const LAYOUT_4_COLUMNS = { + name: "Layout 4 columns", + columns: 4, + itemWidth: 240, + itemHeight: 240, +}; +export const LAYOUT_8_COLUMNS = { + name: "Layout 8 columns", + columns: 8, + itemWidth: 240, + itemHeight: 240, +}; +export const LAYOUTS = [LAYOUT_4_COLUMNS, LAYOUT_8_COLUMNS]; + +export const createImageFile = async (src) => + new Promise((resolve, reject) => { + const img = new Image(); + img.src = src; + img.onload = () => resolve(img); + img.onerror = () => reject(new Error("Failed to construct image.")); + }); + +export const loadImage = async (url) => { + try { + const response = await fetch(url); + if (!response.ok) { + throw new Error(String(response.status)); + } + + return await response.blob(); + } catch (e) { + console.log(`%cFETCHED_FAILED: ${e}`, CONSOLE_ERROR); + } +}; + +export const weakRefCache = (fetchImg) => { + const imgCache = new Map(); + const registry = new FinalizationRegistry(({ imgName, size, type }) => { + const cachedImg = imgCache.get(imgName); + if (cachedImg && !cachedImg.deref()) { + imgCache.delete(imgName); + console.log( + `%cCLEANED_IMAGE: Url: ${imgName}, Size: ${size}, Type: ${type}`, + CONSOLE_ERROR, + ); + + const logEl = document.createElement("div"); + logEl.classList.add("logger-item", "logger--error"); + logEl.innerHTML = `CLEANED_IMAGE: Url: ${imgName}, Size: ${size}, Type: ${type}`; + loggerContainerEl.appendChild(logEl); + loggerContainerEl.scrollTop = loggerContainerEl.scrollHeight; + } + }); + + return async (imgName) => { + const cachedImg = imgCache.get(imgName); + + if (cachedImg?.deref() !== undefined) { + console.log( + `%cCACHED_IMAGE: Url: ${imgName}, Size: ${cachedImg.size}, Type: ${cachedImg.type}`, + CONSOLE_SUCCESS, + ); + + const logEl = document.createElement("div"); + logEl.classList.add("logger-item", "logger--success"); + logEl.innerHTML = `CACHED_IMAGE: Url: ${imgName}, Size: ${cachedImg.size}, Type: ${cachedImg.type}`; + loggerContainerEl.appendChild(logEl); + loggerContainerEl.scrollTop = loggerContainerEl.scrollHeight; + + return cachedImg?.deref(); + } + + const newImg = await fetchImg(imgName); + console.log( + `%cFETCHED_IMAGE: Url: ${imgName}, Size: ${newImg.size}, Type: ${newImg.type}`, + CONSOLE_PRIMARY, + ); + + const logEl = document.createElement("div"); + logEl.classList.add("logger-item", "logger--primary"); + logEl.innerHTML = `FETCHED_IMAGE: Url: ${imgName}, Size: ${newImg.size}, Type: ${newImg.type}`; + loggerContainerEl.appendChild(logEl); + loggerContainerEl.scrollTop = loggerContainerEl.scrollHeight; + + imgCache.set(imgName, new WeakRef(newImg)); + registry.register(newImg, { + imgName, + size: newImg.size, + type: newImg.type, + }); + + return newImg; + }; +}; + +export const stateObj = { + loading: false, + drawing: true, + collageRendered: false, + currentLayout: LAYOUTS[0], + selectedImages: new Set(), +}; diff --git a/2-ui/1-document/01-browser-environment/article.md b/2-ui/1-document/01-browser-environment/article.md index 43f558c07..c0ba3a112 100644 --- a/2-ui/1-document/01-browser-environment/article.md +++ b/2-ui/1-document/01-browser-environment/article.md @@ -1,10 +1,18 @@ # Il Browser come ambiente, specifiche +<<<<<<< HEAD Il linguaggio JavaScript è stato inizialmente creato per i browser. Da allora, si è evoluto fino a diventare un linguaggio adatto a molte piattaforme e differenti usi. La piattaforma di utilizzo può essere un browser, un web-server, una lavatrice o un qualunque altro tipo di *host*. Ognuno di essi fornisce delle funzionalità specifiche alla piattaforma stessa. Secondo la specifica JavaScript questa è la definizione di *ambiente host* Un ambiente host, oltre alle funzionalità core del linguaggio, fornisce oggetti e funzioni specifiche della piattaforma. I browser web, ad esempio, permettono di interagire con le pagine web, mentre Node.JS fornisce funzionalità dedicate al server e così via. +======= +The JavaScript language was initially created for web browsers. Since then, it has evolved into a language with many uses and platforms. + +A platform may be a browser, or a web-server or another *host*, or even a "smart" coffee machine if it can run JavaScript. Each of these provides platform-specific functionality. The JavaScript specification calls that a *host environment*. + +A host environment provides its own objects and functions in addition to the language core. Web browsers give a means to control web pages. Node.js provides server-side features, and so on. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Di seguito una panoramica di cosa succede quando JavaScript viene eseguito nel browser: @@ -15,7 +23,11 @@ C'è un oggetto "padre" chiamato `window` che ha due ruoli: 1. Il primo è quello di essere un oggetto globale per JavaScript, come descritto nel capitolo . 2. Il secondo è quello di rappresentare "la finestra del browser" e fornire metodi per controllarla. +<<<<<<< HEAD In questo caso lo utilizziamo come oggetto globale: +======= +For instance, we can use it as a global object: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run global function sayHi() { @@ -26,17 +38,29 @@ function sayHi() { window.sayHi(); ``` +<<<<<<< HEAD E qui invece come finestra del browser, vogliamo visualizzarne l'altezza: +======= +And we can use it as a browser window, to show the window height: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js run alert(window.innerHeight); // altezza interna della finestra ``` +<<<<<<< HEAD Ci sono molte altre funzionalità dell'oggetto `window`, ma le vedremo più avanti. ## DOM (Document Object Model) L'oggetto `document` dà accesso al contenuto della pagina e ci permette di cambiare o creare qualunque cosa all'interno della stessa. +======= +There are more window-specific methods and properties, which we'll cover later. + +## DOM (Document Object Model) + +The Document Object Model, or DOM for short, represents all page content as objects that can be modified. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ad esempio: @@ -48,18 +72,30 @@ document.body.style.background = "red"; setTimeout(() => document.body.style.background = "", 1000); ``` +<<<<<<< HEAD In questo caso abbiamo usato `document.body.style`, ma c'è molto di più. Proprietà e metodi sono descritti all'interno della specifica [DOM Living Standard](https://dom.spec.whatwg.org). +======= +Here, we used `document.body.style`, but there's much, much more. Properties and methods are described in the specification: [DOM Living Standard](https://dom.spec.whatwg.org). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```smart header="Il DOM non è solo per i browser" La specifica del DOM spiega la struttura di un documento e fornisce oggetti per la sua manipolazione. Esistono strumenti al di fuori del browser che usano comunque il DOM. +<<<<<<< HEAD Per esempio, strumenti lato server che scaricano e processano le pagine HTML sfruttano il DOM. In questo caso però potrebbero supportare solo una parte delle specifiche. +======= +For instance, server-side scripts that download HTML pages and process them can also use the DOM. They may support only a part of the specification though. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` ```smart header="CSSOM per lo stile" Regole CSS e fogli di stile non sono strutturati come l'HTML. Esiste una specifica separata [CSSOM](https://www.w3.org/TR/cssom-1/) che spiega come essi siano rappresentati come oggetti, come leggerli e scriverli. +<<<<<<< HEAD CSSOM è usato in concomitanza con il DOM quando modifichiamo delle regole di stile per il documento. In pratica però, CSSOM è raramente richiesto poiché di solito le regole CSS sono statiche. Di rado esiste la necessità di aggiungere/rimuovere regole CSS attraverso JavaScript, quindi non tratteremo l'argomento al momento. +======= +The CSSOM is used together with the DOM when we modify style rules for the document. In practice though, the CSSOM is rarely required, because we rarely need to modify CSS rules from JavaScript (usually we just add/remove CSS classes, not modify their CSS rules), but that's also possible. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` ## BOM (parte della specifica HTML) @@ -68,8 +104,13 @@ Il Browser Object Model (BOM) rappresenta gli oggetti aggiuntivi forniti dal bro Per esempio: +<<<<<<< HEAD - L'oggetto [navigator](mdn:api/Window/navigator) fornisce informazioni riguardo il browser e il sistema operativo. Ci sono molte proprietà a disposizione, ma quelle largamente conosciute sono: `navigator.userAgent` -- informazioni riguardo il browser corrente, e `navigator.platform` -- informazioni sulla piattaforma (può essere utile differenziare Windows/Linux/Mac etc). - L'oggetto [location](mdn:api/Window/location) permette di leggere l'URL corrente e reindirizzare il browser verso un altro URL. +======= +- The [navigator](mdn:api/Window/navigator) object provides background information about the browser and the operating system. There are many properties, but the two most widely known are: `navigator.userAgent` -- about the current browser, and `navigator.platform` -- about the platform (can help to differentiate between Windows/Linux/Mac etc). +- The [location](mdn:api/Window/location) object allows us to read the current URL and can redirect the browser to a new one. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ecco come possiamo usare l'oggetto `location`: @@ -80,25 +121,52 @@ if (confirm("Go to Wikipedia?")) { } ``` +<<<<<<< HEAD Le funzioni `alert/confirm/prompt` fanno anch'esse parte del BOM: non sono direttamente correlate con il documento, ma rappresentano dei semplici metodi del browser per interagire con l'utente. ```smart header="Specifiche HTML" Il BOM fa parte della [specifica HTML](https://html.spec.whatwg.org). Sì, avete capito bene. La specifica HTML presente al link non è solo per il "linguaggio HTML" (tags, attributi), ma copre anche una miriade di oggetti, metodi ed estensioni del DOM relative ai browser. Questa è la definizione di "HTML a grandi linee". +======= +The functions `alert/confirm/prompt` are also a part of the BOM: they are not directly related to the document, but represent pure browser methods for communicating with the user. + +```smart header="Specifications" +The BOM is a part of the general [HTML specification](https://html.spec.whatwg.org). + +Yes, you heard that right. The HTML spec at is not only about the "HTML language" (tags, attributes), but also covers a bunch of objects, methods, and browser-specific DOM extensions. That's "HTML in broad terms". Also, some parts have additional specs listed at . +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` ## Riepilogo Ricapitolando gli standard, abbiamo: +<<<<<<< HEAD Specifica DOM: Descrive la struttura del documento, sua manipolazione ed eventi, vedi . Specifica CSSOM: Descrive i fogli e le regole di stile, le loro manipolazioni e il loro legame con i documenti, vedi . +======= +DOM specification +: Describes the document structure, manipulations, and events, see . + +CSSOM specification +: Describes stylesheets and style rules, manipulations with them, and their binding to documents, see . +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Specifica HTML: Descrive il linguaggio HTML language (e.g. tags) e il BOM (browser object model) -- varie funzioni del browser: `setTimeout`, `alert`, `location` e così via, vedi . Prende la specifica del DOM e l'arricchisce di ulteriori proprietà e metodi. +<<<<<<< HEAD Per favore prendi nota dei link indicati in precedenza perché c'è talmente tanto da imparare che è impossibile trattare e ricordare ogni argomento. Quando avrai voglia di informarti su una proprietà o un metodo, il manuale Mozilla è sicuramente una buona risorsa, ma leggere la corrispondente specifica potrebbe essere addirittura meglio: è più complessa e lunga da leggere, ma consoliderà e completerà le tue conoscenze. +======= +Please note these links, as there's so much to learn that it's impossible to cover everything and remember it all. + +When you'd like to read about a property or a method, the Mozilla manual at is also a nice resource, but the corresponding spec may be better: it's more complex and longer to read, but will make your fundamental knowledge sound and complete. + +To find something, it's often convenient to use an internet search "WHATWG [term]" or "MDN [term]", e.g , . + +Now, we'll get down to learning the DOM, because the document plays the central role in the UI. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/2-ui/1-document/02-dom-nodes/article.md b/2-ui/1-document/02-dom-nodes/article.md index cef324b1f..67fef329b 100644 --- a/2-ui/1-document/02-dom-nodes/article.md +++ b/2-ui/1-document/02-dom-nodes/article.md @@ -210,7 +210,11 @@ In teoria esistono [12 tipologie di nodo](https://dom.spec.whatwg.org/#node), ma Per vedere la struttura del DOM in real-time, prova [Live DOM Viewer](http://software.hixie.ch/utilities/js/live-dom-viewer/). Inizia a scrivere e vedrai istantaneamente le modifiche aggiunte al DOM. +<<<<<<< HEAD Un altro modo per esplorare il DOM è usare gli "Strumenti per sviluppatori" del browser. Strumenti che usiamo quando sviluppiamo. +======= +To see the DOM structure in real-time, try [Live DOM Viewer](https://software.hixie.ch/utilities/js/live-dom-viewer/). Just type in the document, and it will show up as a DOM at an instant. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Per procedere in questo modo, apri la pagina web [elks.html](elks.html), apri "Strumenti per sviluppatori" e spostati sulla scheda "Elements". diff --git a/2-ui/1-document/02-dom-nodes/domconsole0.svg b/2-ui/1-document/02-dom-nodes/domconsole0.svg index ea0d9141c..eb99f193f 100644 --- a/2-ui/1-document/02-dom-nodes/domconsole0.svg +++ b/2-ui/1-document/02-dom-nodes/domconsole0.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/2-ui/1-document/02-dom-nodes/domconsole1.svg b/2-ui/1-document/02-dom-nodes/domconsole1.svg index d7f32debb..02ef5f0a6 100644 --- a/2-ui/1-document/02-dom-nodes/domconsole1.svg +++ b/2-ui/1-document/02-dom-nodes/domconsole1.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/2-ui/1-document/02-dom-nodes/elk.svg b/2-ui/1-document/02-dom-nodes/elk.svg index 1797a099f..448eea9d1 100644 --- a/2-ui/1-document/02-dom-nodes/elk.svg +++ b/2-ui/1-document/02-dom-nodes/elk.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/2-ui/1-document/02-dom-nodes/inspect.svg b/2-ui/1-document/02-dom-nodes/inspect.svg index a894a5c0e..60696ec0d 100644 --- a/2-ui/1-document/02-dom-nodes/inspect.svg +++ b/2-ui/1-document/02-dom-nodes/inspect.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/2-ui/1-document/04-searching-elements-dom/article.md b/2-ui/1-document/04-searching-elements-dom/article.md index d7f1911df..f5039c179 100644 --- a/2-ui/1-document/04-searching-elements-dom/article.md +++ b/2-ui/1-document/04-searching-elements-dom/article.md @@ -54,8 +54,13 @@ Inoltre, c'è una variabile globale chiamata come l'`id` che fa riferimento all' ``` +<<<<<<< HEAD ```warn header="Non utilizzate le variabili-id globali per accedere agli elementi" Questo comportamento è descritto [nella specifica](http://www.whatwg.org/specs/web-apps/current-work/#dom-window-nameditem), quindi è quasi uno standard, ma è supportato principalmente per una questione di compatibilità. +======= +```warn header="Please don't use id-named global variables to access elements" +This behavior is described [in the specification](https://html.spec.whatwg.org/multipage/window-object.html#named-access-on-the-window-object), but it is supported mainly for compatibility. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Il browser cerca di aiutarci mischiando i namespaces di JS e del DOM. Questo va bene per un semplice script, ma generalmente non è una buona cosa. Potrebbero esserci conflitti tra i nomi. Inoltre, quando uno legge il codice JS e non ha sott'occhio quello HTML non è ovvia la provenienza di una variabile. @@ -116,7 +121,11 @@ In altre parole, il risultato è lo stesso di `elem.querySelectorAll(css)[0]`, I metodi visti finora cercavano nel DOM. +<<<<<<< HEAD Il metodo [elem.matches(css)](http://dom.spec.whatwg.org/#dom-element-matches) non cerca nulla; controlla semplicemente se `elem` combacia con il selettore CSS specificato, e ritorna `true` o `false`. +======= +The [elem.matches(css)](https://dom.spec.whatwg.org/#dom-element-matches) does not look for anything, it merely checks if `elem` matches the given CSS-selector. It returns `true` or `false`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Questo metodo è utile quando stiamo iterando sopra degli elementi (come in un array) e cerchiamo di filtrare quelli che ci interessano. @@ -154,7 +163,7 @@ Ad esempio:
  • Chapter 1
  • -
  • Chapter 1
  • +
  • Chapter 2
diff --git a/2-ui/1-document/05-basic-dom-node-properties/article.md b/2-ui/1-document/05-basic-dom-node-properties/article.md index 8ccc44d07..74934aadd 100644 --- a/2-ui/1-document/05-basic-dom-node-properties/article.md +++ b/2-ui/1-document/05-basic-dom-node-properties/article.md @@ -10,7 +10,11 @@ Nodi del DOM differenti possono avere proprietà differenti. Ad esempio, un nodo Ogni nodo del DOM appartiene alla corrispondente classe nativa. +<<<<<<< HEAD La classe base della gerarchia è [EventTarget](https://dom.spec.whatwg.org/#eventtarget), che è ereditata dalla classe [Node](http://dom.spec.whatwg.org/#interface-node) da cui ereditano le altre classi corrispondenti ai nodi del DOM. +======= +The root of the hierarchy is [EventTarget](https://dom.spec.whatwg.org/#eventtarget), that is inherited by [Node](https://dom.spec.whatwg.org/#interface-node), and other DOM nodes inherit from it. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Qui lo schema, le spiegazioni a seguire: @@ -18,6 +22,7 @@ Qui lo schema, le spiegazioni a seguire: Le classi sono: +<<<<<<< HEAD - [EventTarget](https://dom.spec.whatwg.org/#eventtarget) -- è la classe radice (root class) "astratta". Gli oggetti di questa classe non vengono mai creati. Serve solo come base, in questo modo tutti i nodi del DOM supportano i cosiddetti "eventi" che studieremo successivamente. - [Node](http://dom.spec.whatwg.org/#interface-node) -- anche questa è una classe "astratta" che serve da base per i nodi del DOM. Fornisce le funzionalità principali della struttura gerarchica: `parentNode`, `nextSibling`, `childNodes` e così via (si tratta di getter). Dalla classe `Node` non vengono mai creati oggetti, tuttavia da questa ereditano classi corrispondenti a nodi concreti, nella fattispecie: `Text` per i nodi di testo, `Element` per i nodi elemento e quelli meno ricorrenti come `Comment` per i nodi commento. - [Element](http://dom.spec.whatwg.org/#interface-element) -- è la classe base per gli elementi del DOM. Fornisce le funzionalità di navigazione tra elementi come `nextElementSibling`, `children` ed i metodi di ricerca come `getElementsByTagName`, `querySelector`. Un browser non supporta solo HTML, ma anche XML e SVG. La classe `Element` serve da base per le classi più specifiche: `SVGElement`, `XMLElement` e `HTMLElement`. @@ -26,10 +31,45 @@ Le classi sono: - [HTMLBodyElement](https://html.spec.whatwg.org/multipage/semantics.html#htmlbodyelement) -- la classe per gli elementi ``, - [HTMLAnchorElement](https://html.spec.whatwg.org/multipage/semantics.html#htmlanchorelement) -- la classe per gli elementi ``, - ...e così via, ogni tag ha una propria classe che espone proprietà e metodi specifici. +======= +- [EventTarget](https://dom.spec.whatwg.org/#eventtarget) -- is the root "abstract" class for everything. + + Objects of that class are never created. It serves as a base, so that all DOM nodes support so-called "events", we'll study them later. + +- [Node](https://dom.spec.whatwg.org/#interface-node) -- is also an "abstract" class, serving as a base for DOM nodes. + + It provides the core tree functionality: `parentNode`, `nextSibling`, `childNodes` and so on (they are getters). Objects of `Node` class are never created. But there are other classes that inherit from it (and so inherit the `Node` functionality). + +- [Document](https://dom.spec.whatwg.org/#interface-document), for historical reasons often inherited by `HTMLDocument` (though the latest spec doesn't dictate it) -- is a document as a whole. + + The `document` global object belongs exactly to this class. It serves as an entry point to the DOM. + +- [CharacterData](https://dom.spec.whatwg.org/#interface-characterdata) -- an "abstract" class, inherited by: + - [Text](https://dom.spec.whatwg.org/#interface-text) -- the class corresponding to a text inside elements, e.g. `Hello` in `

Hello

`. + - [Comment](https://dom.spec.whatwg.org/#interface-comment) -- the class for comments. They are not shown, but each comment becomes a member of DOM. + +- [Element](https://dom.spec.whatwg.org/#interface-element) -- is the base class for DOM elements. + + It provides element-level navigation like `nextElementSibling`, `children` and searching methods like `getElementsByTagName`, `querySelector`. + + A browser supports not only HTML, but also XML and SVG. So the `Element` class serves as a base for more specific classes: `SVGElement`, `XMLElement` (we don't need them here) and `HTMLElement`. + +- Finally, [HTMLElement](https://html.spec.whatwg.org/multipage/dom.html#htmlelement) is the basic class for all HTML elements. We'll work with it most of the time. + + It is inherited by concrete HTML elements: + - [HTMLInputElement](https://html.spec.whatwg.org/multipage/forms.html#htmlinputelement) -- the class for `` elements, + - [HTMLBodyElement](https://html.spec.whatwg.org/multipage/semantics.html#htmlbodyelement) -- the class for `` elements, + - [HTMLAnchorElement](https://html.spec.whatwg.org/multipage/semantics.html#htmlanchorelement) -- the class for `
` elements, + - ...and so on. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 In definitiva, la lista completa delle proprietà e dei metodi di un nodo è il risultato dell'ereditarietà. +<<<<<<< HEAD Consideriamo, ad esempio, l'oggetto DOM per un elemento `` che appartiene alla classe [HTMLInputElement](https://html.spec.whatwg.org/multipage/forms.html#htmlinputelement). +======= +So, the full set of properties and methods of a given node comes as the result of the chain of inheritance. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Esso riceve proprietà e metodi per effetto della sovrapposizione di (elencate in ordine di ereditarietà): @@ -132,11 +172,19 @@ Per esempio: ``` +<<<<<<< HEAD Ma ci sono eccezioni; ad esempio `input.value` si sincronizza solo da attributo a proprietà, ma non al contrario: +======= +But there are exclusions, for instance `input.value` synchronizes only from attribute -> property, but not back: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```html run diff --git a/2-ui/1-document/07-modifying-document/5-why-aaa/task.md b/2-ui/1-document/07-modifying-document/5-why-aaa/task.md index 365a8ae47..5282b4e28 100644 --- a/2-ui/1-document/07-modifying-document/5-why-aaa/task.md +++ b/2-ui/1-document/07-modifying-document/5-why-aaa/task.md @@ -22,6 +22,10 @@ Perché? alert(table); // la tabella, come dovrebbe essere table.remove(); +<<<<<<< HEAD // perché aaa è ancora nel documento? +======= + // why there's still "aaa" in the document? +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` diff --git a/2-ui/1-document/08-styles-and-classes/article.md b/2-ui/1-document/08-styles-and-classes/article.md index 185c72f89..32209737d 100644 --- a/2-ui/1-document/08-styles-and-classes/article.md +++ b/2-ui/1-document/08-styles-and-classes/article.md @@ -129,8 +129,21 @@ setTimeout(() => document.body.style.display = "", 1000); // ritorna alla normal Se assegniamo una stringa vuota a `style.display`, il browser applica come di consueto le classi CSS ed i suoi stili predefiniti, come se non ci fosse alcuna proprietà `style.display`. +<<<<<<< HEAD ````smart header="Riscrittura completa con `style.cssText`" Di solito usiamo `style.*` per assegnare le proprietà di stile individualmente. Non possiamo impostare tutti gli stili in questo modo `div.style="color: red; width: 100px"`, perché `div.style` è un oggetto ed è in sola lettura. +======= +Also there is a special method for that, `elem.style.removeProperty('style property')`. So, We can remove a property like this: + +```js run +document.body.style.background = 'red'; //set background to red + +setTimeout(() => document.body.style.removeProperty('background'), 1000); // remove background after 1 second +``` + +````smart header="Full rewrite with `style.cssText`" +Normally, we use `style.*` to assign individual style properties. We can't set the full style like `div.style="color: red; width: 100px"`, because `div.style` is an object, and it's read-only. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Per impostare tutti gli stili come stringa c'è una speciale proprietà `style.cssText`: @@ -261,6 +274,7 @@ Attualmente, quindi, `getComputedStyle` restituisce il valore resolved della pro ````warn header="`getComputedStyle` richiede il nome completo della proprietà" Dovremmo sempre chiedere l'esatta proprietà che si desidera, come `paddingLeft` o `marginTop` o `borderTopWidth`. Diversamente il risultato corretto non è garantito. +<<<<<<< HEAD Per esempio, se ci sono le proprietà `paddingLeft/paddingTop`, cosa otterremmo con `getComputedStyle(elem).padding`? Niente, o forse un valore "generato" a partire dai valori di padding noti? Non esiste una regola standard in questo caso. Ci sono altre incongruenze. Ad esempio, alcuni browser (Chrome) mostrano `10px` nel documento in basso, ed altri (Firefox) -- invece no: @@ -276,6 +290,9 @@ Ci sono altre incongruenze. Ad esempio, alcuni browser (Chrome) mostrano `10px` alert(style.margin); // Firefox restituisce una stringa vuota ``` +======= +For instance, if there are properties `paddingLeft/paddingTop`, then what should we get for `getComputedStyle(elem).padding`? Nothing, or maybe a "generated" value from known paddings? There's no standard rule here. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```` ```smart header="Gli stili applicati ai link `:visited` sono nascosti!" diff --git a/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/field.svg b/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/field.svg index 4ae90b1c7..f5bd9f4f9 100644 --- a/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/field.svg +++ b/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/field.svg @@ -1 +1 @@ -(0,0)clientWidth \ No newline at end of file +(0,0)clientWidth \ No newline at end of file diff --git a/2-ui/1-document/09-size-and-scroll/article.md b/2-ui/1-document/09-size-and-scroll/article.md index ef666f254..6dbc338fa 100644 --- a/2-ui/1-document/09-size-and-scroll/article.md +++ b/2-ui/1-document/09-size-and-scroll/article.md @@ -17,8 +17,8 @@ Useremo l'elemento indicato sotto quale esempio di tali proprietà: width: 300px; height: 200px; border: 25px solid #E8C48F; - padding: 20px; - overflow: auto; + padding: 20px; + overflow: auto; } ``` @@ -106,7 +106,11 @@ Le proprietà geometriche sono calcolate solo per gli elementi visibili. Se un elemento (o uno dei suoi antenati) ha `display:none` o non è nel documento, allora tutte le proprietà geometriche valgono zero (o `null` per `offsetParent`). +<<<<<<< HEAD Per esempio, `offsetParent` vale `null`, e `offsetWidth`, `offsetHeight` sono `0` quando abbiamo creato un elemento, ma non lo abbiamo ancora inserito nel documento, o esso (o un suo antenato) ha `display:none`. +======= +For example, `offsetParent` is `null`, and `offsetWidth`, `offsetHeight` are `0` when we created an element, but haven't inserted it into the document yet, or it (or its ancestor) has `display:none`. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Possiamo servirci di questa particolarità per verificare se un elemento è nascosto, in questo modo: diff --git a/2-ui/1-document/09-size-and-scroll/metric-all.svg b/2-ui/1-document/09-size-and-scroll/metric-all.svg index a5dadb47f..20a59e18d 100644 --- a/2-ui/1-document/09-size-and-scroll/metric-all.svg +++ b/2-ui/1-document/09-size-and-scroll/metric-all.svg @@ -1 +1 @@ -Introduction This Ecma Standard is based on several originating technologies, the most well known being JavaScript (Netscape) and JScript (Microsoft). The language was invented by Brendan Eich at Netscape and first appeared in that company’s Navigator 2.0 browser. It has appeared in all subsequent browsers from Netscape and in all browsers from Microsoft starting with Internet Explorer 3.0. The development of this Standard started in November 1996. The first edition of this Ecma Standard was adopted by the Ecma General Assembly of June 1997. That Ecma Standard was submitted to ISO/ IEC JTC 1 for adoption under the fast-track procedure, and approved as international standard ISO/IEC 16262, in April 1998. The Ecma General Assembly of June 1998 approved the second edition of ECMA-262 to keep it fully aligned with ISO/IEC 16262. Changes between the first and the second edition are editorial in nature.scrollHeightoffsetHeightscrollTopclientHeightoffsetTopclientLeftclientWidthclientTopoffsetLeftoffsetWidth \ No newline at end of file +Introduction This Ecma Standard is based on several originating technologies, the most well known being JavaScript (Netscape) and JScript (Microsoft). The language was invented by Brendan Eich at Netscape and first appeared in that company’s Navigator 2.0 browser. It has appeared in all subsequent browsers from Netscape and in all browsers from Microsoft starting with Internet Explorer 3.0. The development of this Standard started in November 1996. The first edition of this Ecma Standard was adopted by the Ecma General Assembly of June 1997. That Ecma Standard was submitted to ISO/ IEC JTC 1 for adoption under the fast-track procedure, and approved as international standard ISO/IEC 16262, in April 1998. The Ecma General Assembly of June 1998 approved the second edition of ECMA-262 to keep it fully aligned with ISO/IEC 16262. Changes between the first and the second edition are editorial in nature.scrollHeightoffsetHeightscrollTopclientHeightoffsetTopclientLeftclientWidthclientTopoffsetLeftoffsetWidth \ No newline at end of file diff --git a/2-ui/1-document/09-size-and-scroll/metric-client-left-top-rtl.svg b/2-ui/1-document/09-size-and-scroll/metric-client-left-top-rtl.svg index dd9e17cf8..e8dd3d60a 100644 --- a/2-ui/1-document/09-size-and-scroll/metric-client-left-top-rtl.svg +++ b/2-ui/1-document/09-size-and-scroll/metric-client-left-top-rtl.svg @@ -1 +1 @@ -clientTop: 25px = borderclientLeft: 41px \ No newline at end of file +clientTop: 25px = borderclientLeft: 41px \ No newline at end of file diff --git a/2-ui/1-document/09-size-and-scroll/metric-client-left-top.svg b/2-ui/1-document/09-size-and-scroll/metric-client-left-top.svg index 968590466..8097afa78 100644 --- a/2-ui/1-document/09-size-and-scroll/metric-client-left-top.svg +++ b/2-ui/1-document/09-size-and-scroll/metric-client-left-top.svg @@ -1 +1 @@ -Introduction This Ecma Standard is based on several originating technologies, the most well known being JavaScript (Netscape) and JScript (Microsoft). The language was invented by Brendan Eich at Netscape and first appeared in that company’s Navigator 2.0 browser. It has appeared in all subsequent browsers from Netscape and in all browsers from Microsoft starting with Internet Explorer 3.0. The development of this Standard started in November 1996. The first edition of this Ecma Standard was adopted by the Ecma General Assembly of June 1997.clientTop: 25px = borderclientLeft: 25px \ No newline at end of file +Introduction This Ecma Standard is based on several originating technologies, the most well known being JavaScript (Netscape) and JScript (Microsoft). The language was invented by Brendan Eich at Netscape and first appeared in that company’s Navigator 2.0 browser. It has appeared in all subsequent browsers from Netscape and in all browsers from Microsoft starting with Internet Explorer 3.0. The development of this Standard started in November 1996. The first edition of this Ecma Standard was adopted by the Ecma General Assembly of June 1997.clientTop: 25px = borderclientLeft: 25px \ No newline at end of file diff --git a/2-ui/1-document/09-size-and-scroll/metric-client-width-height.svg b/2-ui/1-document/09-size-and-scroll/metric-client-width-height.svg index 83864b4c5..2603b05fb 100644 --- a/2-ui/1-document/09-size-and-scroll/metric-client-width-height.svg +++ b/2-ui/1-document/09-size-and-scroll/metric-client-width-height.svg @@ -1 +1 @@ -border 25pxpadding 20pxcontent width: 284pxborder 25pxpadding 20pxscrollbar 16pxclientWidth = 20+284+20 = 324pxclientHeight: 240pxheight: 200pxIntroduction This Ecma Standard is based on several originating technologies, the most well known being JavaScript (Netscape) and JScript (Microsoft). The language was invented by Brendan Eich at Netscape and first appeared in that company’s Navigator 2.0 browser. It has appeared in all subsequent browsers from Netscape and in all browsers from Microsoft starting with \ No newline at end of file +border 25pxpadding 20pxcontent width: 284pxborder 25pxpadding 20pxscrollbar 16pxclientWidth = 20+284+20 = 324pxclientHeight: 240pxheight: 200pxIntroduction This Ecma Standard is based on several originating technologies, the most well known being JavaScript (Netscape) and JScript (Microsoft). The language was invented by Brendan Eich at Netscape and first appeared in that company’s Navigator 2.0 browser. It has appeared in all subsequent browsers from Netscape and in all browsers from Microsoft starting with \ No newline at end of file diff --git a/2-ui/1-document/09-size-and-scroll/metric-css.svg b/2-ui/1-document/09-size-and-scroll/metric-css.svg index 13aa62afd..1f2e5f780 100644 --- a/2-ui/1-document/09-size-and-scroll/metric-css.svg +++ b/2-ui/1-document/09-size-and-scroll/metric-css.svg @@ -1 +1 @@ -padding: 20pxheight: 200pxpadding: 20pxborder 25pxpadding 20pxcontent width: 284pxborder 25pxpadding 20pxscrollbar 16pxIntroduction This Ecma Standard is based on several originating technologies, the most well known being JavaScript (Netscape) and JScript (Microsoft). The language was invented by Brendan Eich at Netscape and first appeared in that company’s Navigator 2.0 browser. It has appeared in all subsequent browsers from Netscape and in all browsers from Microsoft starting with \ No newline at end of file +padding: 20pxheight: 200pxpadding: 20pxborder 25pxpadding 20pxcontent width: 284pxborder 25pxpadding 20pxscrollbar 16pxIntroduction This Ecma Standard is based on several originating technologies, the most well known being JavaScript (Netscape) and JScript (Microsoft). The language was invented by Brendan Eich at Netscape and first appeared in that company’s Navigator 2.0 browser. It has appeared in all subsequent browsers from Netscape and in all browsers from Microsoft starting with \ No newline at end of file diff --git a/2-ui/1-document/09-size-and-scroll/metric-offset-parent.svg b/2-ui/1-document/09-size-and-scroll/metric-offset-parent.svg index 9e247639b..2d108473e 100644 --- a/2-ui/1-document/09-size-and-scroll/metric-offset-parent.svg +++ b/2-ui/1-document/09-size-and-scroll/metric-offset-parent.svg @@ -1 +1 @@ -offsetTop: 180pxoffsetLeft: 180pxIntroduction This Ecma Standard is based on several originating technologies, the most well known being JavaScript (Netscape) and JScript (Microsoft). The language was invented by Brendan Eich at Netscape and first appeared in that company’s Navigator 2.0 browser. It has appeared in all subsequent browsers from Netscape and in all browsers from Microsoftposition: absolute; left: 180px; top: 180px;offsetParent <MAIN> <DIV> \ No newline at end of file +offsetTop: 180pxoffsetLeft: 180pxIntroduction This Ecma Standard is based on several originating technologies, the most well known being JavaScript (Netscape) and JScript (Microsoft). The language was invented by Brendan Eich at Netscape and first appeared in that company’s Navigator 2.0 browser. It has appeared in all subsequent browsers from Netscape and in all browsers from Microsoftposition: absolute; left: 180px; top: 180px;offsetParent <MAIN> <DIV> \ No newline at end of file diff --git a/2-ui/1-document/09-size-and-scroll/metric-offset-width-height.svg b/2-ui/1-document/09-size-and-scroll/metric-offset-width-height.svg index 49bdccda7..4d30d90cc 100644 --- a/2-ui/1-document/09-size-and-scroll/metric-offset-width-height.svg +++ b/2-ui/1-document/09-size-and-scroll/metric-offset-width-height.svg @@ -1 +1 @@ -border 25pxpadding 20pxcontent width: 284pxheight: 200pxborder 25pxpadding 20pxscrollbar 16pxoffsetWidth = 25+20+284+20+16+25 = 390pxoffsetHeight: 290pxIntroduction This Ecma Standard is based on several originating technologies, the most well known being JavaScript (Netscape) and JScript (Microsoft). The language was invented by Brendan Eich at Netscape and first appeared in that company’s Navigator 2.0 browser. It has appeared in all subsequent browsers from Netscape and in all browsers from Microsoft starting with \ No newline at end of file +border 25pxpadding 20pxcontent width: 284pxheight: 200pxborder 25pxpadding 20pxscrollbar 16pxoffsetWidth = 25+20+284+20+16+25 = 390pxoffsetHeight: 290pxIntroduction This Ecma Standard is based on several originating technologies, the most well known being JavaScript (Netscape) and JScript (Microsoft). The language was invented by Brendan Eich at Netscape and first appeared in that company’s Navigator 2.0 browser. It has appeared in all subsequent browsers from Netscape and in all browsers from Microsoft starting with \ No newline at end of file diff --git a/2-ui/1-document/09-size-and-scroll/metric-scroll-top.svg b/2-ui/1-document/09-size-and-scroll/metric-scroll-top.svg index c6d14d0f3..7f72de422 100644 --- a/2-ui/1-document/09-size-and-scroll/metric-scroll-top.svg +++ b/2-ui/1-document/09-size-and-scroll/metric-scroll-top.svg @@ -1 +1 @@ -Introduction This Ecma Standard is based on several originating technologies, the most well known being JavaScript (Netscape) and JScript (Microsoft). The language was invented by Brendan Eich at Netscape and first appeared in that company’s Navigator 2.0 browser. It has appeared in all subsequent browsers from Netscape and in all browsers from Microsoft starting with Internet Explorer 3.0. The development of this Standard started in November 1996. The first edition of this Ecma Standard was adopted by the Ecma General Assembly of June 1997. That Ecma Standard was submitted to ISO/ IEC JTC 1 for adoption under the fast-track procedure, and approved as international standard ISO/IEC 16262, in April 1998. The Ecma General Assembly of June 1998 approved the second edition of ECMA-262 to keep it fully aligned with ISO/IEC 16262. Changes between the first and the second edition are editorial in nature.scrollTopscrollHeight: 723px \ No newline at end of file +Introduction This Ecma Standard is based on several originating technologies, the most well known being JavaScript (Netscape) and JScript (Microsoft). The language was invented by Brendan Eich at Netscape and first appeared in that company’s Navigator 2.0 browser. It has appeared in all subsequent browsers from Netscape and in all browsers from Microsoft starting with Internet Explorer 3.0. The development of this Standard started in November 1996. The first edition of this Ecma Standard was adopted by the Ecma General Assembly of June 1997. That Ecma Standard was submitted to ISO/ IEC JTC 1 for adoption under the fast-track procedure, and approved as international standard ISO/IEC 16262, in April 1998. The Ecma General Assembly of June 1998 approved the second edition of ECMA-262 to keep it fully aligned with ISO/IEC 16262. Changes between the first and the second edition are editorial in nature.scrollTopscrollHeight: 723px \ No newline at end of file diff --git a/2-ui/1-document/09-size-and-scroll/metric-scroll-width-height.svg b/2-ui/1-document/09-size-and-scroll/metric-scroll-width-height.svg index 0c3d29952..75a24e3bc 100644 --- a/2-ui/1-document/09-size-and-scroll/metric-scroll-width-height.svg +++ b/2-ui/1-document/09-size-and-scroll/metric-scroll-width-height.svg @@ -1 +1 @@ -Introduction This Ecma Standard is based on several originating technologies, the most well known being JavaScript (Netscape) and JScript (Microsoft). The language was invented by Brendan Eich at Netscape and first appeared in that company’s Navigator 2.0 browser. It has appeared in all subsequent browsers from Netscape and in all browsers from Microsoft starting with Internet Explorer 3.0. The development of this Standard started in November 1996. The first edition of this Ecma Standard was adopted by the Ecma General Assembly of June 1997. That Ecma Standard was submitted to ISO/IEC JTC 1 for adoption under the fast-track procedure, and approved as international standard ISO/IEC 16262, in April 1998. The Ecma General Assembly of June 1998 approved the second edition of ECMA-262 to keep it fully aligned with ISO/IEC 16262. Changes between the first and the second edition are editorial in nature.scrollHeight: 723pxscrollWidth = 324px \ No newline at end of file +Introduction This Ecma Standard is based on several originating technologies, the most well known being JavaScript (Netscape) and JScript (Microsoft). The language was invented by Brendan Eich at Netscape and first appeared in that company’s Navigator 2.0 browser. It has appeared in all subsequent browsers from Netscape and in all browsers from Microsoft starting with Internet Explorer 3.0. The development of this Standard started in November 1996. The first edition of this Ecma Standard was adopted by the Ecma General Assembly of June 1997. That Ecma Standard was submitted to ISO/IEC JTC 1 for adoption under the fast-track procedure, and approved as international standard ISO/IEC 16262, in April 1998. The Ecma General Assembly of June 1998 approved the second edition of ECMA-262 to keep it fully aligned with ISO/IEC 16262. Changes between the first and the second edition are editorial in nature.scrollHeight: 723pxscrollWidth = 324px \ No newline at end of file diff --git a/2-ui/1-document/10-size-and-scroll-window/document-client-width-height.svg b/2-ui/1-document/10-size-and-scroll-window/document-client-width-height.svg index 65e77ae80..18cd37a74 100644 --- a/2-ui/1-document/10-size-and-scroll-window/document-client-width-height.svg +++ b/2-ui/1-document/10-size-and-scroll-window/document-client-width-height.svg @@ -1 +1 @@ -documentElement.clientHeightdocumentElement.clientWidth \ No newline at end of file +documentElement.clientHeightdocumentElement.clientWidth \ No newline at end of file diff --git a/2-ui/1-document/11-coordinates/article.md b/2-ui/1-document/11-coordinates/article.md index 74b0ad434..3250eb8dd 100644 --- a/2-ui/1-document/11-coordinates/article.md +++ b/2-ui/1-document/11-coordinates/article.md @@ -36,7 +36,11 @@ Ci sono, inoltre, proprietà derivate: ```online Clicca, per esempio, su questo pulsante per conoscere le sue coordinate relative alla finestra: +<<<<<<< HEAD

+======= +

+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` +<<<<<<< HEAD Come possiamo osservare, se `addEventListener` riceve un oggetto come gestore, allora chiama `obj.handleEvent(event)` nel caso ci sia un evento. +======= +As we can see, when `addEventListener` receives an object as the handler, it calls `obj.handleEvent(event)` in case of an event. + +We could also use objects of a custom class, like this: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Possiamo usare anche una classe: @@ -391,6 +424,7 @@ Possiamo usare anche una classe: *!* let menu = new Menu(); + elem.addEventListener('mousedown', menu); elem.addEventListener('mouseup', menu); */!* diff --git a/2-ui/2-events/02-bubbling-and-capturing/article.md b/2-ui/2-events/02-bubbling-and-capturing/article.md index 113e42ab7..0b25eac02 100644 --- a/2-ui/2-events/02-bubbling-and-capturing/article.md +++ b/2-ui/2-events/02-bubbling-and-capturing/article.md @@ -120,27 +120,46 @@ In genere non ci sono reali necessità di interrompere il *bubbling*. Un problem C'è un'altra fase nell'elaborazione degli eventi, chiamata "capturing". Viene usata raramente nel codice, ma talvolta può essere utile. +<<<<<<< HEAD Lo standard [DOM Events](http://www.w3.org/TR/DOM-Level-3-Events/) descrive 3 fasi nella propagazione dell'evento: +======= +The standard [DOM Events](https://www.w3.org/TR/DOM-Level-3-Events/) describes 3 phases of event propagation: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 1. Fase capturing -- l'evento va sull'elemento. 2. Fase target -- l'evento ha raggiunto l'elemento target. 3. Fase bubbling -- l'evento risale su dall'elemento. +<<<<<<< HEAD Ecco la figura estratta dalle specifiche, di un click su un `` dentro una tabella: +======= +Here's the picture, taken from the specification, of the capturing `(1)`, target `(2)` and bubbling `(3)` phases for a click event on a `` inside a table: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ![](eventflow.svg) Ossia: per un click su `` l'evento prima attraversa la catena degli antenati e scende giù fino all'elemento (fase *capturing*), dopodiché raggiunge il target ed è lì che viene innescato (fase *target*), ed infine risale su (fase di *bubbling*) chiamando i gestori lungo il suo cammino. +<<<<<<< HEAD **Prima abbiamo accennato solo al *bubbling*, in quanto la fase *capturing* è usata raramente. Normalmente è assolutamente trasparente.** I gestori aggiunti usando le proprietà `on` o tramite gli attributi HTML o usando solo due argomenti in `addEventListener(event, handler)` non sanno nulla della fase di *capturing*, ma verranno coinvolti solo nella seconda e terza fase. +======= +Until now, we only talked about bubbling, because the capturing phase is rarely used. + +In fact, the capturing phase was invisible for us, because handlers added using `on`-property or using HTML attributes or using two-argument `addEventListener(event, handler)` don't know anything about capturing, they only run on the 2nd and 3rd phases. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Per catturare un evento in questa fase, abbiamo bisogno di impostare l'opzione `capture` a `true` nel gestore: ```js elem.addEventListener(..., {capture: true}) +<<<<<<< HEAD // oppure solamente "true" che è un alias per {capture: true} +======= + +// or, just "true" is an alias to {capture: true} +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 elem.addEventListener(..., true) ``` @@ -180,9 +199,16 @@ Il codice imposta i gestori di click per *ogni* elemento nel documento per vede Se clicchiamo su `

`, la sequenza sarà: +<<<<<<< HEAD 1. `HTML` -> `BODY` -> `FORM` -> `DIV` (fase di *capturing*, il primo listener): 2. `P` (fase target, viene innescata due volte, dato che abbiamo impostato due listener: *capturing* e *bubbling*) 3. `DIV` -> `FORM` -> `BODY` -> `HTML` (fase *bubbling*, il secondo listener). +======= +1. `HTML` -> `BODY` -> `FORM` -> `DIV -> P` (capturing phase, the first listener): +2. `P` -> `DIV` -> `FORM` -> `BODY` -> `HTML` (bubbling phase, the second listener). + +Please note, the `P` shows up twice, because we've set two listeners: capturing and bubbling. The target triggers at the end of the first and at the beginning of the second phase. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 La proprietà `event.eventPhase` restituisce il numero della fase in cui l'evento è stato catturato, ma viene usata raramente, dato che possiamo dedurla dal gestore. @@ -190,8 +216,13 @@ La proprietà `event.eventPhase` restituisce il numero della fase in cui l'event Se abbiamo assegnato l'evento con `addEventListener(..., true)`, allora siamo obbligati a fare menzione della stessa fase in `removeEventListener(..., true)` per rimuovere l'handler con successo. ``` +<<<<<<< HEAD ````smart header="A parità di elemento e fase, i listeners verranno eseguiti secondo l'ordine di assegnazione" Nel caso in cui avessimo più gestori assegnati alla stessa fase, assegnati allo stesso evento, tramite `addEventListener`, verranno eseguiti secondo l'ordine di creazione: +======= +````smart header="Listeners on the same element and same phase run in their set order" +If we have multiple event handlers on the same phase, assigned to the same element with `addEventListener`, they run in the same order as they are created: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js elem.addEventListener("click", e => alert(1)); // vi è garanzia che venga eseguito prima @@ -199,6 +230,12 @@ elem.addEventListener("click", e => alert(2)); ``` ```` +```smart header="The `event.stopPropagation()` during the capturing also prevents the bubbling" +The `event.stopPropagation()` method and its sibling `event.stopImmediatePropagation()` can also be called on the capturing phase. Then not only the futher capturing is stopped, but the bubbling as well. + +In other words, normally the event goes first down ("capturing") and then up ("bubbling"). But if `event.stopPropagation()` is called during the capturing phase, then the event travel stops, no bubbling will occur. +``` + ## Riepilogo @@ -216,7 +253,11 @@ Ogni handler accede alle proprietà dell'oggetto `event`: Qualunque gestore può interrompere la propagazione dell'evento chiamando `event.stopPropagation()`, ma non è raccomandabile, in quanto non possiamo essere del tutto sicuri che non ne abbiamo bisogno ai livelli superiori, magari per questioni del tutto differenti. +<<<<<<< HEAD La fase di *capturing* viene usata molto raramente, solitamente gestiamo gli eventi nella fase di *bubbling*. Ed in questo c'è una logica. +======= +The capturing phase is used very rarely, usually we handle events on bubbling. And there's a logical explanation for that. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Nel mondo reale, quando avviene un incidente, prima intervengono le autorità locali. Loro conoscono meglio il posto dove è avvenuto. Quindi intervengono e autorità di alto livello in caso di necessità. diff --git a/2-ui/2-events/02-bubbling-and-capturing/event-order-bubbling.svg b/2-ui/2-events/02-bubbling-and-capturing/event-order-bubbling.svg index b62d99089..2ea88f081 100644 --- a/2-ui/2-events/02-bubbling-and-capturing/event-order-bubbling.svg +++ b/2-ui/2-events/02-bubbling-and-capturing/event-order-bubbling.svg @@ -1 +1 @@ -123Most deeply nested element \ No newline at end of file +123Most deeply nested element \ No newline at end of file diff --git a/2-ui/2-events/03-event-delegation/article.md b/2-ui/2-events/03-event-delegation/article.md index 9339c816a..c7e654423 100644 --- a/2-ui/2-events/03-event-delegation/article.md +++ b/2-ui/2-events/03-event-delegation/article.md @@ -1,7 +1,11 @@ # Event delegation +<<<<<<< HEAD Capturing e bubbling ci permettono di implementare uno dei pattern più potenti nella gestione degli eventi, e cioè *event delegation*. +======= +Capturing and bubbling allow us to implement one of the most powerful event handling patterns called *event delegation*. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Il concetto di base è che se abbiamo una serie di elementi gestiti in maniera simile, allora, invece di assegnare un gestore per ognuno di essi, possiamo metterne uno solo sui loro antenati comuni. diff --git a/2-ui/2-events/03-event-delegation/bagua-bubble.svg b/2-ui/2-events/03-event-delegation/bagua-bubble.svg index c4cd1ee1e..4ae67102d 100644 --- a/2-ui/2-events/03-event-delegation/bagua-bubble.svg +++ b/2-ui/2-events/03-event-delegation/bagua-bubble.svg @@ -1 +1 @@ -<table><td><strong>event.target \ No newline at end of file +<table><td><strong>event.target \ No newline at end of file diff --git a/2-ui/2-events/04-default-browser-action/article.md b/2-ui/2-events/04-default-browser-action/article.md index e34cf5e66..6d86cc58b 100644 --- a/2-ui/2-events/04-default-browser-action/article.md +++ b/2-ui/2-events/04-default-browser-action/article.md @@ -17,7 +17,11 @@ Ci sono due modi per comunicare al browser che non vogliamo che esegua l'azione - Il più comune è quello di usare il metodo `event.preventDefault()`, incluso nell'oggetto `event`. - Se il gestore viene assegnato tramite `on` (e non tramite `addEventListener`), allora restituire `false` sortirà lo stesso effetto. +<<<<<<< HEAD In questo HTML un click su un link non innescherà la navigazione verso l'URL, e di fatto il browser non farà nulla: +======= +In this HTML, a click on a link doesn't lead to navigation; the browser doesn't do anything: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```html autorun height=60 no-beautify Clicca qui @@ -96,7 +100,11 @@ Questo perché l'azione del browser viene annullata sul `mousedown`. Il focus sa L'opzione facoltativa `passive: true` di `addEventListener` segnala al browser che il gestore non chiamerà `preventDefault()`. +<<<<<<< HEAD Perché dovrebbe essere necessaria una cosa del genere? +======= +Why might that be needed? +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ci sono alcuni eventi come `touchmove` su dispositivi *mobile* (quando l'utente sposta le dita lungo lo schermo), che di default causerebbero lo scrolling, ma ciò può essere evitato con `preventDefault()` sul gestore. diff --git a/2-ui/2-events/05-dispatch-events/article.md b/2-ui/2-events/05-dispatch-events/article.md index d6be03964..376b410eb 100644 --- a/2-ui/2-events/05-dispatch-events/article.md +++ b/2-ui/2-events/05-dispatch-events/article.md @@ -8,7 +8,11 @@ Possiamo generare non solo eventi del tutto nuovi, creati apposta per i nostri s ## Costruttore dell'evento +<<<<<<< HEAD Le classi degli eventi predefiniti formano una gerarchia, similmente alle classi degli elementi del DOM. La classe base è [Event](http://www.w3.org/TR/dom/#event). +======= +Built-in event classes form a hierarchy, similar to DOM element classes. The root is the built-in [Event](https://dom.spec.whatwg.org/#events) class. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Gli oggetti `Event` vengono creati così: @@ -208,7 +212,11 @@ Nota bene: l'evento deve avere il flag `cancelable: true`, altrimenti la chiamat ## Gli eventi annidati sono sincroni +<<<<<<< HEAD Solitamente gli eventi vengono elaborati in una coda. Ossia: se il browser sta elaborando `onclick` e viene generato un nuovo evento, ad esempio il mouse viene mosso, il suo gestore verrà messo in coda, ed i corrispondenti gestori di `mousemove` verranno chiamati dopo che l'elaborazione di `onclick` sarà terminata. +======= +Usually events are processed in a queue. That is: if the browser is processing `onclick` and a new event occurs, e.g. mouse moved, then its handling is queued up, corresponding `mousemove` handlers will be called after `onclick` processing is finished. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 L'eccezione degna di nota è quando un evento viene inizializzato all'interno di un altro, ad esempio usando `dispatchEvent`. Questi eventi vengono elaborati immediatamente: i gestori del nuovo evento vengono chiamati, e successivamente viene ristabilita la gestione dell'evento corrente. diff --git a/2-ui/3-event-details/1-mouse-events-basics/article.md b/2-ui/3-event-details/1-mouse-events-basics/article.md index 797b66c05..d62da1bfe 100644 --- a/2-ui/3-event-details/1-mouse-events-basics/article.md +++ b/2-ui/3-event-details/1-mouse-events-basics/article.md @@ -1,4 +1,9 @@ +<<<<<<< HEAD # Eventi del mouse +======= + +# Mouse events +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 In questo capitolo andremo un po' più a fondo sugli eventi del mouse e le loro proprietà. @@ -39,9 +44,15 @@ Quando un'azione singola inizia eventi multipli, il loro ordine è fisso. Ossia, ```online Premi il seguente pulsante e vedrai gli eventi. prova anche il doppio click. +<<<<<<< HEAD Nel banco di prova in basso, vengono elencati tutti gli eventi del mouse, e se passa più di un secondo tra uno e l'altro vengono separati da una riga orizzontale. Possiamo inoltre notare la proprietà `button` che permette di rilevare il pulsante del mouse, viene spiegato successivamente. +======= +On the teststand below, all mouse events are logged, and if there is more than a 1 second delay between them, they are separated by a horizontal rule. + +Also, we can see the `button` property that allows us to detect the mouse button; it's explained below. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9

``` @@ -52,7 +63,11 @@ Gli eventi relativi al click contengono sempre la proprietà `button`, che perme Solitamente non lo usiamo per gli eventi `click` e `contextmenu`, perché il primo avviene solo per il click sul pulsante sinistro, ed il secondo -- solo per quelli sul tasto destro. +<<<<<<< HEAD D'altra parte, i gestori `mousedown` e `mouseup` potrebbero necessitare di `event.button`, in quanto questi eventi vengono generati su qualunque pulsante, quindi `button` permette di discriminare tra "mousedown destro" e "mousedown sinistro". +======= +On the other hand, `mousedown` and `mouseup` handlers may need `event.button`, because these events trigger on any button, so `button` allows to distinguish between "right-mousedown" and "left-mousedown". +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 I valori possibili di `event.button` sono: @@ -154,7 +169,11 @@ Muovere il mouse sopra il campo di testo per vedere `clientX/clientY` (l'esempio ## Prevenire la selezione su mousedown +<<<<<<< HEAD Il doppio click del mouse ha un effetto collaterale che potrebbe dare fastidio in alcune interfacce: seleziona il testo. +======= +Double mouse click has a side effect that may be disturbing in some interfaces: it selects text. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Per esempio, il doppio click sul seguente testo lo seleziona in aggiunta al nostro gestore: diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/1-behavior-nested-tooltip/solution.view/index.html b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/1-behavior-nested-tooltip/solution.view/index.html index 8b624d9f8..47621f542 100644 --- a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/1-behavior-nested-tooltip/solution.view/index.html +++ b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/1-behavior-nested-tooltip/solution.view/index.html @@ -54,7 +54,7 @@

Once upon a time there was a mother pig who had three little pigs.

-

The three little pigs grew so big that their mother said to them, "You are too big to live here any longer. You must go and build houses for yourselves. But take care that the wolf does not catch you." +

The three little pigs grew so big that their mother said to them, "You are too big to live here any longer. You must go and build houses for yourselves. But take care that the wolf does not catch you."

The three little pigs set off. "We will take care that the wolf does not catch us," they said.

diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/1-behavior-nested-tooltip/source.view/index.html b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/1-behavior-nested-tooltip/source.view/index.html index 119c38756..6e7055254 100644 --- a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/1-behavior-nested-tooltip/source.view/index.html +++ b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/1-behavior-nested-tooltip/source.view/index.html @@ -54,7 +54,7 @@

Once upon a time there was a mother pig who had three little pigs.

-

The three little pigs grew so big that their mother said to them, "You are too big to live here any longer. You must go and build houses for yourselves. But take care that the wolf does not catch you." +

The three little pigs grew so big that their mother said to them, "You are too big to live here any longer. You must go and build houses for yourselves. But take care that the wolf does not catch you."

The three little pigs set off. "We will take care that the wolf does not catch us," they said.

diff --git a/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/field.svg b/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/field.svg index 4ae90b1c7..f5bd9f4f9 100644 --- a/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/field.svg +++ b/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/field.svg @@ -1 +1 @@ -(0,0)clientWidth \ No newline at end of file +(0,0)clientWidth \ No newline at end of file diff --git a/2-ui/3-event-details/4-mouse-drag-and-drop/article.md b/2-ui/3-event-details/4-mouse-drag-and-drop/article.md index d5ac29102..c335be643 100644 --- a/2-ui/3-event-details/4-mouse-drag-and-drop/article.md +++ b/2-ui/3-event-details/4-mouse-drag-and-drop/article.md @@ -18,11 +18,16 @@ L'algoritmo di base del Drag'n'Drop è qualcosa del genere: 2. Quindi al `mousemove` spostalo variando `left/top` con il `position:absolute`. 3. Al `mouseup` - esegui tutte le azioni coinvolte per completare il drag'n'drop. +<<<<<<< HEAD Queste sono le basi. Dopo vedremo come gestire altre caratteristiche, come evidenziare gli altri elementi sottostanti mentre effettuiamo il trascinamento su di essi. +======= +These are the basics. Later we'll see how to add other features, such as highlighting current underlying elements while we drag over them. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ecco un'implementazione del trascinamento di un pallone: ```js +<<<<<<< HEAD ball.onmousedown = function(event) { // (1) preparazione dello spostamento: imposta il posizionamento assoluto e lo z-index al massimo valore utile ball.style.position = 'absolute'; @@ -31,6 +36,16 @@ ball.onmousedown = function(event) { // spostamento all'esterno da ogni elemento genitore e direttamente verso il body della pagina // per posizionarlo relativamente ad esso document.body.append(ball); +======= +ball.onmousedown = function(event) { + // (1) prepare to moving: make absolute and on top by z-index + ball.style.position = 'absolute'; + ball.style.zIndex = 1000; + + // move it out of any current parents directly into body + // to make it positioned relative to the body + document.body.append(ball); +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 // centratura del pallone alle coordinate (pageX, pageY) function moveAt(pageX, pageY) { @@ -93,14 +108,22 @@ Di conseguenza dovremmo metterci in ascolto sul `document` per la cattura. ## Posizionamento corretto +<<<<<<< HEAD Negli esempi precedenti il pallone viene sempre spostato in modo che il suo centro sia sotto il puntatore: +======= +In the examples above the ball is always moved so that its center is under the pointer: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js ball.style.left = pageX - ball.offsetWidth / 2 + 'px'; ball.style.top = pageY - ball.offsetHeight / 2 + 'px'; ``` +<<<<<<< HEAD Non male, ma c'è un effetto collaterale. Per innescare il drag'n'drop, potremmo cominciare `mousedown` da un punto qualunque del pallone. Ma se lo "prendessimo" dai bordi, si centrerebbe repentinamente sotto il puntatore facendo una specie di "salto". +======= +Not bad, but there's a side effect. To initiate the drag'n'drop, we can `mousedown` anywhere on the ball. But if "take" it from its edge, then the ball suddenly "jumps" to become centered under the mouse pointer. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Sarebbe meglio se mantenessimo lo spostamento iniziale dell'elemento rispetto al puntatore. @@ -219,7 +242,11 @@ Questo è il motivo per cui l'idea iniziale di impostare i gestori su dei potenz Come fare, quindi? +<<<<<<< HEAD C'è un metodo chiamato `document.elementFromPoint(clientX, clientY)` che restituisce le coordinate relative alla window, dell'elemento più annidato (o `null` se le coordinate restituite sono fuori dalla window). +======= +There's a method called `document.elementFromPoint(clientX, clientY)`. It returns the most nested element on given window-relative coordinates (or `null` if given coordinates are out of the window). If there are multiple overlapping elements on the same coordinates, then the topmost one is returned. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Possiamo usarlo su qualunque nostro gestore di evento del mouse per rilevare dei potenziali droppable sotto il puntatore, in questo modo: 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 a9034ea43..b52cd1670 100644 --- a/2-ui/3-event-details/6-pointer-events/article.md +++ b/2-ui/3-event-details/6-pointer-events/article.md @@ -71,7 +71,17 @@ Alcuni dispositivi di puntamento misurano l'area di contatto e la pressione, ad - `tangentialPressure` - la pressione tangenziale normalizzata. - `tiltX`, `tiltY`, `twist` - proprietà specifiche delle penne che descrivono come la penna è posizionata rispetto alla superficie dello schermo. +<<<<<<< HEAD Queste proprietà non sono supportate dalla maggioranza dei dispositivi, per questo vengono usate raramente. In caso di necessità potete trovarne i dettagli nelle [specifiche](https://w3c.github.io/pointerevents/#pointerevent-interface). +======= +- `width` - the width of the area where the pointer (e.g. a finger) touches the device. Where unsupported, e.g. for a mouse, it's always `1`. +- `height` - the height of the area where the pointer touches the device. Where unsupported, it's always `1`. +- `pressure` - the pressure of the pointer tip, in range from 0 to 1. For devices that don't support pressure must be either `0.5` (pressed) or `0`. +- `tangentialPressure` - the normalized tangential pressure. +- `tiltX`, `tiltY`, `twist` - pen-specific properties that describe how the pen is positioned relative to the surface. + +These properties aren't supported by most devices, so they are rarely used. You can find the details about them in the [specification](https://w3c.github.io/pointerevents/#pointerevent-interface) if needed. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Multi-touch @@ -111,7 +121,11 @@ Le cause possono essere: Ecco un caso reale di evento `pointercancel` per vedere cosa e come ci influenza. +<<<<<<< HEAD Mettiamo il caso che stiamo implementando il drag'n'drop per un pallone, proprio come fatto all'inizio dell'articolo . +======= +Let's say we're implementing drag'n'drop for a ball, just as in the beginning of the article . +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ecco il flusso delle azioni dell'utente e gli eventi corrispondenti: @@ -126,7 +140,11 @@ Ecco il flusso delle azioni dell'utente e gli eventi corrispondenti: Qui il problema è che il browser "dirotta" l'interazione: viene generato `pointercancel` all'inizio del processo di "drag-and-drop", e non vengono più generati eventi `pointermove`. ```online +<<<<<<< HEAD Ecco una demo con drag'n'drop con il tracciamento degli eventi del puntatore (solo per `up/down`, `move` e `cancel`) nella `textarea`: +======= +Here's the drag'n'drop demo with logging of pointer events (only `up/down`, `move` and `cancel`) in the `textarea`: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 [iframe src="ball" height=240 edit] ``` diff --git a/2-ui/3-event-details/7-keyboard-events/article.md b/2-ui/3-event-details/7-keyboard-events/article.md index 87851fd2a..d5615eb04 100644 --- a/2-ui/3-event-details/7-keyboard-events/article.md +++ b/2-ui/3-event-details/7-keyboard-events/article.md @@ -107,7 +107,11 @@ Quindi, `event.code` può corrispondere a un carattere errato su layout non cont Per il tracciamento affidabile dei caratteri che sono dipendenti dal layout, `event.key` potrebbe essere la soluzione migliore. +<<<<<<< HEAD Di contro, `event.code` ha il beneficio di essere sempre lo stesso, legato alla posizione fisica del tasto, anche se il visitatore dovesse modificare la lingua. E le scorciatoie ad esso relative funzioneranno bene anche in caso di cambio lingua. +======= +On the other hand, `event.code` has the benefit of staying always the same, bound to the physical key location. So hotkeys that rely on it work well even in case of a language switch. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Vogliamo gestire dei tasti dipendenti dal layout? Ecco che `event.key` è quello che fa per noi. @@ -153,7 +157,7 @@ Come sappiamo, il valore `false` restituito da un gestore di evento, assegnato u Rendiamolo un po' più rilassato permettendo i tasti freccia `key:Left`, `key:Right` e `key:Delete`, `key:Backspace`:: -Please note that special keys, such as `key:Backspace`, `key:Left`, `key:Right`, do not work in the input. That's a side-effect of the strict filter `checkPhoneKey`. These keys make it return `false`. +Please note that special keys, such as `key:Backspace`, `key:Left`, `key:Right`, do not work in the input. That's a side effect of the strict filter `checkPhoneKey`. These keys make it return `false`. Let's relax the filter a little bit by allowing arrow keys `key:Left`, `key:Right` and `key:Delete`, `key:Backspace`: diff --git a/2-ui/4-forms-controls/1-form-elements/article.md b/2-ui/4-forms-controls/1-form-elements/article.md index e87f3e15e..9819d63d3 100644 --- a/2-ui/4-forms-controls/1-form-elements/article.md +++ b/2-ui/4-forms-controls/1-form-elements/article.md @@ -155,7 +155,11 @@ Parliamo un po' dei form controls. ### input e textarea +<<<<<<< HEAD Possiamo accedere ai lori valori tramite `input.value` (string) o `input.checked` (boolean) per i checkbox. +======= +We can access their value as `input.value` (string) or `input.checked` (boolean) for checkboxes and radio buttons. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Come in questo caso: @@ -244,7 +248,11 @@ Questa sintassi è opzionale. Possiamo usare `document.createElement('option')` - `defaultSelected` -- se `true`, allora verrà creato l'attributo HTML `selected`, - `selected` -- se `true`, allora l'opzione verrà selezionata. +<<<<<<< HEAD La differenza tra `defaultSelected` e `selected` è che `defaultSelected` imposta l'attributo HTML (che possiamo ottenere usando `option.getAttribute('selected')`, mentre `selected` definisce lo stato della selezione (se è selezionata o meno). +======= +The difference between `defaultSelected` and `selected` is that `defaultSelected` sets the HTML-attribute (that we can get using `option.getAttribute('selected')`), while `selected` sets whether the option is selected or not. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 In pratica, solitamente possiamo impostare entrambi i valori a `true` o `false` (oppure ometterli, che equivale a `false`). diff --git a/2-ui/4-forms-controls/2-focus-blur/article.md b/2-ui/4-forms-controls/2-focus-blur/article.md index 24d4289fd..5d89715d0 100644 --- a/2-ui/4-forms-controls/2-focus-blur/article.md +++ b/2-ui/4-forms-controls/2-focus-blur/article.md @@ -90,8 +90,15 @@ Se inseriamo qualcosa nell'input e proviamo ad usare `key:Tab` o cliccare fuori Nota bene che non possiamo "prevenire la perdita del focus" chiamando `event.preventDefault()` su `onblur`, poiché `onblur` viene creato *dopo* che l'elemento ha perso il focus. +<<<<<<< HEAD ```warn header="Perdita del focus creata tramite JavaScript" La perdita del focus può avvenire per varie ragioni. +======= +In practice though, one should think well, before implementing something like this, because we generally *should show errors* to the user, but *should not prevent their progress* in filling our form. They may want to fill other fields first. + +```warn header="JavaScript-initiated focus loss" +A focus loss can occur for many reasons. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Una di queste è quando il visitatore clicca da qualche altra parte. Ma anche JavaScript stesso può causarlo, per esempio: diff --git a/2-ui/4-forms-controls/3-events-change-input/article.md b/2-ui/4-forms-controls/3-events-change-input/article.md index 20d7ffa66..aa3660069 100644 --- a/2-ui/4-forms-controls/3-events-change-input/article.md +++ b/2-ui/4-forms-controls/3-events-change-input/article.md @@ -86,14 +86,38 @@ Questo perché `clipboardData` implementa l'interfaccia `DataTransfer`, usata co ```warn header="ClipboardAPI: restrizione per la sicurezza dell'utente" La clipboard è una caratteristica "globale" a livello del sistema operativo. I browser quindi, per ragioni di sicurezza, consentono l'accesso in lettura/scrittura solo per certe azioni dell'utente, ad esempio nei gestori evento `onclick`. +<<<<<<< HEAD Inoltre è vietato generare eventi clipboard "personalizzati" tramite `dispatchEvent` in tutti i browser eccetto Firefox. ``` +======= +That's because `clipboardData` implements `DataTransfer` interface, commonly used for drag'n'drop and copy/pasting. It's a bit beyond our scope now, but you can find its methods in the [DataTransfer specification](https://html.spec.whatwg.org/multipage/dnd.html#the-datatransfer-interface). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ## Riepilogo Eventi di modifica dati: +<<<<<<< HEAD | Evento | Descrizione | Speciali | +======= +The clipboard is a "global" OS-level thing. A user may switch between various applications, copy/paste different things, and a browser page shouldn't see all that. + +So most browsers allow seamless read/write access to the clipboard only in the scope of certain user actions, such as copying/pasting etc. + +It's forbidden to generate "custom" clipboard events with `dispatchEvent` in all browsers except Firefox. And even if we manage to dispatch such event, the specification clearly states that such "synthetic" events must not provide access to the clipboard. + +Even if someone decides to save `event.clipboardData` in an event handler, and then access it later -- it won't work. + +To reiterate, [event.clipboardData](https://www.w3.org/TR/clipboard-apis/#clipboardevent-clipboarddata) works solely in the context of user-initiated event handlers. + +On the other hand, [navigator.clipboard](https://www.w3.org/TR/clipboard-apis/#h-navigator-clipboard) is the more recent API, meant for use in any context. It asks for user permission, if needed. + +## Summary + +Data change events: + +| Event | Description | Specials | +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 |---------|----------|-------------| | `change`| È stato modificato un valore. | Per il testo viene generato alla perdita del focus. | | `input` | Per gli input di testo ad ogni modifica. | Viene generato immediatamente diversamente da `change`. | diff --git a/2-ui/5-loading/01-onload-ondomcontentloaded/article.md b/2-ui/5-loading/01-onload-ondomcontentloaded/article.md index 1f5d52e4e..083903b3e 100644 --- a/2-ui/5-loading/01-onload-ondomcontentloaded/article.md +++ b/2-ui/5-loading/01-onload-ondomcontentloaded/article.md @@ -88,7 +88,11 @@ Ma c'è una trappola. Se abbiamo uno script dopo uno stile quello script deve as ```html run ``` @@ -264,7 +268,7 @@ Ecco un documento con ` - + diff --git a/2-ui/5-loading/01-onload-ondomcontentloaded/readystate.view/index.html b/2-ui/5-loading/01-onload-ondomcontentloaded/readystate.view/index.html index 3eddcf33e..1a644722c 100644 --- a/2-ui/5-loading/01-onload-ondomcontentloaded/readystate.view/index.html +++ b/2-ui/5-loading/01-onload-ondomcontentloaded/readystate.view/index.html @@ -9,8 +9,8 @@ [20] readyState:interactive [21] DOMContentLoaded [30] iframe onload - [40] readyState:complete [40] img onload + [40] readyState:complete [40] window onload --> diff --git a/2-ui/99-ui-misc/02-selection-range/article.md b/2-ui/99-ui-misc/02-selection-range/article.md index 3aa6bc9d5..c02931b9d 100644 --- a/2-ui/99-ui-misc/02-selection-range/article.md +++ b/2-ui/99-ui-misc/02-selection-range/article.md @@ -250,8 +250,55 @@ Fondamentalmente, con questi metodi possiamo fare qualunque cosa con i nodi sele Ecco il banco di prova per vederli in azione: +<<<<<<< HEAD ```html run autorun height=260 Clicca sui pulsanti per eseguire i metodi nella selezione, "resetExample" per resettare. +======= +## Range selection methods + +There are many convenient methods to manipulate ranges. + +We've already seen `setStart` and `setEnd`, here are other similar methods. + +Set range start: + +- `setStart(node, offset)` set start at: position `offset` in `node` +- `setStartBefore(node)` set start at: right before `node` +- `setStartAfter(node)` set start at: right after `node` + +Set range end (similar methods): + +- `setEnd(node, offset)` set end at: position `offset` in `node` +- `setEndBefore(node)` set end at: right before `node` +- `setEndAfter(node)` set end at: right after `node` + +Technically, `setStart/setEnd` can do anything, but more methods provide more convenience. + +In all these methods, `node` can be both a text or element node: for text nodes `offset` skips that many of characters, while for element nodes that many child nodes. + +Even more methods to create ranges: +- `selectNode(node)` set range to select the whole `node` +- `selectNodeContents(node)` set range to select the whole `node` contents +- `collapse(toStart)` if `toStart=true` set end=start, otherwise set start=end, thus collapsing the range +- `cloneRange()` creates a new range with the same start/end + +## Range editing methods + +Once the range is created, we can manipulate its content using these methods: + +- `deleteContents()` -- remove range content from the document +- `extractContents()` -- remove range content from the document and return as [DocumentFragment](info:modifying-document#document-fragment) +- `cloneContents()` -- clone range content and return as [DocumentFragment](info:modifying-document#document-fragment) +- `insertNode(node)` -- insert `node` into the document at the beginning of the range +- `surroundContents(node)` -- wrap `node` around range content. For this to work, the range must contain both opening and closing tags for all elements inside it: no partial ranges like `abc`. + +With these methods we can do basically anything with selected nodes. + +Here's the test stand to see them in action: + +```html run refresh autorun height=260 +Click buttons to run methods on the selection, "resetExample" to reset it. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9

Example: italic and bold

@@ -347,7 +394,11 @@ Le proprietà principali di selection sono: - `rangeCount` -- conto del numero di selezioni, massimo `1` su tutti i browser, eccetto Firefox. +<<<<<<< HEAD ```smart header="Selection end/start contro Range" +======= +There's an important difference between a selection anchor/focus compared with a `Range` start/end. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Esiste un'importante differenza tra una selection anchor/focus e un `Range` start/end. @@ -402,8 +453,13 @@ From – To Ci sono due approcci alla copia del contenuto di una selezione: +<<<<<<< HEAD 1. Possiamo usare `document.getSelection().toString()` per avere il contenuto come testo. 2. Oppure possiamo copiare il DOM completo (ad esempio se volgiamo mantenere la formattazione) recuperando i ranges con `getRangesAt(...)`. Un oggetto `Range` possiede il metodo `cloneContents()` che clona il contenuto e lo ritorna come oggetto `DocumentFragment`, che può essere inserito dove necessario. +======= +1. We can use `document.getSelection().toString()` to get it as text. +2. Otherwise, to copy the full DOM, e.g. if we need to keep formatting, we can get the underlying ranges with `getRangeAt(...)`. A `Range` object, in turn, has `cloneContents()` method that clones its content and returns as `DocumentFragment` object, that we can insert elsewhere. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Ecco la demo per copiare il contenuto selezionato, sia come testo che come nodi del DOM: @@ -433,7 +489,11 @@ As text: ## Metodi per la selezione +<<<<<<< HEAD Possiamo lavorare con la selezione aggiungendo/rimuovendo ranges: +======= +We can work with the selection by adding/removing ranges: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 - `getRangeAt(i)` -- legge il range alla posizione i, partendo da '0'. In tutti i browser, tranne Firefox, viene usato solo `0`. - `addRange(range)` -- aggiunge `range` alla selezione. Tutti i browser, eccetto Firefox, ignorano la chiamata, se la selezione ha già un range associato. diff --git a/2-ui/99-ui-misc/02-selection-range/range-example-p-0-1.svg b/2-ui/99-ui-misc/02-selection-range/range-example-p-0-1.svg index 9ebcffaac..a97d1b47a 100644 --- a/2-ui/99-ui-misc/02-selection-range/range-example-p-0-1.svg +++ b/2-ui/99-ui-misc/02-selection-range/range-example-p-0-1.svg @@ -1 +1 @@ -0123 \ No newline at end of file +0123 \ No newline at end of file diff --git a/2-ui/99-ui-misc/02-selection-range/range-example-p-1-3.svg b/2-ui/99-ui-misc/02-selection-range/range-example-p-1-3.svg index 088c71c20..2a8f9aca3 100644 --- a/2-ui/99-ui-misc/02-selection-range/range-example-p-1-3.svg +++ b/2-ui/99-ui-misc/02-selection-range/range-example-p-1-3.svg @@ -1 +1 @@ -0123 \ No newline at end of file +0123 \ No newline at end of file diff --git a/2-ui/99-ui-misc/02-selection-range/range-example-p-2-b-3-range.svg b/2-ui/99-ui-misc/02-selection-range/range-example-p-2-b-3-range.svg index f13c6d74a..32843436d 100644 --- a/2-ui/99-ui-misc/02-selection-range/range-example-p-2-b-3-range.svg +++ b/2-ui/99-ui-misc/02-selection-range/range-example-p-2-b-3-range.svg @@ -1 +1 @@ -startContainer (<p>.firstChild)startOffset (=2)commonAncestorContainer (<p>)endContainer (<b>.firstChild)endOffset (=3) \ No newline at end of file +startContainer (<p>.firstChild)startOffset (=2)commonAncestorContainer (<p>)endContainer (<b>.firstChild)endOffset (=3) \ No newline at end of file diff --git a/2-ui/99-ui-misc/02-selection-range/range-example-p-2-b-3.svg b/2-ui/99-ui-misc/02-selection-range/range-example-p-2-b-3.svg index 4bf5b00b0..859f755ce 100644 --- a/2-ui/99-ui-misc/02-selection-range/range-example-p-2-b-3.svg +++ b/2-ui/99-ui-misc/02-selection-range/range-example-p-2-b-3.svg @@ -1 +1 @@ -0123 \ No newline at end of file +0123 \ No newline at end of file diff --git a/2-ui/99-ui-misc/02-selection-range/selection-direction-backward.svg b/2-ui/99-ui-misc/02-selection-range/selection-direction-backward.svg index 6399f9d5e..85615d38f 100644 --- a/2-ui/99-ui-misc/02-selection-range/selection-direction-backward.svg +++ b/2-ui/99-ui-misc/02-selection-range/selection-direction-backward.svg @@ -1 +1 @@ -focusanchormouse move direction \ No newline at end of file +focusanchormouse move direction \ No newline at end of file diff --git a/2-ui/99-ui-misc/02-selection-range/selection-direction-forward.svg b/2-ui/99-ui-misc/02-selection-range/selection-direction-forward.svg index 03c6fc5c6..511b00a26 100644 --- a/2-ui/99-ui-misc/02-selection-range/selection-direction-forward.svg +++ b/2-ui/99-ui-misc/02-selection-range/selection-direction-forward.svg @@ -1 +1 @@ -anchorfocusmouse move direction \ No newline at end of file +anchorfocusmouse move direction \ No newline at end of file diff --git a/2-ui/99-ui-misc/02-selection-range/selection-firefox.svg b/2-ui/99-ui-misc/02-selection-range/selection-firefox.svg index 050852d3d..aa7ff1eb7 100644 --- a/2-ui/99-ui-misc/02-selection-range/selection-firefox.svg +++ b/2-ui/99-ui-misc/02-selection-range/selection-firefox.svg @@ -1 +1 @@ -selection \ No newline at end of file +selection \ No newline at end of file diff --git a/2-ui/99-ui-misc/03-event-loop/2-micro-macro-queue/solution.md b/2-ui/99-ui-misc/03-event-loop/2-micro-macro-queue/solution.md new file mode 100644 index 000000000..2911b76cf --- /dev/null +++ b/2-ui/99-ui-misc/03-event-loop/2-micro-macro-queue/solution.md @@ -0,0 +1,50 @@ +The console output is: 1 7 3 5 2 6 4. + +The task is quite simple, we just need to know how microtask and macrotask queues work. + +Let's see what's going on, step by step. + +```js +console.log(1); +// The first line executes immediately, it outputs `1`. +// Macrotask and microtask queues are empty, as of now. + +setTimeout(() => console.log(2)); +// `setTimeout` appends the callback to the macrotask queue. +// - macrotask queue content: +// `console.log(2)` + +Promise.resolve().then(() => console.log(3)); +// The callback is appended to the microtask queue. +// - microtask queue content: +// `console.log(3)` + +Promise.resolve().then(() => setTimeout(() => console.log(4))); +// The callback with `setTimeout(...4)` is appended to microtasks +// - microtask queue content: +// `console.log(3); setTimeout(...4)` + +Promise.resolve().then(() => console.log(5)); +// The callback is appended to the microtask queue +// - microtask queue content: +// `console.log(3); setTimeout(...4); console.log(5)` + +setTimeout(() => console.log(6)); +// `setTimeout` appends the callback to macrotasks +// - macrotask queue content: +// `console.log(2); console.log(6)` + +console.log(7); +// Outputs 7 immediately. +``` + +To summarize, + +1. Numbers `1` and `7` show up immediately, because simple `console.log` calls don't use any queues. +2. Then, after the main code flow is finished, the microtask queue runs. + - It has commands: `console.log(3); setTimeout(...4); console.log(5)`. + - Numbers `3` and `5` show up, while `setTimeout(() => console.log(4))` adds the `console.log(4)` call to the end of the macrotask queue. + - The macrotask queue is now: `console.log(2); console.log(6); console.log(4)`. +3. After the microtask queue becomes empty, the macrotask queue executes. It outputs `2`, `6`, `4`. + +Finally, we have the output: `1 7 3 5 2 6 4`. \ No newline at end of file diff --git a/2-ui/99-ui-misc/03-event-loop/2-micro-macro-queue/task.md b/2-ui/99-ui-misc/03-event-loop/2-micro-macro-queue/task.md new file mode 100644 index 000000000..ad406b3be --- /dev/null +++ b/2-ui/99-ui-misc/03-event-loop/2-micro-macro-queue/task.md @@ -0,0 +1,21 @@ +importance: 5 + +--- + +# What will be the output of this code? + +```js +console.log(1); + +setTimeout(() => console.log(2)); + +Promise.resolve().then(() => console.log(3)); + +Promise.resolve().then(() => setTimeout(() => console.log(4))); + +Promise.resolve().then(() => console.log(5)); + +setTimeout(() => console.log(6)); + +console.log(7); +``` diff --git a/2-ui/99-ui-misc/03-event-loop/article.md b/2-ui/99-ui-misc/03-event-loop/article.md index c545a0a6d..4fbe95966 100644 --- a/2-ui/99-ui-misc/03-event-loop/article.md +++ b/2-ui/99-ui-misc/03-event-loop/article.md @@ -18,7 +18,11 @@ A grandi linee, l'algoritmo del motore è così: Questa è una trasposizione di quello che vediamo mentre navighiamo in una pagina web. Il motore di Javascript non fa nulla per la maggior parte del tempo, e va in esecuzione quando si attiva uno script/handler/evento. +<<<<<<< HEAD Esempio di tasks: +======= +That's a formalization of what we see when browsing a page. The JavaScript engine does nothing most of the time, it only runs if a script/handler/event activates. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 - Quando viene caricato uno script esterno ` +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` La maggior parte delle animazioni possono essere implementate con CSS come descritto in questo articolo. Insieme all'evento `transitionend` possiamo eseguire codice al termine dell'animazione, integrandoci perfettamente con l'animazione. diff --git a/7-animation/3-js-animation/article.md b/7-animation/3-js-animation/article.md index 1e4957cec..b6e4da86f 100644 --- a/7-animation/3-js-animation/article.md +++ b/7-animation/3-js-animation/article.md @@ -79,7 +79,11 @@ Questa serie di operazioni di repaint dovrebbero essere raggruppate, in modo tal C'è un ulteriore cosa a cui prestare attenzione. Talvolta la CPU potrebbe essere sovraccarica, oppure potrebbero esserci altri motivi per cui potremmo effettuare il repaint con minore frequenza (ad esempio quando la tab del browser non è visibile), quindi non è necessaria l'esecuzione ogni `20ms`. +<<<<<<< HEAD Ma come facciamo ad avere controllo su questo utilizzando JavaScript? Abbiamo a disposizione [Animation timing](http://www.w3.org/TR/animation-timing/) definita nelle specifiche, che ci fornisce la funzione `requestAnimationFrame`. Questa ha lo scopo di aiutarci a risolvere questo tipo di problemi. +======= +But how do we know about that in JavaScript? There's a specification [Animation timing](https://www.w3.org/TR/animation-timing/) that provides the function `requestAnimationFrame`. It addresses all these issues and even more. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 La sintassi: ```js @@ -96,7 +100,11 @@ Il valore ritornato, `requestId`, può essere utilizzato per annullare l'invocaz cancelAnimationFrame(requestId); ``` +<<<<<<< HEAD La `callback` riceve un solo argomento, il tempo trascorso dall'inizio del caricamento della pagina, in microsecondi. Possiamo ottenere questa informazione anche invocando [performance.now()](mdn:api/Performance/now). +======= +The `callback` gets one argument -- the time passed from the beginning of the page load in milliseconds. This time can also be obtained by calling [performance.now()](mdn:api/Performance/now). +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Solitamente `callback` viene eseguita molto presto, a meno che la CPU non sia in uno stato di sovraccarico, la batteria del portatile non sia quasi scarica, o per altri motivi. @@ -159,7 +167,11 @@ La funzione `animate` accetta 3 parametri che descrivono l'animazione: } ``` +<<<<<<< HEAD La curva corrispondente: +======= + Its graph: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ![](linear.svg) Proprio come `transition-timing-function: linear`. Vengono mostrare altre varianti sotto. @@ -452,4 +464,8 @@ Ovviamente potremmo migliorarla aggiungendo più opzioni, ma le animazioni JavaS Le animazioni JavaScript possono utilizzare qualsiasi funzione di temporizzazione. Abbiamo visto molti esempi e trasformazioni che le rendono molto versatili. A differenza del CSS, non siamo limitati alle sole curve di Bezier. +<<<<<<< HEAD Lo stesso vale per `draw`: possiamo animare qualsiasi cosa, non solamente le proprietà CSS. +======= +The same is true about `draw`: we can animate anything, not just CSS properties. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 diff --git a/7-animation/3-js-animation/text.view/index.html b/7-animation/3-js-animation/text.view/index.html index 001b0ae94..4947e4cd4 100644 --- a/7-animation/3-js-animation/text.view/index.html +++ b/7-animation/3-js-animation/text.view/index.html @@ -29,7 +29,7 @@ timing: bounce, draw: function(progress) { let result = (to - from) * progress + from; - textArea.value = text.substr(0, Math.ceil(result)) + textArea.value = text.slice(0, Math.ceil(result)) } }); } diff --git a/8-web-components/1-webcomponents-intro/web-components-twitter.svg b/8-web-components/1-webcomponents-intro/web-components-twitter.svg index 9d3b0b00b..8f59f789f 100644 --- a/8-web-components/1-webcomponents-intro/web-components-twitter.svg +++ b/8-web-components/1-webcomponents-intro/web-components-twitter.svg @@ -1 +1 @@ -1243567 \ No newline at end of file +1243567 \ No newline at end of file diff --git a/8-web-components/4-template-element/article.md b/8-web-components/4-template-element/article.md index caa163c0c..e42c71644 100644 --- a/8-web-components/4-template-element/article.md +++ b/8-web-components/4-template-element/article.md @@ -1,7 +1,11 @@ # Elemento Template +<<<<<<< HEAD L'elemento built-in `