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 2f567f17b..b0e893845 100644 --- a/1-js/01-getting-started/1-intro/article.md +++ b/1-js/01-getting-started/1-intro/article.md @@ -34,16 +34,26 @@ Os termos acima são bons para lembrar, pois são usados em artigos de desenvolv Os interpretadores são complicados. Mas o básico é fácil. +<<<<<<< HEAD 1. O interpretador (embutido se for um navegador) lê ("analisa") o script. 2. Depois converte ("compila") o script para a linguagem da máquina. 3. E então o código da máquina é executado, bem rápido. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b O interpretador aplica otimizações em cada etapa do processo. Ele ainda observa o script compilado enquanto ele roda, analisa os dados que passam por ele e aplica otimizações ao código da máquina com base nesse conhecimento. ``` ## O que o JavaScript no navegador pode fazer? +<<<<<<< HEAD JavaScript moderno é uma linguagem de programação "segura". Ele não fornece acesso de baixo nível à memória ou CPU, porque foi inicialmente criado para navegadores que não necessitam dele. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b As capacidades do JavaScript dependem muito do ambiente em que está sendo executado. Por exemplo, [Node.js]https://pt.wikipedia.org/wiki/Node.js) suporta funções que permitem ao JavaScript ler/gravar arquivos arbitrários, executar solicitações de rede, etc. @@ -59,7 +69,11 @@ Por exemplo, o JavaScript no navegador é capaz de: ## O que o JavaScript no navegador não pode fazer? +<<<<<<< HEAD As habilidades do JavaScript no navegador são limitadas por uma questão de segurança do usuário. O objetivo é evitar que uma página maléfica acesse informações privadas ou prejudique os dados do usuário. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Exemplos de tais restrições incluem: @@ -67,6 +81,7 @@ Exemplos de tais restrições incluem: Os navegadores modernos permitem que ele trabalhe com arquivos, mas o acesso é limitado e fornecido apenas se o usuário executar determinadas ações, como "dropping" de um arquivo em uma janela do navegador ou selecioná-lo por meio de uma tag ``. +<<<<<<< HEAD Existem maneiras de interagir com a câmera / microfone e outros dispositivos, mas eles exigem permissão explícita do usuário. Assim, uma página habilitada para JavaScript pode não habilmente habilitar uma câmera web, observar os arredores e enviar as informações para a [NSA](https://pt.wikipedia.org/wiki/Ag%C3%AAncia_de_Seguran%C3%A7a_Nacional). - Diferentes abas/janelas geralmente não se conhecem mutuamente. Às vezes sim, por exemplo, quando uma janela usa JavaScript para abrir a outra. Mas mesmo neste caso, JavaScript de uma página pode não acessar a outra se eles vierem de sites diferentes (de um domínio, protocolo ou porta diferente). @@ -78,6 +93,19 @@ Exemplos de tais restrições incluem: ![](limitations.svg) Esses limites não existem se o JavaScript for usado fora do navegador, por exemplo, em um servidor. Os navegadores modernos também permitem plugins / extensões que podem solicitar permissões estendidas. +======= + 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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ## O que torna o JavaScript único? @@ -92,7 +120,11 @@ JavaScript é a única tecnologia de navegador que combina estas três qualidade Isso é o que torna o JavaScript único. É por isso que é a ferramenta mais difundida para criar interfaces de navegador. +<<<<<<< HEAD Ao passo que planeja aprender uma nova tecnologia, é benéfico verificar suas perspectivas. Então, vamos seguir para as tendências modernas que o afetam, incluindo novas linguagens e habilidades de navegador. +======= +That said, JavaScript can be used to create servers, mobile applications, etc. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ## Linguagens "sobre" JavaScript @@ -100,12 +132,17 @@ A sintaxe do JavaScript não se adapta às necessidades de todos. Pessoas difere Isso é de se esperar, porque os projetos e requisitos são diferentes para todos. +<<<<<<< HEAD Então, recentemente uma infinidade de novas linguagens apareceu, que são *transpiladas* (convertidas) para JavaScript antes de rodarem no navegador. +======= +So, recently a plethora of new languages appeared, which are *transpiled* (converted) to JavaScript before they run in the browser. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Ferramentas modernas tornam a transpilação muito rápida e transparente, permitindo que os desenvolvedores codifiquem em outra linguagem e auto-convertendo-a "sob o capô". Exemplos de tais linguagens: +<<<<<<< HEAD - [CoffeeScript](http://coffeescript.org/) é um "açúcar sintático" para JavaScript. Ele introduz uma sintaxe mais curta, permitindo-nos escrever um código mais claro e preciso. Normalmente, Ruby devs gostam dele. - [TypeScript](http://www.typescriptlang.org/) está concentrado em adicionar "estritos tipos de dados" para simplificar o desenvolvimento e suporte de sistemas complexos. É desenvolvido pela Microsoft. - [Flow](http://flow.org/) também adiciona tipos de dados, mas de uma forma diferente. Desenvolvido pela Facebook. @@ -114,6 +151,16 @@ Exemplos de tais linguagens: - [Kotlin](https://kotlinlang.org/docs/js-overview.html) é uma linguagem de programação moderna, concisa e segura, que pode ser usada no navegador ou no Node. Há mais. Claro que, mesmo que usemos uma dessas linguagens transpiladas, também devemos saber JavaScript para entender o que estamos fazendo. +======= +- [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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ## Resumo 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 17592155d..d983213d7 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 @@ # Manuais e especificações +<<<<<<< HEAD Este livro é um *tutorial*. Ele tem como objetivo lhe ajudar a aprender gradualmente a linguagem. Mas uma vez familiarizado com o básico, irá precisar de outros recursos. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ## Especificação @@ -9,7 +13,11 @@ A [Especificação ECMA-262](https://www.ecma-international.org/publications/sta Mas, estando num formato mais formal, fica difícil de entender à primeira vista. Porém, se você precisa da mais confiável fonte de informações sobre detalhes da linguagem, está no lugar certo. Contudo, não é para o uso cotidiano. +<<<<<<< HEAD Uma nova versão dessa especificação é lançada todos os anos. Entre estes lançamentos, a sua última versão de esboço se encontra em . +======= +A new specification version is released every year. Between these releases, the latest specification draft is at . +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Para ler sobre as mais novas funcionalidades (*bleeding-edge features*), incluindo as que estão em fase de padronização (chamadas também de "estágio 3"), veja as suas propostas em . @@ -19,9 +27,15 @@ E mais, se você está desenvolvendo para browsers, há outras especificações - **MDN (Mozilla) JavaScript Reference** é um manual com exemplos e outras informações. É ótimo para um entendimento sobre funções da linguagem, métodos , etc. +<<<<<<< HEAD Pode ser encontrado em . Porém, às vezes é melhor fazer uma busca na internet. Apenas use "MDN [termo]" na busca, por exemplo: para procurar pela função `parseInt`. +======= + 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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ## Tabelas de compatibilidade @@ -29,9 +43,16 @@ JavaScript é uma linguagem em desenvolvimento, novas funcionalidades são adici Para verificar o suporte dessas funcionalidades entre interpretadores de JavaScript (*JavaScript engines*) para browsers ou para outras aplicações, veja em: +<<<<<<< HEAD - - mostra uma tabela de compatibilidade por funcionalidade, por exemplo, para verificar quais interpretadores suportam funções de criptografia moderna: . - - uma tabela com funcionalidades da linguagem e os interpretadores que as suportam ou não. Todos esses recursos são úteis no cotidiano do desenvolvedor, uma vez que eles contêm informações valiosas sobre os detalhes da linguagem, seu suporte, etc. +======= +- - 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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Por favor, lembre-se deles (ou desta página) quando precisar de informações específicas sobre alguma funcionalidade. 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 c31d05b03..a12846592 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 @@ Uma IDE carrega o projeto (que pode ter muitos arquivos), permite navegação en Se você ainda não tiver selecionado uma IDE, considere as seguintes opções: +<<<<<<< HEAD - [Visual Studio Code](https://code.visualstudio.com/) (plataforma cruzada, livre). - [WebStorm](https://www.jetbrains.com/pt-br/webstorm/) (plataforma cruzada, pago). +======= +- [Visual Studio Code](https://code.visualstudio.com/) (cross-platform, free). +- [WebStorm](https://www.jetbrains.com/webstorm/) (cross-platform, paid). +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Para Windows, há também "Visual Studio", que não deve ser confundido com "Visual Studio Code". "Visual Studio" é um editor pago e poderoso somente para Windows, bem adequado para a plataforma .NET . Uma versão gratuita é chamada [Visual Studio Community](https://visualstudio.microsoft.com/pt-br/vs/community/). @@ -29,12 +34,20 @@ A principal diferença entre um "editor leve" e uma "IDE", é que uma IDE trabal Na prática, os editores leves podem ter muitos plug-ins, incluindo analisadores de sintaxe no nível de diretório e preenchimentos automáticos, portanto não há uma limitação rígida entre um editor leve e uma IDE. +<<<<<<< HEAD As seguintes opções merecem sua atenção: - [Atom](https://atom.io/) (plataforma cruzada, livre). - [Sublime Text](http://www.sublimetext.com) (plataforma cruzada, shareware). - [Notepad++](https://notepad-plus-plus.org/) (Windows, livre). - [Vim](http://www.vim.org/) e [Emacs](https://www.gnu.org/software/emacs/) também são legais se você sabe como usá-los. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ## Não vamos discutir @@ -42,4 +55,13 @@ Os editores nas listas acima são aqueles que eu ou os meus amigos que eu consid Há outros grandes editores no nosso grande mundo. Por favor, escolha o que você mais gosta. +<<<<<<< HEAD A escolha de um editor, como qualquer outra ferramenta, é individual e depende de seus projetos, hábitos e preferências pessoais. +======= +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). +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b diff --git a/1-js/01-getting-started/4-devtools/article.md b/1-js/01-getting-started/4-devtools/article.md index b880718c5..1cf9356e4 100644 --- a/1-js/01-getting-started/4-devtools/article.md +++ b/1-js/01-getting-started/4-devtools/article.md @@ -22,7 +22,7 @@ As ferramentas de desenvolvedor serão abertas na aba Console por padrão. É parecido com isto: -![chrome](chrome.png) +![chrome](chrome.webp) O aspecto exato das ferramentas de desenvolvimento depende da sua versão do Chrome. Ele muda de vez em quando, mas deve ser semelhante. @@ -48,7 +48,11 @@ A interface deles é bem parecida. Uma vez que você saiba como usar uma dessas O Safari (navegador do Mac, não suportado pelo Windows/Linux) é um pouco especial aqui. Precisamos primeiro habilitar o "Develop menu". +<<<<<<< HEAD Abra Preferências e vá para o painel "Avançado". Há uma caixa de seleção na parte inferior: +======= +Open Settings and go to the "Advanced" pane. There's a checkbox at the bottom: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ![safari](safari.png) diff --git a/1-js/01-getting-started/4-devtools/chrome.png b/1-js/01-getting-started/4-devtools/chrome.png deleted file mode 100644 index 4cb3ea2f4..000000000 Binary files a/1-js/01-getting-started/4-devtools/chrome.png and /dev/null differ diff --git a/1-js/01-getting-started/4-devtools/chrome.webp b/1-js/01-getting-started/4-devtools/chrome.webp new file mode 100644 index 000000000..bdf067079 Binary files /dev/null and b/1-js/01-getting-started/4-devtools/chrome.webp differ diff --git a/1-js/01-getting-started/4-devtools/chrome@2.webp b/1-js/01-getting-started/4-devtools/chrome@2.webp new file mode 100644 index 000000000..2aeca5898 Binary files /dev/null and b/1-js/01-getting-started/4-devtools/chrome@2.webp differ diff --git a/1-js/01-getting-started/4-devtools/chrome@2x.png b/1-js/01-getting-started/4-devtools/chrome@2x.png deleted file mode 100644 index b87404a8f..000000000 Binary files a/1-js/01-getting-started/4-devtools/chrome@2x.png and /dev/null differ diff --git a/1-js/01-getting-started/4-devtools/safari.png b/1-js/01-getting-started/4-devtools/safari.png index 64c7a3f6c..4538827eb 100644 Binary files a/1-js/01-getting-started/4-devtools/safari.png and b/1-js/01-getting-started/4-devtools/safari.png differ diff --git a/1-js/01-getting-started/4-devtools/safari@2x.png b/1-js/01-getting-started/4-devtools/safari@2x.png index 27def4d09..1561b2bd9 100644 Binary files a/1-js/01-getting-started/4-devtools/safari@2x.png and b/1-js/01-getting-started/4-devtools/safari@2x.png differ 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 8c1ca833e..e53041e6b 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,24 @@ const birthday = '18.04.1982'; const age = someCode(birthday); ``` +<<<<<<< HEAD Aqui temos uma constante `birthday` e a `age` que é calculada apartir de `birthday` com a ajuda de algum código (não é fornecido por falta de tempo, e porque os detalhes não importam aqui). +======= +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`. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Seria correcto utilizar maiúsculas para `birthday`? Para `age`? Ou mesmo para ambos? ```js +<<<<<<< HEAD const BIRTHDAY = '18.04.1982'; // fazer maiúsculas? const AGE = someCode(BIRTHDAY); // fazer maiúsculas? -``` +======= +const BIRTHDAY = '18.04.1982'; // make birthday uppercase? +const AGE = someCode(BIRTHDAY); // make age uppercase? +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b +``` diff --git a/1-js/02-first-steps/04-variables/article.md b/1-js/02-first-steps/04-variables/article.md index 791a2d694..4938f4b49 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 = 'Olá'; ``` +<<<<<<< HEAD Algumas pessoas também definem múltiplas variáveis nesse estilo multilinha: +======= +Some people also define multiple variables in this multiline style: + +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js no-beautify let user = 'John', age = 25, @@ -87,22 +92,37 @@ Em scripts antigos, você também pode encontrar outra palavra-chave: `var` em v *!*var*/!* message = 'Olá'; ``` +<<<<<<< HEAD A palavra-chave `var` é quase a mesma que `let`. Ela também declara uma variável, mas de um modo um pouco diferente, "old-school". Existem diferenças sutis entre `let` e `var`, mas elas ainda não são importantes para nós. Nós as abordaremos em detalhes no capítulo . +======= +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 . +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```` ## Uma analogia da vida real Podemos facilmente compreender o conceito de uma "variável" se a imaginarmos como uma "caixa" para dados, com um adesivo de nome exclusivo. +<<<<<<< HEAD Por exemplo, a variável `mensagem` pode ser imaginada como uma caixa chamada `"message"`com o valor `"Olá"`!: +======= +For instance, the variable `message` can be imagined as a box labelled `"message"` with the value `"Hello!"` in it: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ![](variable.svg) Podemos pôr qualquer valor na caixa. +<<<<<<< HEAD Também podemos mudá-lo quantas vezes quisermos: +======= +We can also change it as many times as we want: + +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js run let message; @@ -148,12 +168,21 @@ let message = "Aquilo"; // SyntaxError: 'message' has already been declared (Err Assim, devemos declarar uma variável apenas uma vez e depois fazer referência a ela sem o `let`. ```` +<<<<<<< HEAD ```smart header="Linguagens funcionais" É interessante notar que existem linguagens de programação [funcionais](https://en.wikipedia.org/wiki/Functional_programming), como [Scala](http://www.scala-lang.org/) ou [Erlang](http://www.erlang.org/), que proíbem a modificação de valores de variáveis. +======= +```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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Em tais linguagens, uma vez que o valor é armazenado "na caixa", ele está lá para sempre. Se precisarmos de armazenar algo mais, a linguagem nos obriga a criar uma nova caixa (declarar uma nova variável). Não podemos reutilizar a antiga. +<<<<<<< HEAD Embora possa parecer um pouco estranho à primeira vista, estas linguagens são bastante capazes de um desenvolvimento sério. Mais do que isso, há áreas como cálculos paralelos onde essa limitação confere certos benefícios. Estudar alguma dessas linguagens (mesmo que você não esteja planejando usá-la em breve) é recomendado para ampliar a mente. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ``` ## Nomeação de variável [#variable-naming] @@ -191,19 +220,32 @@ let 1a; // não pode começar com um dígito let my-name; // hífens '-' não são permitidos no nome ``` +<<<<<<< HEAD ```smart header="Questões de caso" Variáveis chamadas `apple` e `AppLE` são duas variáveis diferentes. ``` ````smart header="Letras não-Latin são permitidas, mas não são recomendadas" É possível usar qualquer idioma, incluindo letras cirílicas ou até hieróglifos, como estes: +======= +```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: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js let имя = '...'; let 我 = '...'; ``` +<<<<<<< HEAD Tecnicamente, não há erro aqui. Tais nomes são permitidos, mas há uma tradição internacional de usar o inglês em nomes de variáveis. Mesmo que estejamos escrevendo um pequeno script, ele pode ter uma longa vida pela frente. Pessoas de outros países podem precisar de o ler em algum momento. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```` ````warn header="Nomes reservados" @@ -258,12 +300,20 @@ const myBirthday = '18.04.1982'; myBirthday = '01.01.2001'; // erro, não é possível reatribuir a constante! ``` +<<<<<<< HEAD Quando um programador está certo de que uma variável nunca mudará, ele pode declará-la com `const` para garantir e comunicar claramente esse fato a todos. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ### Constantes maiúsculas +<<<<<<< HEAD Há uma prática generalizada de usar constantes como aliases para valores difíceis de lembrar que são conhecidos antes da execução. +======= +There is a widespread practice to use constants as aliases for difficult-to-remember values that are known before execution. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Tais constantes são nomeadas usando letras maiúsculas e sublinhados. @@ -288,16 +338,29 @@ Benefícios: Quando devemos usar maiúsculas para uma constante e quando devemos nomeá-la normalmente? Vamos deixar isso bem claro. +<<<<<<< HEAD Ser uma "constante" significa apenas que o valor de uma variável nunca muda. Mas há constantes que são conhecidas antes da execução (como um valor hexadecimal para vermelho) e há constantes que são *calculadas* em tempo de execução, durante a execução, mas não mudam após sua atribuição inicial. Como por exemplo: +======= +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: + +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js const pageLoadTime = /* tempo necessário para carregar uma página web */; ``` +<<<<<<< HEAD O valor de `pageLoadTime` não é conhecido antes do carregamento da página, portanto é nomeado normalmente. Mas ainda é uma constante porque não muda após a atribuição. Em outras palavras, constantes com nomes maiúsculos são usadas apenas como pseudônimos para valores de "codificação rígida". +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ## Nomeie as coisas como devem ser @@ -305,18 +368,31 @@ Falando em variáveis, há mais uma coisa extremamente importante. O nome de uma variável deveria ter um significado claro e óbvio, descrevendo os dados que ela armazena. +<<<<<<< HEAD A nomenclatura variável é uma das habilidades mais importantes e complexas em programação. Uma rápida olhada em nomes de variáveis pode revelar que código foi escrito por um iniciante versus um desenvolvedor experiente. Em um projeto real, a maior parte do tempo é gasto modificando e estendendo uma base de código existente ao invés de escrever algo completamente separado do zero. Quando voltamos a algum código depois de fazer outra coisa por um tempo, é muito mais fácil encontrar informação se for bem rotulada. Ou, em outras palavras, quando as variáveis têm bons nomes. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Por favor, gaste tempo pensando sobre o nome certo para uma variável antes de declará-lo. Fazê-lo irá recompensá-lo generosamente. Algumas regras boas para seguir são: +<<<<<<< HEAD - Use nomes legíveis por humanos como `userName` ou `shoppingCart`. - Fique longe de abreviações ou nomes curtos como `a`, `b`, `c`, a menos que você realmente saiba o que está fazendo. - Faça nomes maximamente descritivos e concisos. Exemplos de nomes ruins são `data` e `value`. Tais nomes não dizem nada. Só é possível usá-los se o contexto do código tornar excepcionalmente óbvio quais dados ou valores a variável está referenciando. - Concorde em termos dentro da sua equipa e na sua própria mente. Se um visitante do site é chamado de "user", então devemos nomear variáveis relacionadas `currentUser` ou `newUser` em vez de `currentVisitor` ou `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`. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Parece simples? Na verdade é, mas criar nomes de variáveis descritivas e concisas na prática não é. Vá em frente. diff --git a/1-js/02-first-steps/05-types/article.md b/1-js/02-first-steps/05-types/article.md index f475e66ea..f4f83244b 100644 --- a/1-js/02-first-steps/05-types/article.md +++ b/1-js/02-first-steps/05-types/article.md @@ -68,9 +68,26 @@ Veremos mais sobre como trabalhar com números no capítulo . ## BigInt [#bigint-type] +<<<<<<< HEAD Em JavaScript, o tipo "number" não pode representar com segurança valores inteiros maiores que (253-1) (que é `9007199254740991`) ou menores que -( 253-1) para negativos. Para ser realmente preciso, o tipo "number" pode armazenar números inteiros maiores (até 1.7976931348623157 * 10308), mas fora do intervalo de números inteiros seguros ±(2 53-1) haverá um erro de precisão, porque nem todos os dígitos cabem no armazenamento fixo de 64 bits. Portanto, um valor “aproximado” pode ser armazenado. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Por exemplo, estes dois números (logo acima da faixa segura) são iguais: @@ -94,12 +111,15 @@ const bigInt = 1234567890123456789012345678901234567890n; Como os números `BigInt` raramente são necessários, nós não os cobrimos aqui, mas dedicamos-lhes um capítulo separado . Leia-o quando precisar de números tão grandes. +<<<<<<< HEAD ```smart header="Problemas de compatibilidade" No momento, o `BigInt` é suportado no Firefox/Chrome/Edge/Safari, mas não no IE. ``` Você pode verificar a [tabela de compatibilidade do *MDN* sobre BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#browser_compatibility) para saber quais versões de um navegador são suportadas. +======= +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ## String Uma string em JavaScript deve estar entre aspas. @@ -223,7 +243,11 @@ O tipo `symbol` é usado para criar identificadores únicos para objetos. Nós o ## The typeof operator [#type-typeof] +<<<<<<< HEAD O operador `typeof` retorna o tipo do argumento. É útil quando queremos processar valores de diferentes tipos ou apenas queremos fazer uma verificação rápida. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b A chamada para `typeof x` retorna uma string com o nome do tipo: @@ -273,6 +297,7 @@ Algumas pessoas preferem `typeof(x)`, embora a sintaxe `typeof x` seja muito mai Existem 8 tipos básicos em JavaScript. +<<<<<<< HEAD - `number` para números de qualquer tipo: inteiro ou ponto flutuante; inteiros estão limitados a ±(253-1). - `bigint` é para números inteiros de comprimento arbitrário. - `string` para cadeias-de-caracteres. Uma *string* pode ter zero ou mais caracteres, não há nenhum tipo de caractere único separado. @@ -281,6 +306,18 @@ Existem 8 tipos básicos em JavaScript. - `undefined` para valores não atribuídos -- um tipo autônomo que tem um único valor `undefined`. - `object` para estruturas de dados mais complexas. - `symbol` para identificadores exclusivos. +======= +- 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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b O operador `typeof` nos permite ver que tipo está armazenado em uma variável. 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 88f14e8ac..12d46b8fc 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,13 @@ Por exemplo, `alert` converte automaticamente qualquer valor para string antes d Também existem casos em que precisamos explicitamente de converter um valor para o tipo que precisamos. +<<<<<<< HEAD ```smart header="Não vamos falar de objetos" Nesse capítulo, não vamos falar sobre objetos. Por agora, vamos abordar apenas os tipos primitivos. +======= +```smart header="Not talking about objects yet" +In this chapter, we won't cover objects. For now, we'll just be talking about primitives. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Mais tarde, após abordarmos objetos no capítulo , veremos como objetos se comportam em conversões de tipo. ``` @@ -36,7 +41,13 @@ Conversões para string são as mais fáceis. `false` se torna `"false"`, `null` As conversões numéricas acontecem automaticamente em funções e expressões matemáticas. +<<<<<<< HEAD Por exemplo, quando `/` é usado com valores que não são números: +======= +Numeric conversion in mathematical functions and expressions happens automatically. + +For example, when division `/` is applied to non-numbers: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js run alert( "6" / "2" ); // 3, strings viram números @@ -69,8 +80,13 @@ Regras de conversões numéricas: |-------|-------------| |`undefined`|`NaN`| |`null`|`0`| +<<<<<<< HEAD |true e false| `1` e `0` | | `string` | Espaços em branco do início e do fim são removidos. Se a string que sobrar for vazia, o resultado é `0`. Senão, o número é "lido" a partir da string. Um erro nos dá `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`. | +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Exemplos: @@ -129,8 +145,13 @@ A conversão segue as seguintes regras: |-------|-------------| |`undefined`|`NaN`| |`null`|`0`| +<<<<<<< HEAD |true / false| `1 / 0` | | `string` | A string é lida "como ela é", espaços em branco do início e do fim são ignorados. Uma string vazia, vira `0`. Um erro nos dá `NaN`| +======= +|true / false | `1 / 0` | +| `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`. | +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b **`Conversões Booleanas`** -- Ocorrem em operações lógicas. Podem ser feitas com `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 114984580..7a1f7903b 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. A adição de uma string `"" + 1` converte `1` para uma string: `"" + 1 = "1"`, e quando nós temos `"1" + 0`, a mesma regra é aplicada. 2. A subtração `-` (como a maioria das operações matemáticas) apenas funciona com números, e converte uma string vazia `""` para `0`. 3. A adição a uma string anexa o número `5` à string. @@ -23,3 +24,12 @@ undefined + 1 = NaN // (6) 5. `null` se torna `0` após a conversão numérica. 6. `undefined` se torna `NaN` após a conversão numérica. 7. Caracteres de espaço, são aparados do início e final de uma string quando esta é convertida em um número. Aqui a string inteira consiste em caracteres de espaço, tais como `\t`, `\n` e um espaço "regular" entre eles. Então, similarmente à string vazia, isto se torna `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`. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b diff --git a/1-js/02-first-steps/08-operators/article.md b/1-js/02-first-steps/08-operators/article.md index 4c5e9116b..d24f14d75 100644 --- a/1-js/02-first-steps/08-operators/article.md +++ b/1-js/02-first-steps/08-operators/article.md @@ -50,8 +50,14 @@ O resultado de `a % b` é o [resto](https://pt.wikipedia.org/wiki/Resto_da_divis Por exemplo: ```js run +<<<<<<< HEAD alert( 5 % 2 ); // 1, o resto de 5 dividido por 2 alert( 8 % 3 ); // 2, o resto de 8 dividido por 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 +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ``` ### Exponenciação ** @@ -68,7 +74,11 @@ alert( 2 ** 3 ); // 2³ = 8 alert( 2 ** 4 ); // 2⁴ = 16 ``` +<<<<<<< HEAD Assim como na matemática, o operador de exponenciação também é definido para números não-inteiros. +======= +Just like in maths, the exponentiation operator is defined for non-integer numbers as well. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Por exemplo, a raiz quadrada é uma exponenciação por ½: @@ -80,7 +90,11 @@ alert( 8 ** (1/3) ); // 2 (a potência de 1/3 é o mesmo que a raiz cúbica) ## Concatenação de strings com + binário +<<<<<<< HEAD Vamos conhecer os recursos dos operadores JavaScript que estão para além da aritmética escolar. +======= +Let's meet the features of JavaScript operators that are beyond school arithmetics. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Normalmente o operador mais `+` soma números. @@ -194,6 +208,7 @@ Aqui está um extrato da [tabela de precedência](https://developer.mozilla.org/ | Precedência | Nome | Sinal | |------------|------|------| | ... | ... | ... | +<<<<<<< HEAD | 15 | positivo unário | `+` | | 15 | negativo unário | `-` | | 14 | exponenciação | `**` | @@ -201,11 +216,24 @@ Aqui está um extrato da [tabela de precedência](https://developer.mozilla.org/ | 13 | divisão | `/` | | 12 | adição | `+` | | 12 | subtração | `-` | +======= +| 14 | unary plus | `+` | +| 14 | unary negation | `-` | +| 13 | exponentiation | `**` | +| 12 | multiplication | `*` | +| 12 | division | `/` | +| 11 | addition | `+` | +| 11 | subtraction | `-` | +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b | ... | ... | ... | | 2 | atribuição | `=` | | ... | ... | ... | +<<<<<<< HEAD Como podemos ver, o "positivo unário" tem uma prioridade de `15` que é maior que a de `12` da "adição" (positivo binário). É por este motivo que na expressão `"+apples + +oranges"`, positivos unários operam antes da adição. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ## Atribuição @@ -303,7 +331,11 @@ Tais operadores têm a mesma precedência que uma atribuição normal, de modo q ```js run let n = 2; +<<<<<<< HEAD n *= 3 + 5; // parte à direita avaliada primeiro, o mesmo que n *= 8 +======= +n *= 3 + 5; // right part evaluated first, same as n *= 8 +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b alert( n ); // 16 ``` @@ -437,7 +469,11 @@ A lista de operadores: - RIGHT SHIFT ( `>>` ) - ZERO-FILL RIGHT SHIFT ( `>>>` ) +<<<<<<< HEAD Estes operadores são muito raramente usados, e acontece quando nós precisamos mexer com números no nível mais baixo (bit a bit). Nós não precisaremos destes operadores tão cedo, já que desenvolvimento web faz pouco uso deles, mas em algumas áreas específicas, como em criptografia, eles são úteis. Você pode ler o capítulo [Operadores bit a bit](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Guide/Expressions_and_Operators#operadores_bit_a_bit) na MDN quando surgir a necessidade. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ## Vírgula diff --git a/1-js/02-first-steps/10-ifelse/article.md b/1-js/02-first-steps/10-ifelse/article.md index e4d5c8076..c576d9395 100644 --- a/1-js/02-first-steps/10-ifelse/article.md +++ b/1-js/02-first-steps/10-ifelse/article.md @@ -68,9 +68,13 @@ if (cond) { ## A cláusula "else" +<<<<<<< HEAD A instrução `if` pode conter um bloco opcional "else" (senão). Ele é executado quando a condição é falsa. Por exemplo: +======= +The `if` statement may contain an optional `else` block. It executes when the condition is falsy. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js run let year = prompt('Em que ano foi publicada a especificação ECMAScript-2015?', ''); @@ -183,10 +187,17 @@ alert( message ); Pode ser difícil no início entender o que está acontecendo. Mas depois de um olhar mais atento, percebemos que é apenas uma sequência comum de testes: +<<<<<<< HEAD 1. O primeiro ponto de interrogação verifica se `age < 3`. 2. Se for verdadeiro -- retorna `'Oi, bebê!'`. Caso contrário, continua para a expressão após os dois pontos ":", verificando `age < 18`. 3. Se for verdade -- retorna `'Olá!'`. Caso contrário, continua para a expressão após os próximos dois pontos ":", verificando `age < 100`. 4. Se for verdade -- retorna `'Saudações!'`. Caso contrário, continua com a expressão após os últimos dois-pontos ":", retornando `'Que idade incomum!'`. +======= +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!'`. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Veja como isso fica usando `if..else`: 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 f9733a0fe..ad751dc14 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 @@ O operador de coalescência nula é escrito usando dois sinais de interrogação `??`. +<<<<<<< HEAD Como ele trata `null` e `undefined` da mesma forma, nós iremos usar um termo especial aqui, neste artigo. Diremos que uma expressão está definida quando não é `null` nem `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`. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b O resultado de `a ?? b` é: @@ -23,14 +27,24 @@ result = a !== null && a !== undefined ? a : b; Agora, deveria estar completamente claro o que `??` faz. Vamos ver onde ele é útil. +<<<<<<< HEAD O caso de uso comum para `??` é obter um valor padrão para uma variável potencialmente indefinida. Por exemplo, aqui exibimos `Anônimo` se `user` não for definido: +======= +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`: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js run let user; +<<<<<<< HEAD alert(user ?? "Anônimo"); // Anônimo ("user" não definido) +======= +alert(user ?? "Anonymous"); // Anonymous (user is undefined) +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ``` Aqui está o exemplo com um nome atribuído a `user`: @@ -38,14 +52,24 @@ Aqui está o exemplo com um nome atribuído a `user`: ```js run let user = "João"; +<<<<<<< HEAD alert(user ?? "Anônimo"); // João ("user" está definido) +======= +alert(user ?? "Anonymous"); // John (user is not null/undefined) +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ``` Podemos também usar uma sequência de `??` para selecionar o primeiro valor em uma lista que não seja `null/undefined`. +<<<<<<< HEAD Digamos que temos dados de um usuário nas variáveis `nome`, `sobrenome` ou `apelido`. Todos eles podem ser indefinidos, se o usuário optar por não entrar com um valor. Gostaríamos de exibir o nome do usuário usando uma dessas variáveis, ou exibir "Anônimo" se todas elas forem indefinidas. +======= +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`. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Para isso usaremos o operador `??`: @@ -77,7 +101,11 @@ alert(firstName || lastName || nickName || "Anônimo"); // Supercoder */!* ``` +<<<<<<< HEAD Historicamente, o operador OU `||` foi o primeiro a existir. Ele existe desde a criação do JavaScript, e vem sendo utilizado para este propósito desde então. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Por outro lado, o operador de coalescência nula `??` foi adicionado ao JavaScript recentemente, e a razão para isso foi o descontentamento com `||`. @@ -108,11 +136,19 @@ Na prática, a altura igual a zero é um valor válido que não deve ser substit ## Precedência +<<<<<<< HEAD A precedência do operador `??` é a mesma que a de `||`. Ambos são iguais a '4' na [tabela MDN](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table). +======= +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). +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Isto significa que, tal como `||`, o operador de coalescência nula `??` é avaliado antes de `=` e `?`, mas após a maioria dos outros operadores, como `+` e `*`. +<<<<<<< HEAD Então, se quiser selecionar um valor com `??` em uma expressão com outros operadores, considere o uso de parênteses: +======= +So we may need to add parentheses in expressions like this: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js run let height = null; @@ -130,8 +166,13 @@ Caso contrário, se omitirmos os parênteses, como `*` tem maior precedência qu // sem parênteses let area = height ?? 100 * width ?? 50; +<<<<<<< HEAD // ...funciona desta forma (provavelmente não como gostaríamos): let area = height ?? 100 * width ?? 50; +======= +// ...works this way (not what we want): +let area = height ?? (100 * width) ?? 50; +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ``` ### Usando ?? com && ou || diff --git a/1-js/02-first-steps/14-switch/article.md b/1-js/02-first-steps/14-switch/article.md index a661d7d0a..7200c3ed7 100644 --- a/1-js/02-first-steps/14-switch/article.md +++ b/1-js/02-first-steps/14-switch/article.md @@ -139,7 +139,11 @@ switch (a) { Agora ambos `3` e `5` mostram a mesma mensagem. +<<<<<<< HEAD A habilidade para "agrupar" cases é um efeito secundário de como o `switch/case` funciona sem `break`. Aqui a execução do `case 3` começa pela linha `(*)` e prossegue pelo `case 5`, por não existir `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`. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ## O tipo de dados importa 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 b7c045d0b..7ba3ca286 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,3 +1,9 @@ +<<<<<<< HEAD Nenhuma diferença! -Em ambos os casos, `return confirm('Seus pais permitiram?')` é executado exatamente quando a condição `if` é falsa. \ No newline at end of file +Em ambos os casos, `return confirm('Seus pais permitiram?')` é executado exatamente quando a condição `if` é falsa. +======= +No difference! + +In both cases, `return confirm('Did parents allow you?')` executes exactly when the `if` condition is falsy. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b 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 461d4978a..8b90d0cdb 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,11 @@ A palavra-chave `function` vem primeiro, depois vem o *nome da função*, e uma ```js function name(parameter1, parameter2, ... parameterN) { +<<<<<<< HEAD ...corpo... +======= + // body +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b } ``` @@ -175,8 +179,13 @@ Quando um valor é passado como um parâmetro de função, ele também é chamad Em outras palavras, para colocar esses termos em ordem: +<<<<<<< HEAD - Um parâmetro é a variável listada entre parênteses na declaração da função (é um termo de tempo de declaração) - Um argumento é o valor passado para a função quando ela é chamada (é um termo de tempo de chamada). +======= +- 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). +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Declaramos funções listando seus parâmetros e as chamamos de passagem de argumentos. @@ -205,7 +214,17 @@ function showMessage(from, *!*text = "nenhum texto fornecido"*/!*) { showMessage("Ann"); // Ann: nenhum texto fornecido ``` +<<<<<<< HEAD Agora se o parâmetro `text` não for passado, ele receberá o valor `"nenhum texto fornecido"` +======= +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 +``` +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Aqui `"nenhum texto fornecido"` é uma string, mas pode ser uma expressão mais complexa, que só é avaliada e atribuída se o parâmetro estiver ausente. Então, isso também é possível: @@ -224,9 +243,47 @@ No exemplo acima, `anotherFunction()` não é chamado se o parâmetro `text` for Por outro lado, é chamado independentemente toda vez que `text` está faltando. ``` +<<<<<<< HEAD ### Parâmetros padrão alternativos Às vezes, faz sentido atribuir valores padrão para parâmetros não na declaração da função, mas em um estágio posterior. +======= +````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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Podemos verificar se o parâmetro é passado durante a execução da função, comparando-o com `undefined`: @@ -421,7 +478,11 @@ Esses exemplos assumem significados comuns de prefixos. Você e sua equipe são ```smart header="Nomes de função ultracurtos" As funções que são usadas *com muita frequência* às vezes têm nomes ultracurtos. +<<<<<<< HEAD Por exemplo, o framework [jQuery](http://jquery.com) define uma função com `$`. A biblioteca [Lodash](http://lodash.com/) tem sua função central chamada `_`. +======= +For example, the [jQuery](https://jquery.com/) framework defines a function with `$`. The [Lodash](https://lodash.com/) library has its core function named `_`. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Estas são exceções. Geralmente, os nomes das funções devem ser concisos e descritivos. ``` @@ -489,7 +550,11 @@ function name(parameters, delimited, by, comma) { Para tornar o código limpo e fácil de entender, é recomendável usar principalmente variáveis ​​e parâmetros locais na função, não variáveis ​​externas. +<<<<<<< HEAD É sempre mais fácil entender uma função que obtém parâmetros, trabalha com eles e retorna um resultado do que uma função que não obtém parâmetros, mas modifica variáveis ​​externas como efeito colateral. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Nomenclatura da função: 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 b952d5943..c6dd891bd 100644 --- a/1-js/02-first-steps/16-function-expressions/article.md +++ b/1-js/02-first-steps/16-function-expressions/article.md @@ -82,7 +82,7 @@ let sayHi = function() { // (1) create alert( "Hello" ); }; -let func = sayHi; +let func = sayHi; //(2) // ... ``` 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 3728b4898..2b209c4cd 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 @@ -48,7 +48,11 @@ Como pode ver, `(a, b) => a + b` significa uma função que aceita dois argument alert( double(3) ); // 6 ``` +<<<<<<< HEAD - Se não houver argumentos, os parênteses irão estar vazios (mas devem estar presentes): +======= +- If there are no arguments, parentheses are empty, but they must be present: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js run let sayHi = () => alert("Olá!"); @@ -64,8 +68,13 @@ Por exemplo, para criar dinamicamente uma função: let age = prompt("Que idade tem?", 18); let welcome = (age < 18) ? +<<<<<<< HEAD () => alert('Olá') : () => alert("Saudações!"); +======= + () => alert('Hello!') : + () => alert("Greetings!"); +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b welcome(); ``` @@ -76,9 +85,15 @@ Elas são muito convenientes para ações simples numa única-linha, quando esta ## Funções seta de múltiplas linhas +<<<<<<< HEAD Os exemplos acima tomaram os argumentos à esquerda de `=>` e avaliaram a expressão à direita com eles. Por vezes, precisamos de algo um pouco mais complexo, como de múltiplas expressões ou instruções. Isso também é possível, mas devemos colocar elas dentro de chavetas. Depois, usamos um `return` normal com elas. +======= +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). +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Desta forma: @@ -105,7 +120,14 @@ Por ora, podemos já usar funções seta para ações numa única-linha e *callb ## Resumo +<<<<<<< HEAD Funções seta são práticas para ações numa única-linha. Elas vêm em dois sabores: 1. Sem chavetas: `(...args) => expression` -- o lado direito é uma expressão: a função a avalia e retorna o resultado. 2. Com chavetas: `(...args) => { body }` -- chavetas nos permitem escrever múltiplas instruções dentro da função, mas precisamos de um explícito `return` para retornar alguma coisa. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b 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 016214e3b..0ba505066 100644 --- a/1-js/02-first-steps/18-javascript-specials/article.md +++ b/1-js/02-first-steps/18-javascript-specials/article.md @@ -103,13 +103,13 @@ More in: and . We're using a browser as a working environment, so basic UI functions will be: -[`prompt(question, [default])`](mdn:api/Window/prompt) +[`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)`](mdn:api/Window/confirm) +[`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)`](mdn:api/Window/alert) +[`alert(message)`](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert) : Output a `message`. All these functions are *modal*, they pause the code execution and prevent the visitor from interacting with the page until they answer. @@ -144,7 +144,11 @@ Assignments : There is a simple assignment: `a = b` and combined ones like `a *= 2`. Bitwise +<<<<<<< HEAD : Bitwise operators work with 32-bit integers at the lowest, bit-level: see the [docs](mdn:/JavaScript/Guide/Expressions_and_Operators#bitwise_operators) when they are needed. +======= +: 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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Conditional : The only operator with three parameters: `cond ? resultA : resultB`. If `cond` is truthy, returns `resultA`, otherwise `resultB`. 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 c2647370e..02f5471d6 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 pressionarmos `key:Esc`, um terminal (*Console*) se abrirá abaixo. Assim per Depois de uma instrução ser executada, o resultado será mostrado logo a seguir. +<<<<<<< HEAD Por exemplo, a instrução `1+2` resultará em `3`, enquanto a chamada de função `hello("debugger")` não retornará nada, assim tendo como resultado `undefined`: +======= +For example, here `1+2` results in `3`, while the function call `hello("debugger")` returns nothing, so the result is `undefined`: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ![](chrome-sources-console.svg) @@ -62,13 +66,22 @@ Uma lista de *breakpoints* sempre estará disponível no painel à direita. Muit - Remover o breakpoint, clicando com o botão direito do mouse e selecionando *Remove*. - ...E assim por diante. +<<<<<<< HEAD ```smart header="*Breakpoints* condicionais" *Clicar com o botão direito do mouse* sobre um número de linha permite a criação de um *breakpoint condicional* o qual será ativado apenas quando a expressão inserida for verdadeira. +======= +```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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b É prático quando precisamos de suspender a execução apenas para valores determinados de certa variável ou para parâmetros específicos numa função. ``` +<<<<<<< HEAD ## O comando *debugger* +======= +## The command "debugger" +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Podemos também suspender o código utilizando o comando `debugger`, desta forma: @@ -84,9 +97,13 @@ function hello(name) { } ``` +<<<<<<< HEAD Este comando só irá funcionar quando a interface de ferramentas de desenvolvedor do navegador estiver aberta, caso contrário, será ignorado. ## Pause e dê uma olhada +======= +Such command works only when the development tools are open, otherwise the browser ignores it. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b No nosso exemplo, a função `hello()` é chamada durante o carregamento da página, assim a forma mais fácil para ativar o *debugger* (depois de termos colocado os *breakpoints*) seria recarregar a página. Desta forma, vamos pressionar `key:F5` (Windows, Linux) ou `key:Cmd+R` (Mac). @@ -98,7 +115,11 @@ Por favor, abra as secções de *dropdown* informacionais à direita (apontadas 1. **`Watch` -- mostra valores atuais das expressões.** +<<<<<<< HEAD É possível clicar no `+` e inserir uma expressão. O *debugger* mostrará o valor da expressão e continuará recalculando-a ao longo do processo de execução. +======= + You can click the plus `+` and input an expression. The debugger will show its value, automatically recalculating it in the process of execution. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b 2. **`Call Stack` -- mostra a sequência de chamadas de funções aninhadas.** @@ -133,12 +154,21 @@ Existem botões para isso no topo do painel direito. Vamos interagir com eles. Continuando a clicar nele, passará por todas as instruções do programa, uma por uma. +<<<<<<< HEAD -- "Step over": execute o próximo comando, *mas não vá para dentro de uma função*, atalho `key:F10`. : Similar ao comando "Step" anterior mas com um comportamento diferente se a próxima instrução for uma chamada de função. Isto é: não uma incorporada (*built-in*), como `alert`, mas uma função nossa. O comando "Step", vai para dentro dessa função e suspende a execução na sua primeira linha, ao contrário de "Step over" que executa essa chamada de função aninhada de forma invisível para nós, pulando todo seu funcionamento interno. É feita uma pausa na execução imediatamente depois dessa função. +======= + -- "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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b É util quando não se está interessado em ver o que acontece dentro da chamada de uma função. @@ -153,8 +183,13 @@ Existem botões para isso no topo do painel direito. Vamos interagir com eles. -- ativar/desativar todos os *breakpoints*. : Esse botão não move a execução. Simplesmente ativa/desativa *breakpoints* em conjunto. +<<<<<<< HEAD -- ativar/desativar a pausa automática em caso de erro. : Quando ativo e as ferramentas do desenvolvedor abertas, um erro no código automáticamente suspende a execução do código. Assim permitindo a análise de variáveis para entender o que ocorreu de errado. Desta forma, se o código falhar por um erro, é possível abrir o *debugger*, ativar esta opção e recarregar a página afim de se observar onde e em que contexto a falha ocorreu. +======= + -- 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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```smart header="Continue até aqui" Ao clicar com o botão direito do mouse sobre uma linha de código, abre-se o menu de contexto com uma ótima opção chamada "Continue até aqui" (*Continue to here*). @@ -186,7 +221,11 @@ Como podemos ver, existem três formas principais para pausar a execução de um 2. As instruções `debugger`. 3. Um erro (se as ferramentas do desenvolvedor [*dev tools*] estiverem abertas, e o botão estiver "ativo"). +<<<<<<< HEAD Enquanto suspenso, podemos depurar erros - examinar variáveis e rastear o código para ver que parte da execução ocorre com erros. +======= +When paused, we can debug: examine variables and trace the code to see where the execution goes wrong. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Existem muitas outras opções nas ferramentas do desenvolvedor além das já cobertas ao longo desta leitura. O manual completo está em . 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 a60cb3da1..115208abf 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 @@ Tais comentários, nos permitem compreender o propósito da função e a usar de A propósito, muitos editores, como o [WebStorm](https://www.jetbrains.com/webstorm/, podem também os perceber e os usar para fornecer completação automática de palavras (*autocomplete*), e algumas verificações de código (*code-checking*) automáticas. +<<<<<<< HEAD Também, existem ferramentas como o [JSDoc 3](https://github.com/jsdoc3/jsdoc), que podem gerar documentação HTML a partir de comentários. Pode ler mais informação sobre o JSDoc em . +======= +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 . +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Porque é a tarefa solucionada dessa forma? : O que está escrito é importante. Mas, o que *não* está escrito pode ser ainda mais importante, para se compreender o que se passa. Porque é a tarefa solucionada exatamente dessa forma? O código não dá resposta alguma. 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 e5a3ab6b4..a1a4d8507 100644 --- a/1-js/03-code-quality/05-testing-mocha/article.md +++ b/1-js/03-code-quality/05-testing-mocha/article.md @@ -50,8 +50,13 @@ describe("pow", function() { Uma *spec* tem três principais blocos construtores, como pode ver acima: +<<<<<<< HEAD `describe("título", function() { ... })` : Que funcionalidade estamos a descrever. No nosso caso, estamos a descrever a função `pow`. São usados para agrupar "executores" ("*workers*") -- os blocos `it`. +======= +`describe("title", function() { ... })` +: What functionality we're describing? In our case we're describing the function `pow`. Used to group "workers" -- the `it` blocks. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b `it("descrição do caso exemplo", function() { ... })` : No título de `it` nós, *de uma forma claramente legível*, descrevemos o caso exemplo em questão, e no segundo argumento está uma função que o testa. @@ -59,8 +64,46 @@ Uma *spec* tem três principais blocos construtores, como pode ver acima: `assert.equal(valor1, valor2)` : O código dentro do bloco `it`, se a implementação estiver correta, não deverá mostrar erros. +<<<<<<< HEAD ```text Funções `assert.*` são usadas para verificar se `pow` funciona como esperado. Aqui mesmo, estamos a usar uma delas -- `assert.equal`, que compara argumentos e dá como resultado um erro se eles não forem iguais. Aqui, ela verifica se o resultado de `pow(2, 3)` é `8`. Existem outros tipos de comparações e verificações, que adicionaremos mais adiante. +======= + Functions `assert.*` are used to check whether `pow` works as expected. Right here we're using one of them -- `assert.equal`, it compares arguments and yields an error if they are not equal. Here it checks that the result of `pow(2, 3)` equals `8`. There are other types of comparisons and checks, that we'll add later. + +The specification can be executed, and it will run the test specified in `it` block. We'll see that later. + +## The development flow + +The flow of development usually looks like this: + +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. + +So, the development is *iterative*. We write the spec, implement it, make sure tests pass, then write more tests, make sure they work etc. At the end we have both a working implementation and tests for it. + +Let's see this development flow in our practical case. + +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). + +## The spec in action + +Here in the tutorial we'll be using the following JavaScript libraries for tests: + +- [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. + +These libraries are suitable for both in-browser and server-side testing. Here we'll consider the browser variant. + +The full HTML page with these frameworks and `pow` spec: + +```html src="index.html" +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ``` A especificação pode ser executada, e irá correr o teste especificado no bloco `it`. O que veremos mais adiante. @@ -342,6 +385,7 @@ Os testes agora adicionados falham, porque a nossa implementação não possui s ```smart header="Outras asserções" +<<<<<<< HEAD Por favor, observe a asserção `assert.isNaN`: ela verifica por `NaN`. Existem ainda outras asserções em [Chai](http://chaijs.com), como por exemplo: @@ -352,6 +396,16 @@ Existem ainda outras asserções em [Chai](http://chaijs.com), como por exemplo: - `assert.isTrue(valor)` -- verifica se `valor === true` - `assert.isFalse(valor)` -- verifica se `valor === false` - ...a lista completa está em [docs](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/) +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ``` Assim, nós deveríamos adicionar algumas linhas 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 50e841cfc..243c66e93 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 A linguagem JavaScript evolui constantemente. Novas propostas para a linguagem aparecem regularmente, elas são analisadas e, se consideradas válidas, são anexadas à lista em e depois progridem para a [especificação (en)](https://www.ecma-international.org/publications-and-standards/standards/ecma-262/). +======= +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/). +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Grupos por detrás dos interpretadores de JavaScript têm as suas próprias ideias sobre o que implementar primeiro. Eles podem decidir implementar propostas que estão em esboço e adiar coisas que já estão na spec, por serem menos interessantes ou apenas mais difíceis de fazer. +<<<<<<< HEAD Assim, é muito comum que um interpretador implemente apenas parte de um padrão. Uma boa página para se ver o estágio atual de suporte de funcionalidades da linguagem é (é extensa, nós ainda temos muito que estudar). +======= +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). +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Como programadores, nós gostaríamos de usar as funcionalidades mais recentes. Quantas mais forem as coisas boas - melhor! @@ -40,9 +50,15 @@ Agora, o código reescrito está adequado a interpretadores de JavaScript antigo Geralmente, um desenvolvedor executa o transpiler na sua própria máquina, e depois coloca o código transpilado no servidor. +<<<<<<< HEAD Falando em nomes, o [Babel](https://babeljs.io) é um dos mais prominentes transpilers por aí. Sistemas para a construção de projetos modernos, tais como o [webpack](https://webpack.js.org/), fornecem meios para automaticamente correr o transpiler em cada alteração do código, e assim é muito fácil o integrar no processo de desenvolvimento. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ## Polyfills @@ -69,6 +85,7 @@ if (!Math.trunc) { // se a função não existir } ``` +<<<<<<< HEAD O JavaScript é uma linguagem altamente dinâmica. Scripts podem adicionar/modificar quaisquer funções, incluindo até incorporadas. Duas interessantes bibliotecas de polyfills são: @@ -76,15 +93,32 @@ Duas interessantes bibliotecas de polyfills são: - [polyfill.io](http://polyfill.io) um serviço que fornece um script com polyfills, dependendo das funcionalidades e do navegador do utilizador. ## Resumo +======= +JavaScript is a highly dynamic language. Scripts may add/modify any function, even built-in ones. + +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Neste capítulo, gostaríamos de o motivar a estudar funcionalidades modernas ou até em esboço da linguagem, mesmo que elas ainda não tenham um bom suporte pelos interpretadores de JavaScript. Apenas não se esqueça de usar um transpiler (se empregar sintaxe ou operadores modernos) e polyfills (para adicionar funções que possam estar ausentes). E eles irão garantir que o código funcione. +<<<<<<< HEAD Por exemplo, mais adiante quando estiver familiarizado com o JavaScript, você pode configurar um sistema para a construção de código com base no [webpack](https://webpack.js.org/) e com o plugin [babel-loader](https://github.com/babel/babel-loader). Bons recursos que mostram o estágio atual do suporte para várias funcionalidades: - - para puro JavaScript. - - para funções com relação ao navegador. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b P.S. O Google Chrome, geralmente é o mais atualizado relativamente a funcionalidades da linguagem, experimente-o se um exemplo no tutorial falhar. Contudo, a maioria dos exemplos no tutorial funcionam com qualquer navegador moderno. diff --git a/1-js/04-object-basics/01-object/article.md b/1-js/04-object-basics/01-object/article.md index 7cb931672..29b045a56 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 @@ O objeto `user` resultante, pode ser imaginado como um fichário com dois fichei ![user object](object-user.svg) +<<<<<<< HEAD Podemos adicionar, remover ou ler ficheiros dele em qualquer momento. +======= +We can add, remove and read files from it at any time. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Valores de propriedades podem ser acedidos usando a notação por ponto (*dot notation*): @@ -62,7 +66,11 @@ user.isAdmin = true; ![user object 2](object-user-isadmin.svg) +<<<<<<< HEAD Para remover uma propriedade, podemos usar o operador `delete`: +======= +To remove a property, we can use the `delete` operator: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js delete user.age; @@ -201,13 +209,21 @@ let bag = { }; ``` +<<<<<<< HEAD Parênteses retos, são mais poderosos que a notação por ponto. Eles permitem quaisquer nomes de propriedades e variáveis. Mas, eles também dão mais trabalho para escrever. +======= +Square brackets are much more powerful than dot notation. They allow any property names and variables. But they are also more cumbersome to write. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Assim, na maior parte as vezes, quando os nomes de propriedades são conhecidos e simples, o ponto é utilizado. E, se precisarmos de algo mais complexo, mudamos para os parênteses retos. ## Abreviação do valor da propriedade +<<<<<<< HEAD Em código real, muitas vezes usamos nomes de propriedades e nomes de variáveis iguais. +======= +In real code, we often use existing variables as values for property names. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Por exemplo: @@ -252,7 +268,11 @@ let user = { ## Limitações dos nomes de propriedades +<<<<<<< HEAD Como já sabemos, uma variável não pode ter um nome igual a uma palavra reservada da linguagem, como "for", "let", "return" etc. +======= +As we already know, a variable cannot have a name equal to one of the language-reserved words like "for", "let", "return" etc. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Mas, para propriedades de objetos não há tal restrição. @@ -325,7 +345,11 @@ alert( "blabla" in user ); // false, 'user.blabla' não existe Por favor, note que no lado esquerdo de `in` deve existir um *nome de propriedade*. Geralmente, é uma *string* entre aspas. +<<<<<<< HEAD Se omitirmos as aspas, isso terá o significado de uma variável que contém o nome a ser testado. Por exemplo: +======= +If we omit quotes, that means a variable should contain the actual name to be tested. For instance: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js run let user = { age: 30 }; @@ -355,7 +379,11 @@ No código acima, a propriedade `obj.test` tecnicamente existe. Assim, o operado Situações como esta muito raramente ocorrem, porque `undefined` não deveria ser explicitamente atribuído. Em geral, empregamos `null` para valores "desconhecidos" ou "vazios". Assim, o operador `in` é um convidado exótico na codificação. +<<<<<<< HEAD ## O laço "for..in" +======= +## The "for..in" loop [#forin] +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Para navegar por todas as chaves (*keys*) de um objeto, existe uma forma especial de laço (*loop*): `for..in`. Esta, é uma coisa completamente diferente da construção `for(;;)` que estudámos antes. @@ -412,7 +440,11 @@ for (let code in codes) { */!* ``` +<<<<<<< HEAD O objeto pode ser usado para sugerir uma lista de opções para o utilizador. Se, estivermos a construir um *site* maioritariamente para uma audiência Alemã, então provavelmente queremos `49` como o primeiro. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Mas, ao correr o código, temos uma imagem totalmente diferente: @@ -424,6 +456,7 @@ Os indicativos telefónicos, são ordenados por ordem ascendente, porque são in ````smart header="Propriedades inteiras? O que é isso?" O termo "propriedade inteira" aqui, significa que uma *string* pode ser convertida para inteiro ('integer'), e convertida de volta sem qualquer alteração. +<<<<<<< HEAD Assim, "49" é um nome de propriedade inteiro porque, ao ser transformado num número inteiro e reconvertido, continua o mesmo. Mas, "+49" e "1.2" não são: ```js run @@ -431,6 +464,16 @@ Assim, "49" é um nome de propriedade inteiro porque, ao ser transformado num n alert( String(Math.trunc(Number("49"))) ); // "49", inalterado ⇒ propriedade inteira alert( String(Math.trunc(Number("+49"))) ); // "49", não o mesmo que "+49" ⇒ não é uma propriedade inteira alert( String(Math.trunc(Number("1.2"))) ); // "1", não o mesmo que "1.2" ⇒ não é uma propriedade inteira +======= +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 +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ``` ```` @@ -479,9 +522,15 @@ Eles armazenam propriedades (pares chave-valor), onde: - As chaves das propriedades devem ser *strings* ou símbolos (geralmente *strings*). - Os valores podem ser de qualquer tipo. +<<<<<<< HEAD Para aceder a uma propriedade, podemos utilizar: - A notação por ponto: `obj.property`. - A notação por parênteses retos `obj["property"]`. Os parênteses retos permitem receber a chave a partir de uma variável, como por exemplo `obj[varWithKey]`. +======= +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]`. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Operadores adicionais: - Para remover uma propriedade: `delete obj.prop`. 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 6739fc246..e475f7cca 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 @@ E aqui é como ela está realmente armazenada na memória O objeto é armazenado em algum lugar na memória (à direita da imagem), enquanto a variável `user` (à esquerda) possui uma referência a ele. +<<<<<<< HEAD Podemos pensar em uma variável de objeto, `user`, como uma folha de papel com o endereço do objeto escrito nela. +======= +We may think of an object variable, such as `user`, like a sheet of paper with the address of the object on it. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Quando realizamos ações com o objeto, por exemplo, acessar a propriedade `user.name`, o motor do Javascript verifica o que está nesse endereço e realiza a operação no objeto real. @@ -100,10 +104,17 @@ alert(a == b); // false Para comparações como `obj1 > obj2` ou para uma comparação com um primitivo `obj == 5`, os objetos são convertidos em primitivos. Vamos estudar como as conversões de objetos funcionam muito em breve, mas, para ser honesto, tais comparações são necessárias muito raramente - geralmente, elas surgem como resultado de um erro de programação. +<<<<<<< HEAD ````smart header="Objetos com const podem ser modificados" Um efeito colateral importante de armazenar objetos como referência é que um objeto declarado como `const` *pode* ser modificado Por exemplo: +======= +````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. + +For instance: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js run const user = { @@ -124,12 +135,209 @@ Em outras palavras, o `const user` gera um erro apenas se tentarmos definir `use Dito isto, se realmente precisamos tornar as propriedades do objeto constantes, também é possível, porém usando métodos totalmente diferentes. Vamos mencionar isto no capítulo . ```` +<<<<<<< HEAD ## Clonando e mesclando, Object.assign [#cloning-and-merging-object-assign] +======= +## 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 +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Sim, copiar uma variável de objeto cria mais uma referência para o mesmo objeto. Mas e se precisamos duplicar um objeto? +<<<<<<< HEAD Podemos criar um novo objeto e replicar a estrutura existente, iterando sobre suas propriedades e copiando-as no nível primitivo. Como neste exemplo: @@ -323,3 +531,6 @@ Objetos são atribuídos e copiados por referência. Em outras palavras, uma var Todas as operações feitas através de referências copiadas (como adição/remoção de propriedades) são realizadas no mesmo objeto único. Para fazer uma "cópia real" (um clone) podemos usar `Object.assign` caracterizando a chamada "cópia rasa" (objetos aninhados são copiados por referência) ou uma função `structuredClone` de "clonagem profunda" ou usar uma implementação de clonagem personalizada, como [\_.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). +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b 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 a2a19c620..7d2ef8c15 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,7 @@ importance: 2 # Chaining -There's a `ladder` object that allows to go up and down: +There's a `ladder` object that allows you to go up and down: ```js let ladder = { @@ -21,7 +21,7 @@ let ladder = { }; ``` -Now, if we need to make several calls in sequence, can do it like this: +Now, if we need to make several calls in sequence, we can do it like this: ```js ladder.up(); @@ -32,10 +32,10 @@ ladder.down(); ladder.showStep(); // 0 ``` -Modify the code of `up`, `down` and `showStep` to make the calls chainable, like this: +Modify the code of `up`, `down`, and `showStep` to make the calls chainable, like this: ```js ladder.up().up().down().showStep().down().showStep(); // shows 1 then 0 ``` -Such approach is widely used across JavaScript libraries. +Such an approach is widely used across JavaScript libraries. 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 ea54d2874..0bd8934e5 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 Crie uma função construtora `Calculator` que crie objetos com 3 métodos: +<<<<<<< HEAD - `read()` solicita 2 valores e os guarda como propriedades do objeto com nomes `a` e `b` respectivamente. - `sum()` retorna a soma dessas propriedades. - `mul()` retorna o produto da multiplicação dessas propriedades. +======= +- `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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Por exemplo: 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 4ac2f5b90..12d969336 100644 --- a/1-js/04-object-basics/06-constructor-new/article.md +++ b/1-js/04-object-basics/06-constructor-new/article.md @@ -168,8 +168,13 @@ alert( new SmallUser().name ); // John Geralmente os construtores não têm uma declaração `return`. Aqui, nós mencionamos o comportamento especial com objetos retornados principalmente por uma questão de integralidade. +<<<<<<< HEAD ````smart header="Omitindo parênteses" A propósito, nós podemos omitir os parênteses depois de `new`: +======= +````smart header="Omitting parentheses" +By the way, we can omit parentheses after `new`: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js let user = new User; // <-- sem parênteses diff --git a/1-js/04-object-basics/08-symbol/article.md b/1-js/04-object-basics/08-symbol/article.md index 9ccced8e9..551e439e9 100644 --- a/1-js/04-object-basics/08-symbol/article.md +++ b/1-js/04-object-basics/08-symbol/article.md @@ -2,6 +2,7 @@ Por especificação, apenas dois tipos primitivos podem ser utilizados como chaves de propriedades de objetos: +<<<<<<< HEAD - o tipo string, ou - o tipo symbol. @@ -10,6 +11,18 @@ Caso contrário, se for usado outro tipo, como o tipo number, ele é convertido Até agora, só temos utilizado strings. Agora vamos explorar os symbols e ver o que eles podem fazer por nós. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ## Symbols @@ -21,14 +34,22 @@ Um valor desse tipo pode ser criado usando `Symbol()`: let id = Symbol(); ``` +<<<<<<< HEAD Ao criá-los, podemos atribuir aos symbols uma descrição (também conhecida como nome do symbol), geralmente útil para fins de depuração: +======= +Upon creation, we can give symbols a description (also called a symbol name), mostly useful for debugging purposes: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js // id é um symbol com a descrição "id" let id = Symbol("id"); ``` +<<<<<<< HEAD Symbols são garantidos como únicos. Mesmo que criemos muitos symbols com exatamente a mesma descrição, eles são valores diferentes. A descrição é apenas um rótulo que não afeta nada. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Por exemplo, aqui estão dois symbols com a mesma descrição -- eles não são iguais: @@ -43,7 +64,14 @@ alert(id1 == id2); // false Se você estiver familiarizado com Ruby ou outra linguagem que também tenha algum tipo de "symbols", por favor, não se deixe confundir. Symbols no JavaScript são diferentes. +<<<<<<< HEAD Então, para resumir, um symbol é um "valor primitivo único" com uma descrição opcional. Vamos ver onde podemos usá-los. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ````warn header="Symbols não são automaticamente convertidos para uma string" A maioria dos valores no JavaScript suporta conversão implícita para string. Por exemplo, podemos usar `alert` com quase qualquer valor, e isso funcionará. Symbols são especiais, pois não são convertidos automaticamente para uma string. @@ -61,6 +89,11 @@ Isso serve como um "guardião da linguagem" contra confusões, uma vez que strin Se realmente queremos exibir um symbol, precisamos chamá-lo explicitamente com `.toString()`, como mostrado aqui: +<<<<<<< HEAD +======= +If we really want to show a symbol, we need to explicitly call `.toString()` on it, like here: + +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js run let id = Symbol("id"); *!* @@ -68,7 +101,11 @@ alert(id.toString()); // Symbol(id), agora funciona */!* ``` +<<<<<<< HEAD Ou podemos obter a propriedade `symbol.description` para exibir apenas a descrição: +======= +Or get `symbol.description` property to show the description only: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js run let id = Symbol("id"); @@ -81,7 +118,12 @@ alert(id.description); // id ## Propriedades "Ocultas" +<<<<<<< HEAD Symbols nos permitem criar propriedades "ocultas" de um objecto, as quais nenhuma outra parte do código pode acessar ou sobrescrever acidentalmente. +======= + +Symbols allow us to create "hidden" properties of an object, that no other part of code can accidentally access or overwrite. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Por exemplo, se estivermos trabalhando com objetos `user` que pertencem a um código de terceiros, gostaríamos de adicionar identificadores a eles. @@ -102,9 +144,15 @@ alert(user[id]); // podemos acessar os dados usando symbol como chave Qual o benefício de usar `Symbol("id")` ao invés de uma string `"id"`? +<<<<<<< HEAD Como os objetos `user` pertencem a outra base de código, não é seguro adicionar campos a eles, pois podemos afetar o comportamento pré-definido nessa outra base de código. No entanto, symbols não podem ser acessados acidentalmente. O código de terceiros não estará ciente da existência de symbols recém-definidos, portanto, é seguro adicionar symbols aos objetos `user`. Além disso, imagine que outro script deseja ter seu próprio identificador dentro de `user`, para seus próprios propósitos. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Então esse script pode criar seu próprio `Symbol("id")`, dessa forma: @@ -168,7 +216,11 @@ let user = { for (let key in user) alert(key); // name, age (sem symbols) */!* +<<<<<<< HEAD // o acesso direto por meio do symbol funciona +======= +// the direct access by the symbol works +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b alert( "Direct: " + user[id] ); // Direct: 123 ``` @@ -217,12 +269,20 @@ Symbols dentro do registro são chamados de _symbols globais_. Se quisermos um s ```smart header="Isso parece com Ruby" Em algumas linguagens de programação, como no Ruby, há um único symbol por nome. +<<<<<<< HEAD Em JavaScript, como podemos ver, isso é verdade para symbols globais. +======= +In JavaScript, as we can see, that's true for global symbols. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ``` ### Symbol.keyFor +<<<<<<< HEAD Nós vimos que, para symbols globais, `Symbol.for(chave)` retorna um symbol pelo nome. Para fazer o oposto -- retornar um nome pelo symbol global -- podemos usar: `Symbol.keyFor(sym)`: +======= +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)`: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Por exemplo: @@ -238,7 +298,11 @@ alert(Symbol.keyFor(sym2)); // id O `Symbol.keyFor` utiliza internamente o registro global de symbols para procurar a chave associada ao symbol. Portanto, não funciona para symbols não globais. Se o symbol não for global, não será possível encontrá-lo, e a função retornará `undefined` +<<<<<<< HEAD Dito isso, todos os symbols têm a propriedade `description` +======= +That said, all symbols have the `description` property. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Por exemplo: @@ -278,12 +342,22 @@ Symbols são sempre valores diferentes, mesmo se tiverem o mesmo nome. Se deseja Symbols têm dois principais casos de uso: +<<<<<<< HEAD 1. Propriedades "ocultas" de objetos. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Se desejamos adicionar uma propriedade a um objeto que "pertence" a outro script ou biblioteca, podemos criar um símbolo e usá-lo como chave de propriedade. Uma propriedade simbólica não aparece em for..in, portanto, não será processada acidentalmente junto com outras propriedades. Além disso, ela não será acessada diretamente, porque outro script não possui o nosso símbolo. Assim, a propriedade estará protegida contra uso ou sobrescrita acidental. Portanto, podemos "ocultar discretamente" algo em objetos que precisamos, mas que outros não devem ver, usando propriedades simbólicas. +<<<<<<< HEAD 2. Existem muitos símbolos do sistema usados pelo JavaScript que são acessíveis como `Symbol.*`. Podemos utilizá-los para alterar alguns comportamentos embutidos. Por exemplo, mais tarde no tutorial, utilizaremos `Symbol.iterator` para [iteráveis](info:iterable), `Symbol.toPrimitive` para configurar [conversão de objeto para primitivo](info:object-toprimitive) e assim por diante. Tecnicamente, symbols nao são 100% ocultos. Existe um método embutido [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) que nos permite obter todos os symbols. Também há um método chamado [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) que retorna _todas_ as chaves de um objeto, incluindo as simbólicas. No entanto, a maioria das bibliotecas, funções embutidas e construções de syntaxe não utilizam esses métodos. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b 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 0a16b5399..fa68da583 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -253,7 +253,7 @@ let obj = { } }; -alert(obj + 2); // 22 ("2" + 2), conversion to primitive returned a string => concatenation +alert(obj + 2); // "22" ("2" + 2), conversion to primitive returned a string => concatenation ``` ## Summary 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 d87bf0174..96e406d8c 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 @@ -15,4 +15,8 @@ str.test = 5; alert(str.test); ``` +<<<<<<< HEAD Como você acha, vai funcionar? O que será mostrado? +======= +What do you think, will it work? What will be shown? +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b 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 1a2558b73..8031f3c13 100644 --- a/1-js/05-data-types/01-primitives-methods/article.md +++ b/1-js/05-data-types/01-primitives-methods/article.md @@ -39,8 +39,13 @@ Objetos são "mais pesados" que primitivos. Eles exigem recursos adicionais para Aqui está o paradoxo enfrentado pelo criador do JavaScript: +<<<<<<< HEAD - Há muitas coisas que alguém poderia querer fazer com um primitivo como uma string ou um número. Seria ótimo acessá-los usando métodos. - Primitivos devem ser o mais rápidos e leves possível. +======= +- 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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b A solução parece um pouco estranha, mas aqui está: @@ -104,9 +109,16 @@ if (zero) { // zero é true (verdadeiro), por que é um objeto } ``` +<<<<<<< HEAD Por outro lado, usar as mesmas funções `String / Number / Boolean` sem` new` é uma coisa totalmente sensata e útil. Eles convertem um valor para o tipo correspondente: para uma string, um número ou um booleano (primitivo). Por exemplo, isso é inteiramente válido: +======= +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: + +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js let num = Number("123"); // converte a string para número ``` diff --git a/1-js/05-data-types/02-number/article.md b/1-js/05-data-types/02-number/article.md index c704bd980..f1f881ceb 100644 --- a/1-js/05-data-types/02-number/article.md +++ b/1-js/05-data-types/02-number/article.md @@ -4,7 +4,11 @@ In modern JavaScript, there are two types of numbers: 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. +<<<<<<< HEAD 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 few special areas, we devote them a special 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 . +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b So here we'll talk about regular numbers. Let's expand our knowledge of them. @@ -41,7 +45,7 @@ In other words, `e` multiplies the number by `1` with the given zeroes count. 1.23e6 === 1.23 * 1000000; // e6 means *1000000 ``` -Now let's write something very small. Say, 1 microsecond (one millionth of a second): +Now let's write something very small. Say, 1 microsecond (one-millionth of a second): ```js let mсs = 0.000001; @@ -103,13 +107,13 @@ alert( num.toString(16) ); // ff alert( num.toString(2) ); // 11111111 ``` -The `base` can vary from `2` to `36`. By default it's `10`. +The `base` can vary from `2` to `36`. By default, it's `10`. Common use cases for this are: - **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`: +- **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`: ```js run alert( 123456..toString(36) ); // 2n9c @@ -118,7 +122,7 @@ Common use cases for this are: ```warn header="Two dots to call a method" Please note that two dots in `123456..toString(36)` is not a typo. If we want to call a method directly on a number, like `toString` in the example above, then we need to place two dots `..` after it. -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 goes the method. +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)`. @@ -137,7 +141,7 @@ There are several built-in functions for rounding: : Rounds up: `3.1` becomes `4`, and `-1.1` becomes `-1`. `Math.round` -: Rounds to the nearest integer: `3.1` becomes `3`, `3.6` becomes `4`, the middle case: `3.5` rounds up to `4` too. +: 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`. `Math.trunc` (not supported by Internet Explorer) : Removes anything after the decimal point without rounding: `3.1` becomes `3`, `-1.1` becomes `-1`. @@ -147,8 +151,10 @@ Here's the table to summarize the differences between them: | | `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` | @@ -188,7 +194,11 @@ There are two ways to do so: alert( num.toFixed(5) ); // "12.34000", added zeroes to make exactly 5 digits ``` +<<<<<<< HEAD We can convert it to a number using the unary plus or a `Number()` call, e.g write `+num.toFixed(5)`. +======= + We can convert it to a number using the unary plus or a `Number()` call, e.g. write `+num.toFixed(5)`. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ## Imprecise calculations @@ -222,7 +232,17 @@ But why does this happen? A number is stored in memory in its binary form, a sequence of bits - ones and zeroes. But fractions like `0.1`, `0.2` that look simple in the decimal numeric system are actually unending fractions in their binary form. +<<<<<<< HEAD What is `0.1`? It is one divided by ten `1/10`, one-tenth. In decimal numeral system such numbers are easily representable. Compare it to one-third: `1/3`. It becomes an endless fraction `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)`. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b So, division by powers `10` is guaranteed to work well in the decimal system, but division by `3` is not. For the same reason, in the binary numeral system, the division by powers of `2` is guaranteed to work, but `1/10` becomes an endless binary fraction. @@ -242,7 +262,7 @@ That's why `0.1 + 0.2` is not exactly `0.3`. ```smart header="Not only JavaScript" The same issue exists in many other programming languages. -PHP, Java, C, Perl, Ruby give exactly the same result, because they are based on the same numeric format. +PHP, Java, C, Perl, and Ruby give exactly the same result, because they are based on the same numeric format. ``` Can we work around the problem? Sure, the most reliable method is to round the result with the help of a method [toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed): @@ -266,7 +286,7 @@ alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3 alert( (0.28 * 100 + 0.14 * 100) / 100); // 0.4200000000000001 ``` -So, multiply/divide approach reduces the error, but doesn't remove it totally. +So, the multiply/divide approach reduces the error, but doesn't remove it totally. Sometimes we could try to evade fractions at all. Like if we're dealing with a shop, then we can store prices in cents instead of dollars. But what if we apply a discount of 30%? In practice, totally evading fractions is rarely possible. Just round them to cut "tails" when needed. @@ -288,7 +308,7 @@ Another funny consequence of the internal representation of numbers is the exist That's because a sign is represented by a single bit, so it can be set or not set for any number including a zero. -In most cases the distinction is unnoticeable, because operators are suited to treat them as the same. +In most cases, the distinction is unnoticeable, because operators are suited to treat them as the same. ``` ## Tests: isFinite and isNaN @@ -337,7 +357,11 @@ Please note that an empty or a space-only string is treated as `0` in all numeri ````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. +<<<<<<< HEAD - `Number.isNaN(value)` returns `true` if the argument belongs to the `number` type and it is `NaN`. In any other case it returns `false`. +======= +- `Number.isNaN(value)` returns `true` if the argument belongs to the `number` type and it is `NaN`. In any other case, it returns `false`. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js run alert( Number.isNaN(NaN) ); // true @@ -348,7 +372,11 @@ Please note that an empty or a space-only string is treated as `0` in all numeri alert( isNaN("str") ); // true, because isNaN converts string "str" into a number and gets NaN as a result of this conversion ``` +<<<<<<< HEAD - `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`. +======= +- `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`. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js run alert( Number.isFinite(123) ); // true @@ -367,7 +395,11 @@ In a way, `Number.isNaN` and `Number.isFinite` are simpler and more straightforw 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. +<<<<<<< HEAD 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. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b In all other cases, `Object.is(a, b)` is the same as `a === b`. @@ -385,7 +417,7 @@ alert( +"100px" ); // NaN The sole exception is spaces at the beginning or at the end of the string, as they are ignored. -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. +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. That's what `parseInt` and `parseFloat` are for. @@ -479,4 +511,4 @@ For fractions: More mathematical functions: -- 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. +- 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. 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 6382029f4..c99a5f15a 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 @@ The result of the function should be the truncated (if needed) string. For instance: ```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/04-array/article.md b/1-js/05-data-types/04-array/article.md index 4bcab0bc9..1b0f17215 100644 --- a/1-js/05-data-types/04-array/article.md +++ b/1-js/05-data-types/04-array/article.md @@ -98,7 +98,11 @@ The "trailing comma" style makes it easier to insert/remove items, because all l Let's say we want the last element of the array. +<<<<<<< HEAD Some programming languages allow to use negative indexes for the same purpose, like `fruits[-1]`. +======= +Some programming languages allow the use of negative indexes for the same purpose, like `fruits[-1]`. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Although, in JavaScript it won't work. The result will be `undefined`, because the index in square brackets is treated literally. @@ -426,7 +430,7 @@ let matrix = [ [7, 8, 9] ]; -alert( matrix[1][1] ); // 5, the central element +alert( matrix[0][1] ); // 2, the second value of the first inner array ``` ## toString 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 4db1a16b6..fbc95237c 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,6 @@ # Array methods -Arrays provide a lot of methods. To make things easier, in this chapter they are split into groups. +Arrays provide a lot of methods. To make things easier, in this chapter, they are split into groups. ## Add/remove items @@ -32,11 +32,11 @@ alert( arr.length ); // 3 The element was removed, but the array still has 3 elements, we can see that `arr.length == 3`. -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 elements to shift and occupy the freed place. We expect to have a shorter array now. +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. So, special methods should be used. -The [arr.splice](mdn:js/Array/splice) method is a swiss army knife for arrays. It can do everything: insert, remove and replace elements. +The [arr.splice](mdn:js/Array/splice) method is a Swiss army knife for arrays. It can do everything: insert, remove and replace elements. The syntax is: @@ -62,7 +62,7 @@ alert( arr ); // ["I", "JavaScript"] Easy, right? Starting from the index `1` it removed `1` element. -In the next example we remove 3 elements and replace them with the other two: +In the next example, we remove 3 elements and replace them with the other two: ```js run let arr = [*!*"I", "study", "JavaScript",*/!* "right", "now"]; @@ -84,7 +84,7 @@ let removed = arr.splice(0, 2); alert( removed ); // "I", "study" <-- array of removed elements ``` -The `splice` method is also able to insert the elements without any removals. For that we need to set `deleteCount` to `0`: +The `splice` method is also able to insert the elements without any removals. For that, we need to set `deleteCount` to `0`: ```js run let arr = ["I", "study", "JavaScript"]; @@ -114,7 +114,7 @@ alert( arr ); // 1,2,3,4,5 ### slice -The method [arr.slice](mdn:js/Array/slice) is much simpler than similar-looking `arr.splice`. +The method [arr.slice](mdn:js/Array/slice) is much simpler than the similar-looking `arr.splice`. The syntax is: @@ -124,7 +124,7 @@ arr.slice([start], [end]) It returns a new array copying to it all items from index `start` to `end` (not including `end`). Both `start` and `end` can be negative, in that case position from array end is assumed. -It's similar to a string method `str.slice`, but instead of substrings it makes subarrays. +It's similar to a string method `str.slice`, but instead of substrings, it makes subarrays. For instance: @@ -206,7 +206,7 @@ The [arr.forEach](mdn:js/Array/forEach) method allows to run a function for ever The syntax: ```js arr.forEach(function(item, index, array) { - // ... do something with item + // ... do something with an item }); ``` @@ -239,7 +239,11 @@ The methods [arr.indexOf](mdn:js/Array/indexOf) and [arr.includes](mdn:js/Array/ - `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. +<<<<<<< HEAD Usually these methods are used with only one argument: the `item` to search. By default, the search is from the beginning. +======= +Usually, these methods are used with only one argument: the `item` to search. By default, the search is from the beginning. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b For instance: @@ -255,7 +259,11 @@ alert( arr.includes(1) ); // true Please note that `indexOf` uses the strict equality `===` for comparison. So, if we look for `false`, it finds exactly `false` and not the zero. +<<<<<<< HEAD If we want to check if `item` exists in the array, and don't need the index, then `arr.includes` is preferred. +======= +If we want to check if `item` exists in the array and don't need the index, then `arr.includes` is preferred. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b The method [arr.lastIndexOf](mdn:js/Array/lastIndexOf) is the same as `indexOf`, but looks for from right to left. @@ -274,12 +282,16 @@ const arr = [NaN]; alert( arr.indexOf(NaN) ); // -1 (wrong, should be 0) alert( arr.includes(NaN) );// true (correct) ``` +<<<<<<< HEAD That's because `includes` was added to JavaScript much later and uses the more up to date comparison algorithm internally. +======= +That's because `includes` was added to JavaScript much later and uses the more up-to-date comparison algorithm internally. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```` ### find and findIndex/findLastIndex -Imagine we have an array of objects. How do we find an object with the specific condition? +Imagine we have an array of objects. How do we find an object with a specific condition? Here the [arr.find(fn)](mdn:js/Array/find) method comes in handy. @@ -297,7 +309,7 @@ The function is called for elements of the array, one after another: - `index` is its index. - `array` is the array itself. -If it returns `true`, the search is stopped, the `item` is returned. If nothing found, `undefined` is returned. +If it returns `true`, the search is stopped, the `item` is returned. If nothing is found, `undefined` is returned. For example, we have an array of users, each with the fields `id` and `name`. Let's find the one with `id == 1`: @@ -313,11 +325,15 @@ let user = users.find(item => item.id == 1); alert(user.name); // John ``` -In real life arrays of objects is a common thing, so the `find` method is very useful. +In real life, arrays of objects are a common thing, so the `find` method is very useful. Note that in the example we provide to `find` the function `item => item.id == 1` with one argument. That's typical, other arguments of this function are rarely used. +<<<<<<< HEAD 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.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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b The [arr.findLastIndex](mdn:js/Array/findLastIndex) method is like `findIndex`, but searches from right to left, similar to `lastIndexOf`. @@ -450,11 +466,11 @@ alert(arr); // *!*1, 2, 15*/!* Now it works as intended. -Let's step aside and think what's happening. The `arr` can be 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. +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. The `arr.sort(fn)` method implements a generic sorting algorithm. We don't need to care how it internally works (an optimized [quicksort](https://en.wikipedia.org/wiki/Quicksort) or [Timsort](https://en.wikipedia.org/wiki/Timsort) most of the time). It will walk the array, compare its elements using the provided function and reorder them, all we need is to provide the `fn` which does the comparison. -By the way, if we ever want to know which elements are compared -- nothing prevents from alerting them: +By the way, if we ever want to know which elements are compared -- nothing prevents us from alerting them: ```js run [1, -2, 15, 2, 0, 8].sort(function(a, b) { @@ -526,7 +542,7 @@ Here's the situation from real life. We are writing a messaging app, and the per The [str.split(delim)](mdn:js/String/split) method does exactly that. It splits the string into an array by the given delimiter `delim`. -In the example below, we split by a comma followed by space: +In the example below, we split by a comma followed by a space: ```js run let names = 'Bilbo, Gandalf, Nazgul'; @@ -593,9 +609,9 @@ Arguments: - `index` -- is its position. - `array` -- is the array. -As function is applied, the result of the previous function call is passed to the next one as the first argument. +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`. +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`. Sounds complicated? @@ -664,7 +680,11 @@ arr.reduce((sum, current) => sum + current); So it's advised to always specify the initial value. +<<<<<<< HEAD The method [arr.reduceRight](mdn:js/Array/reduceRight) does the same, but goes from right to left. +======= +The method [arr.reduceRight](mdn:js/Array/reduceRight) does the same but goes from right to left. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ## Array.isArray @@ -689,7 +709,7 @@ alert(Array.isArray([])); // true Almost all array methods that call functions -- like `find`, `filter`, `map`, with a notable exception of `sort`, accept an optional additional parameter `thisArg`. -That parameter is not explained in the sections above, because it's rarely used. But for completeness we have to cover it. +That parameter is not explained in the sections above, because it's rarely used. But for completeness, we have to cover it. Here's the full syntax of these methods: @@ -749,7 +769,7 @@ A cheat sheet of array methods: - `concat(...items)` -- returns a new array: copies all members of the current one and adds `items` to it. If any of `items` is an array, then its elements are taken. - To search among elements: - - `indexOf/lastIndexOf(item, pos)` -- look for `item` starting from position `pos`, return the index or `-1` if not found. + - `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. @@ -795,7 +815,7 @@ These methods are the most used ones, they cover 99% of use cases. But there are For the full list, see the [manual](mdn:js/Array). -From the first sight it may seem that there are so many methods, quite difficult to remember. But actually that's much easier. +At first sight, it may seem that there are so many methods, quite difficult to remember. But actually, that's much easier. Look through the cheat sheet just to be aware of them. Then solve the tasks of this chapter to practice, so that you have experience with array methods. diff --git a/1-js/05-data-types/06-iterable/article.md b/1-js/05-data-types/06-iterable/article.md index 76f74036c..e2c0d4f97 100644 --- a/1-js/05-data-types/06-iterable/article.md +++ b/1-js/05-data-types/06-iterable/article.md @@ -174,7 +174,7 @@ When we use JavaScript for practical tasks in a browser or any other environment For instance, strings are both iterable (`for..of` works on them) and array-like (they have numeric indexes and `length`). -But an iterable may be not array-like. And vice versa an array-like may be not iterable. +But an iterable may not be array-like. And vice versa an array-like may not be iterable. For example, the `range` in the example above is iterable, but not array-like, because it does not have indexed properties and `length`. 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 8672bac66..3f0d34bc3 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 @@ Mas isso não é suficiente para a vida real. É por isso que `Map` e `Set` tamb ## Map +<<<<<<< HEAD [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) é uma coleção de itens de dados indexados, assim como um `Object`. Mas a principal diferença é que `Map` permite chaves de qualquer 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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Métodos e propriedades são: +<<<<<<< HEAD - [`new Map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/Map) -- cria o mapa. - [`map.set(chave, valor)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set) -- armazena o valor pela chave. - [`map.get(chave)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get) -- retorna o valor pela chave, `undefined` se a `chave` não existir no mapa. @@ -21,6 +26,15 @@ Métodos e propriedades são: - [`map.delete(chave)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete) -- remove o elemento (o par chave/valor) pela chave. - [`map.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear) -- remove tudo do mapa. - [`map.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size) -- retorna a contagem atual de elementos. +======= +- [`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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Por exemplo: @@ -100,15 +114,27 @@ map.set('1', 'str1') ``` ```` +<<<<<<< HEAD ## Iteração sobre o Map Para fazer um loop em um `map`, existem 3 métodos: +======= +## Iteration over Map +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b - [`map.keys()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/keys) -- retorna um iterável para chaves, - [`map.values()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/values) -- retorna um iterável para valores, - [`map.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries) -- retorna um iterável para entradas `[chave, valor]`, é usado por padrão em `for..of`. +<<<<<<< HEAD Por exemplo: +======= +- [`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: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js run let recipeMap = new Map([ @@ -161,7 +187,11 @@ let map = new Map([ alert( map.get('1') ); // str1 ``` +<<<<<<< HEAD Se tivermos um objeto simples e gostaríamos de criar um `Map` a partir dele, podemos usar o método embutido [Object.entries(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries), que retorna um array de pares chave/valor para um objeto exatamente nesse 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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Portanto, podemos criar um mapa a partir de um objeto da seguinte forma: @@ -231,16 +261,29 @@ Isso é o mesmo, porque `Object.fromEntries` espera um objeto iterável como arg ## Set +<<<<<<< HEAD Um [`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) é um tipo especial de coleção - "conjunto de valores" (sem chaves), onde cada valor pode ocorrer apenas uma vez. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Seus principais métodos são: +<<<<<<< HEAD - [`new Set([iterable])`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/Set) -- cria o conjunto e, se um objeto `iterable` (geralmente um array) for fornecido, copia os valores dele para o conjunto. - [`set.add(value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/add) -- adiciona um valor e retorna o próprio conjunto. - [`set.delete(value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/delete) -- remove o valor e retorna `true` se o `value` existir no momento da chamada, caso contrário, retorna `false`. - [`set.has(value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/has) -- retorna `true` se o valor existir no conjunto, caso contrário, retorna `false`. - [`set.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/clear) -- remove tudo do conjunto. - [`set.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/size) -- representa a contagem de elementos. +======= +- [`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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b A principal característica é que chamadas repetidas de `set.add(value)` com o mesmo valor não fazem nada. Essa é a razão pela qual cada valor aparece em um `Set` apenas uma vez. @@ -270,7 +313,11 @@ for (let user of set) { } ``` +<<<<<<< HEAD A alternativa ao `Set` poderia ser um array de usuários e o código para verificar duplicatas em cada inserção usando [arr.find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find). No entanto, o desempenho seria muito pior, porque esse método percorre todo o array verificando cada elemento. O `Set` é muito mais otimizado internamente para verificações de unicidade. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ## Iteração sobre o Set @@ -289,20 +336,35 @@ set.forEach((value, valueAgain, set) => { Observe a coisa curiosa. A função de retorno de chamada passada no `forEach` tem 3 argumentos: um `value`, em seguida, *o mesmo valor* `valueAgain`, e depois o objeto de destino. Na verdade, o mesmo valor aparece nos argumentos duas vezes. +<<<<<<< HEAD Isso é para compatibilidade com o `Map`, onde a função de retorno de chamada passada no `forEach` tem três argumentos. Parece um pouco estranho, com certeza. Mas isso pode ajudar a substituir `Map` por `Set` em determinados casos com facilidade, 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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Os mesmos métodos que o `Map` tem para iteradores também são suportados: +<<<<<<< HEAD - [`set.keys()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/keys) -- retorna um objeto iterável para valores, - [`set.values()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/values) -- o mesmo que `set.keys()`, para compatibilidade com `Map`, - [`set.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/entries) -- retorna um objeto iterável para entradas `[valor, valor]`, existe para compatibilidade com `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`. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ## Resumo +<<<<<<< HEAD [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) -- é uma coleção de valores indexados. +======= +[`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) -- is a collection of keyed values. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Métodos e propriedades: +<<<<<<< HEAD - [`new Map([iterable])`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/Map) -- cria o mapa, com um `iterable` opcional (por exemplo, array) de pares `[chave, valor]` para inicialização. - [`map.set(chave, valor)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set) -- armazena o valor pela chave e retorna o próprio mapa. - [`map.get(chave)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get) -- retorna o valor pela chave, `undefined` se a `chave` não existir no mapa. @@ -310,21 +372,43 @@ Métodos e propriedades: - [`map.delete(chave)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete) -- remove o elemento pela chave e retorna `true` se a `chave` existir no momento da chamada, caso contrário, `false`. - [`map.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear) -- remove tudo do mapa. - [`map.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size) -- retorna a contagem atual de elementos. +======= +- [`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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b As diferenças em relação a um objeto normal (`Object`): - Qualquer chave, objetos também podem ser chaves. - Métodos adicionais convenientes e a propriedade `size`. +<<<<<<< HEAD [`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) -- é uma coleção de valores únicos. +======= +[`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) -- is a collection of unique values. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Métodos e propriedades: +<<<<<<< HEAD - [`new Set([iterable])`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/Set) -- cria o conjunto, com um `iterable` opcional (por exemplo, array) de valores para inicialização. - [`set.add(valor)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/add) -- adiciona um valor (não faz nada se o `valor` já existir) e retorna o próprio conjunto. - [`set.delete(valor)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/delete) -- remove o valor e retorna `true` se o `valor` existir no momento da chamada, caso contrário, `false`. - [`set.has(valor)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/has) -- retorna `true` se o valor existir no conjunto, caso contrário, `false`. - [`set.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/clear) -- remove tudo do conjunto. - [`set.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/size) -- representa a contagem de elementos. +======= +- [`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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b A iteração sobre `Map` e `Set` sempre segue a ordem de inserção, então não podemos dizer que essas coleções são desordenadas. No entanto, não podemos reordenar os elementos ou obter um elemento diretamente pelo seu número. 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 41e36db2c..0c52741d1 100644 --- a/1-js/05-data-types/10-destructuring-assignment/article.md +++ b/1-js/05-data-types/10-destructuring-assignment/article.md @@ -5,18 +5,18 @@ The two most used data structures in JavaScript are `Object` and `Array`. - 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. -Although, when we pass those to a function, it may need not be an object/array as a whole. It may need individual pieces. +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 great with complex functions that have a lot of parameters, default values, and so on. Soon we'll see that. +Destructuring also works well with complex functions that have a lot of parameters, default values, and so on. Soon we'll see that. ## Array destructuring Here's an example of how an array is destructured into variables: ```js -// we have an array with the name and surname +// we have an array with a name and surname let arr = ["John", "Smith"] *!* @@ -40,10 +40,10 @@ alert(firstName); // John alert(surname); // Smith ``` -As you can see, the syntax is simple. There are several peculiar details though. Let's see more examples, to better understand it. +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. But the array itself is not modified. +It's called "destructuring assignment," because it "destructurizes" by copying items into variables. However, the array itself is not modified. It's just a shorter way to write: ```js @@ -65,7 +65,7 @@ let [firstName, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic alert( title ); // Consul ``` -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 is also skipped (as there are no variables for them). +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). ```` ````smart header="Works with any iterable on the right-side" @@ -95,9 +95,9 @@ alert(user.surname); // Smith ```` ````smart header="Looping with .entries()" -In the previous chapter we saw the [Object.entries(obj)](mdn:js/Object/entries) method. +In the previous chapter, we saw the [Object.entries(obj)](mdn:js/Object/entries) method. -We can use it with destructuring to loop over keys-and-values of an object: +We can use it with destructuring to loop over the keys-and-values of an object: ```js run let user = { @@ -105,7 +105,7 @@ let user = { age: 30 }; -// loop over keys-and-values +// loop over the keys-and-values *!* for (let [key, value] of Object.entries(user)) { */!* @@ -169,7 +169,7 @@ If we'd like also to gather all that follows -- we can add one more parameter th let [name1, name2, *!*...rest*/!*] = ["Julius", "Caesar", *!*"Consul", "of the Roman Republic"*/!*]; *!* -// rest is array of items, starting from the 3rd one +// rest is an array of items, starting from the 3rd one alert(rest[0]); // Consul alert(rest[1]); // of the Roman Republic alert(rest.length); // 2 @@ -187,7 +187,7 @@ let [name1, name2, *!*...titles*/!*] = ["Julius", "Caesar", "Consul", "of the Ro ### Default values -If the array is shorter than the list of variables at the left, there'll be no errors. Absent values are considered undefined: +If the array is shorter than the list of variables on the left, there will be no errors. Absent values are considered undefined: ```js run *!* @@ -418,7 +418,7 @@ alert( title ); // Menu ## Nested destructuring -If an object or an array contain other nested objects and arrays, we can use more complex left-side patterns to extract deeper portions. +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: @@ -449,7 +449,7 @@ alert(item1); // Cake alert(item2); // Donut ``` -All properties of `options` object except `extra` that is absent in the left part, are assigned to corresponding variables: +All properties of `options` object except `extra` which is absent in the left part, are assigned to corresponding variables: ![](destructuring-complex.svg) @@ -459,9 +459,9 @@ Note that there are no variables for `size` and `items`, as we take their conten ## Smart function parameters -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, items list and so on. +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 function: +Here's a bad way to write such a function: ```js function showMenu(title = "Untitled", width = 200, height = 100, items = []) { @@ -469,7 +469,7 @@ function showMenu(title = "Untitled", width = 200, height = 100, items = []) { } ``` -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. +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. Like this? @@ -534,7 +534,7 @@ function({ }) ``` -Then, for an object of parameters, there will be a variable `varName` for property `incomingProperty`, with `defaultValue` by default. +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: @@ -561,7 +561,7 @@ In the code above, the whole arguments object is `{}` by default, so there's alw - Destructuring assignment allows for instantly mapping an object or array onto many variables. - The full object syntax: ```js - let {prop : varName = default, ...rest} = object + let {prop : varName = defaultValue, ...rest} = object ``` This means that property `prop` should go into the variable `varName` and, if no such property exists, then the `default` value should be used. @@ -571,9 +571,9 @@ In the code above, the whole arguments object is `{}` by default, so there's alw - The full array syntax: ```js - let [item1 = default, item2, ...rest] = array + let [item1 = defaultValue, item2, ...rest] = array ``` - The first item goes to `item1`; the second goes into `item2`, all the rest makes the array `rest`. + The first item goes to `item1`; the second goes into `item2`, and all the rest makes the array `rest`. - It's possible to extract data from nested arrays/objects, for that the left side must have the same structure as the right one. diff --git a/1-js/05-data-types/12-json/article.md b/1-js/05-data-types/12-json/article.md index 25bb52fe3..133ffb353 100644 --- a/1-js/05-data-types/12-json/article.md +++ b/1-js/05-data-types/12-json/article.md @@ -405,7 +405,7 @@ To decode a JSON-string, we need another method named [JSON.parse](mdn:js/JSON/p The syntax: ```js -let value = JSON.parse(str, [reviver]); +let value = JSON.parse(str[, reviver]); ``` str 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 3d35e82f7..e539a780e 100644 --- a/1-js/06-advanced-functions/05-global-object/article.md +++ b/1-js/06-advanced-functions/05-global-object/article.md @@ -25,7 +25,11 @@ var gVar = 5; alert(window.gVar); // 5 (se torna uma propriedade do objeto global) ``` +<<<<<<< HEAD O mesmo efeito têm declarações de função (instruções com a palavra-chave `function` no fluxo principal do código, não expressões de função). +======= +Function declarations have the same effect (statements with `function` keyword in the main code flow, not function expressions). +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Por favor, não confie nisso! Esse comportamento existe por motivos de compatibilidade. Scripts modernos usam [JavaScript modules](info:modules) onde tal coisa não acontece. 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 c84f4e52f..9f62b202f 100644 --- a/1-js/06-advanced-functions/06-function-object/article.md +++ b/1-js/06-advanced-functions/06-function-object/article.md @@ -326,7 +326,11 @@ welcome(); // Hello, Guest (nested call works) Now it works, because the name `"func"` is function-local. It is not taken from outside (and not visible there). The specification guarantees that it will always reference the current function. +<<<<<<< HEAD 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. +======= +The outer code still has its variable `sayHi` or `welcome`. And `func` is an "internal function name", the way for the function to call itself reliably. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```smart header="There's no such thing for Function Declaration" The "internal name" feature described here is only available for Function Expressions, not for Function Declarations. For Function Declarations, there is no syntax for adding an "internal" name. 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 17ae38ad1..7ac7ab681 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 @@ Crie um decorador de "regulação" `throttle(f, ms)` -- que retorna uma função Quando é chamado várias vezes, este passa a chamada a `f` no máximo uma vez por `ms` milissegundos. +<<<<<<< HEAD Em comparação com o decorador de redução, o comportamento é completamente diferente: - `debounce` executa a função uma vez após o período de "arrefecimento". Bom para processar o resultado final. - `throttle` executa a função não mais frequentemente do que o tempo dado `ms`. Bom para atualizações regulares que não devem ser muito frequentes. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Por outras palavras, `throttle` é como uma secretária que aceita chamadas telefónicas, mas que incomoda a chefe (chama a verdadeira `f`) não mais do que uma vez por `ms` milissegundos. 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 403107ca6..4a381c0b4 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,5 @@ -The error occurs because `ask` gets functions `loginOk/loginFail` without the object. +The error occurs because `askPassword` gets functions `loginOk/loginFail` without the object. When it calls them, they naturally assume `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 6d65e7dd1..7a6e47b90 100644 --- a/1-js/06-advanced-functions/10-bind/article.md +++ b/1-js/06-advanced-functions/10-bind/article.md @@ -125,7 +125,7 @@ funcUser(); // John */!* ``` -Here `func.bind(user)` as a "bound variant" of `func`, with fixed `this=user`. +Here `func.bind(user)` is a "bound variant" of `func`, with fixed `this=user`. All arguments are passed to the original `func` "as is", for instance: diff --git a/1-js/08-prototypes/01-prototype-inheritance/article.md b/1-js/08-prototypes/01-prototype-inheritance/article.md index d60e186d2..d6bebf6aa 100644 --- a/1-js/08-prototypes/01-prototype-inheritance/article.md +++ b/1-js/08-prototypes/01-prototype-inheritance/article.md @@ -131,10 +131,15 @@ Só existem duas limitações: Além disso, só pode haver um `[[Prototype]]`. Um objeto não pode ser herdeiro de outros dois. +<<<<<<< HEAD ```smart header="`__proto__` é um getter/setter histórico para `[[Prototype]]`" É um erro comum, desenvolvedores novatos não saberem a diferença entre esses dois. Mas note que `__proto__` *não é o mesmo* que a propriedade interna `[[Prototype]]`. Ele é um getter/setter para o `[[Prototype]]`. Mais tarde veremos situações nas quais isso importa, por ora vamos apenar manter isso em mente enquanto construimos nossa compreensão da linguagem Javascript. +======= +```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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b A propriedade `__proto__` está um pouco ultrapassada, ela existe por motivos históricos. O Javascript moderno sugere que nós usemos as funções `Object.getPrototypeOf/Object.setPrototypeOf` no lugar, que também fazem get/set do protótipo. Nós também vamos cobrir essas funções mais tarde. diff --git a/1-js/08-prototypes/03-native-prototypes/article.md b/1-js/08-prototypes/03-native-prototypes/article.md index 77138fdf7..2c4d7d91b 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 @@ A propriedade `"prototype"` é amplamente utilizada pelo próprio núcleo do JavaScript. Todas as funções construtoras integradas o utilizam. +<<<<<<< HEAD Primeiro veremos os detalhes e depois como usá-lo para adicionar novos recursos a objetos integrados. +======= +First we'll look at the details, and then how to use it for adding new capabilities to built-in objects. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ## Object.prototype diff --git a/1-js/08-prototypes/04-prototype-methods/article.md b/1-js/08-prototypes/04-prototype-methods/article.md index 71f118e1b..b59e32765 100644 --- a/1-js/08-prototypes/04-prototype-methods/article.md +++ b/1-js/08-prototypes/04-prototype-methods/article.md @@ -14,7 +14,11 @@ The only usage of `__proto__`, that's not frowned upon, is as a property when cr Although, there's a special method for this too: +<<<<<<< HEAD - [Object.create(proto, [descriptors])](mdn:js/Object/create) -- creates an empty object with given `proto` as `[[Prototype]]` and optional property descriptors. +======= +- [Object.create(proto[, descriptors])](mdn:js/Object/create) -- creates an empty object with given `proto` as `[[Prototype]]` and optional property descriptors. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b For instance: @@ -116,7 +120,11 @@ alert(obj[key]); // [object Object], not "some value"! Here, if the user types in `__proto__`, the assignment in line 4 is ignored! +<<<<<<< HEAD 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 an assignment a string to `__proto__` 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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b But we didn't *intend* to implement such behavior, right? We want to store key/value pairs, and the key named `"__proto__"` was not properly saved. So that's a bug! @@ -201,7 +209,11 @@ alert(Object.keys(chineseDictionary)); // hello,bye - To create an object with the given prototype, use: - literal syntax: `{ __proto__: ... }`, allows to specify multiple properties +<<<<<<< HEAD - or [Object.create(proto, [descriptors])](mdn:js/Object/create), allows to specify property descriptors. +======= + - or [Object.create(proto[, descriptors])](mdn:js/Object/create), allows to specify property descriptors. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b The `Object.create` provides an easy way to shallow-copy an object with all descriptors: diff --git a/1-js/09-classes/07-mixins/article.md b/1-js/09-classes/07-mixins/article.md index 1c9a4dc38..4f1c03814 100644 --- a/1-js/09-classes/07-mixins/article.md +++ b/1-js/09-classes/07-mixins/article.md @@ -100,7 +100,11 @@ Aqui está o diagrama (veja a parte direita): Isso porque os métodos `sayHi` e `sayBye` foram inicialmente criados em `sayHiMixin`. Portanto, mesmo que tenham sido copiados, suas propriedades internas `[[HomeObject]]` referenciam a `sayHiMixin`, como mostrado na figura acima. +<<<<<<< HEAD Como `super` procura por métodos pais em `[[HomeObject]].[[Prototype]]`, isso significa que procura em `sayHiMixin.[[Prototype]]`. +======= +As `super` looks for parent methods in `[[HomeObject]].[[Prototype]]`, that means it searches `sayHiMixin.[[Prototype]]`. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ## 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 bf548373a..d3755be0f 100644 --- a/1-js/10-error-handling/1-try-catch/article.md +++ b/1-js/10-error-handling/1-try-catch/article.md @@ -632,7 +632,11 @@ For instance: The role of the global handler `window.onerror` is usually not to recover the script execution -- that's probably impossible in case of programming errors, but to send the error message to developers. +<<<<<<< HEAD There are also web-services that provide error-logging for such cases, like or . +======= +There are also web-services that provide error-logging for such cases, like or . +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b They work like this: 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 918289319..d28b07439 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 { Now let's inherit `ValidationError` from it and try it in action: -```js run untrusted +```js run *!* class ValidationError extends Error { */!* diff --git a/1-js/11-async/02-promise-basics/article.md b/1-js/11-async/02-promise-basics/article.md index 207fb2c8c..dbe095c1b 100644 --- a/1-js/11-async/02-promise-basics/article.md +++ b/1-js/11-async/02-promise-basics/article.md @@ -46,7 +46,7 @@ Later we'll see how "fans" can subscribe to these changes. Here's an example of a promise constructor and a simple executor function with "producing code" that takes time (via `setTimeout`): -```js run +```js let promise = new Promise(function(resolve, reject) { // the function is executed automatically when the promise is constructed @@ -222,7 +222,11 @@ The idea of `finally` is to set up a handler for performing cleanup/finalizing a E.g. stopping loading indicators, closing no longer needed connections, etc. +<<<<<<< HEAD Think of it as a party finisher. No matter was a party good or bad, how many friends were in it, we still need (or at least should) do a cleanup after it. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b The code may look like this: diff --git a/1-js/11-async/03-promise-chaining/article.md b/1-js/11-async/03-promise-chaining/article.md index 8c621c3b4..ec7b0c7d4 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 O que fizemos aqui é apenas utilizar uma série de tratadores em uma promessa. Eles não passam o resultado uns para os outros; pelo contrário, eles o processam de maneira independente. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Aqui está uma imagem (compare-a com a cadeia acima): @@ -224,7 +228,11 @@ Essa funcionalidade nos permite integrar objetos customizáveis com cadeias de p ## Maior exemplo: fetch +<<<<<<< HEAD Em programação frontend, promessas são com frequência utilizadas em requisições de rede. Então vamos ver um exemplo estendido disso. +======= +In frontend programming, promises are often used for network requests. So let's see an extended example of that. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Vamos usar o método [fetch](info:fetch) para carregar de um servidor remoto informações sobre o usuário. Ele possui vários parâmetros opcionais abordados em [separate chapters](info:fetch), mas a sintaxe básica é bem simples: 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/13-modules/02-import-export/article.md b/1-js/13-modules/02-import-export/article.md index bd56c3db7..c33ed44f6 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 @@ Além disso, podemos colocar `export` separadamente. Aqui primeiro declaramos e então exportamos: -```js +```js // 📁 say.js function sayHi(user) { alert(`Olá, ${user}!`); @@ -93,6 +93,7 @@ say.sayBye('John'); Bem, existem algumas razões. +<<<<<<< HEAD 1. Ferramentas modernas de build ([webpack](http://webpack.github.io) e outras) agrupam os módulos e os otimizam para acelerar o carregamento e remover itens não utilizados. Digamos que adicionamos a biblioteca externa `say.js` em nosso projeto com muitas funções: @@ -112,6 +113,16 @@ Bem, existem algumas razões. 2. Listar explicitamente o que importar nos fornece nomes mais curtos: `sayHi()` ao invés de `say.sayHi()`. 3. Uma lista explícita do que importar fornece uma visão geral melhor da estrutura do código: o que é usado e onde. Torna o código fácil de prover suporte e de refatorar. +======= +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. +``` +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ## Import "as" @@ -224,7 +235,7 @@ Sem `default`, esse export causaria um erro: export class { // Erro! (exports que não são default precisam de um nome) constructor() {} } -``` +``` ### O nome "default" @@ -326,7 +337,7 @@ Imagine, we're writing a "package": a folder with a lot of modules, with some of A estrutura de arquivos pode ser assim: ``` auth/ - index.js + index.js user.js helpers.js tests/ @@ -372,7 +383,11 @@ A sintaxe `export ... from ...` é apenas uma notação mais curta para essa imp ```js // 📁 auth/index.js +<<<<<<< HEAD // re-exportar login/logout +======= +// re-export login/logout +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b export {login, logout} from './helpers.js'; // re-exportar o 'export default' como User @@ -380,7 +395,11 @@ export {default as User} from './user.js'; ... ``` +<<<<<<< HEAD Uma diferença notável entre `export ... from` e `import/export` está em que módulos re-exportados não estão disponíveis no arquivo corrente. Assim, dentro do exemplo acima de `auth/index.js` nós não podemos utilizar funções `login/logout` re-exportadas. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ### Reexportando o export default @@ -399,11 +418,19 @@ Podemos nos deparar com dois problemas para isso: 1. `export User from './user.js'` não funcionará. Isso levaria a um erro de sintaxe. +<<<<<<< HEAD Para reexportar o export default, nós temos que escrever `export {default as User}`, como no exemplo acima. +======= + To re-export the default export, we have to write `export {default as User}`, as in the example above. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b 2. `export * from './user.js'` reexporta apenas os exports com nome, mas ignora o default. +<<<<<<< HEAD Se desejarmos reexportar tanto os export com nome e o export default, serão necessárias duas declarações: +======= + If we'd like to re-export both named and default exports, then two statements are needed: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js export * from './user.js'; // para reexportar exports com nome export {default} from './user.js'; // para reexportar o export default @@ -430,7 +457,11 @@ Import: - Importando exports com nome: - `import {x [as y], ...} from "module"` +<<<<<<< HEAD - Importando o export default: +======= +- Importing the default export: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b - `import x from "module"` - `import {default as x} from "module"` - Importar tudo: 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 e62f7e564..ac5d531dd 100644 --- a/1-js/99-js-misc/04-reference-type/article.md +++ b/1-js/99-js-misc/04-reference-type/article.md @@ -87,7 +87,11 @@ O resultado de um acesso à propriedade `user.hi` não é uma função, mas um v (user, "hi", true) ``` +<<<<<<< HEAD Quando parênteses são chamados no tipo de referência, eles recebem todas as informações sobre o objeto e o seu método, e podem definir o `this` correto (`user` nesse 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). +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b O tipo de referência é um tipo interno especial "intermediário", com o propósito de transmitir informações do ponto `.` para os parênteses de chamada `()`. diff --git a/1-js/99-js-misc/06-unicode/article.md b/1-js/99-js-misc/06-unicode/article.md index 5a4d71c7c..32bf57f4b 100644 --- a/1-js/99-js-misc/06-unicode/article.md +++ b/1-js/99-js-misc/06-unicode/article.md @@ -1,4 +1,5 @@ +<<<<<<< HEAD # Unicode, detalhes internos da String ```warn header="Conhecimento avançado" @@ -31,10 +32,45 @@ JavaScript nos permite inserir um caractere em uma string ao especificar o seu c alert( "\u00A9" ); // ©, o mesmo que \xA9, usando a notação hexadecimal de 4 dígitos alert( "\u044F" ); // я, a letra do alfabeto cirílico alert( "\u2191" ); // ↑, o símbolo da seta para cima +======= +# 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 +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ``` - `\u{X…XXXXXX}` +<<<<<<< HEAD `X...XXXXXX` deve ser um valor hexadecimal de 1 a 6 bytes entre `0` e `10FFFF` (o maior ponto de código definido pelo Unicode). Esta notação nos permite representar facilmente todos os caracteres Unicode existentes. ```js run @@ -90,20 +126,89 @@ alert( '𝒳'.charCodeAt(0).toString(16) ); // d835 alert( '𝒳'.codePointAt(0).toString(16) ); // 1d4b3, lê ambas as partes do par substituto ``` Dito isto, se partirmos da posição 1 (e isso está bastante incorreto aqui), então ambos retornam apenas a 2ª parte do par: +======= + `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: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js run alert( '𝒳'.charCodeAt(1).toString(16) ); // dcb3 alert( '𝒳'.codePointAt(1).toString(16) ); // dcb3 +<<<<<<< HEAD // segunda parte do par sem sentido ``` Você encontrará mais maneiras de lidar com pares substitutos mais tarde no capítulo . Provavelmente existem bibliotecas especiais para isso também, mas nada famoso o suficiente para sugerir aqui. ````warn header="Conclusão: dividir strings em um ponto arbitrário é perigoso" Nós não podemos simplesmente dividir uma string em uma posição arbitrária, por exemplo, pegar `str.slice(0, 4)` e esperar que seja uma string válida, por exemplo: +======= +// 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.: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js run alert( 'hi 😂'.slice(0, 4) ); // hi [?] ``` +<<<<<<< HEAD Aqui podemos ver um caractere inválido (primeira metade do par substituto) na saída. Apenas fique ciente disso se você pretende trabalhar de forma confiável com pares substitutos. Pode não ser um grande problema, mas pelo menos você deve entender o que acontece. @@ -120,19 +225,48 @@ Os caracteres "compostos" mais comuns têm seu próprio código na tabela Unicod Para auxiliar composições arbitrárias, o padrão Unicode nos permite usar vários caracteres Unicode: o caractere base seguido por um ou vários caracteres "marca" que o "decoram". Por exemplo, se tivermos `S` seguido pelo caractere especial "ponto acima" (código `\u0307`), ele será mostrado como Ṡ. +======= + +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 Ṡ. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js run alert( 'S\u0307' ); // Ṡ ``` +<<<<<<< HEAD Se precisarmos de uma marca adicional acima da letra (ou abaixo dela) -- sem problemas, apenas adicione o caractere de marca necessário. Por exemplo, se anexarmos o caractere "ponto abaixo" (código `\u0323`), então teremos "S com pontos acima e abaixo": `Ṩ`. Por exemplo: +======= + +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: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js run alert( 'S\u0307\u0323' ); // Ṩ ``` +<<<<<<< HEAD Isso fornece grande flexibilidade, mas também um problema interessante: dois caracteres podem parecer visualmente iguais, mas serem representados com diferentes composições Unicode. Por exemplo: @@ -155,13 +289,47 @@ alert( "S\u0307\u0323".normalize() == "S\u0323\u0307".normalize() ); // verdadei ``` É engraçado que na nossa situação `normalize()` realmente junta uma sequência de 3 caracteres em um: `\u1e68` (S com dois pontos). +======= + +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). +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```js run alert( "S\u0307\u0323".normalize().length ); // 1 +<<<<<<< HEAD alert( "S\u0307\u0323".normalize() == "\u1e68" ); // verdadeiro ``` Na realidade, isso nem sempre é o caso. O motivo é que o símbolo `Ṩ` é "comum o suficiente", então os criadores do Unicode o incluíram na tabela principal e deram o código. Se você deseja aprender mais sobre regras de normalização e variantes -- elas são descritas no apêndice do padrão Unicode: [Unicode Normalization Forms](https://www.unicode.org/reports/tr15/), mas para a maioria dos propósitos práticos a informação desta seção é suficiente. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b 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/04-searching-elements-dom/article.md b/2-ui/1-document/04-searching-elements-dom/article.md index 8afed40ac..c92677344 100644 --- a/2-ui/1-document/04-searching-elements-dom/article.md +++ b/2-ui/1-document/04-searching-elements-dom/article.md @@ -52,8 +52,13 @@ Além disso, existe uma variável global nomeada por `id` que referencia o eleme ``` +<<<<<<< HEAD ```warn header="Por favor, não use variáveis globais nomeadas com id para acessar elementos" Esse comportamento é descrito [na especificação](https://html.spec.whatwg.org/multipage/window-object.html#named-access-on-the-window-object), mas é suportado principalmente por questões de compatibilidade. +======= +```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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b O navegador tenta nos ajudar misturando os namespaces do JavaScript e do DOM. Isso é bom para scripts simples, inseridos diretamente no HTML, mas geralmente não é algo bom. Pode haver conflitos de nomes. Além disso, quando alguém lê o código JavaScript e não tem o HTML à vista, não é óbvio de onde a variável vem. @@ -112,7 +117,11 @@ Em outras palavras, o resultado é o mesmo que `elem.querySelectorAll(css)[0]`, Os métodos anteriores estavam procurando no DOM. +<<<<<<< HEAD O método [elem.matches(css)](https://dom.spec.whatwg.org/#dom-element-matches) não procura por nada, apenas verifica se `elem` corresponde ao seletor CSS fornecido. Ele retorna `true` ou `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`. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b O método é útil quando estamos iterando sobre elementos (como em um array ou algo do tipo) e tentando filtrar aqueles que nos interessam. @@ -149,8 +158,13 @@ Poe exemplo:
    +<<<<<<< HEAD
  • Capítulo 1
  • Capítulo 2
  • +======= +
  • Chapter 1
  • +
  • Chapter 2
  • +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
diff --git a/2-ui/1-document/06-dom-attributes-and-properties/article.md b/2-ui/1-document/06-dom-attributes-and-properties/article.md index cceb4eabb..397691493 100644 --- a/2-ui/1-document/06-dom-attributes-and-properties/article.md +++ b/2-ui/1-document/06-dom-attributes-and-properties/article.md @@ -162,7 +162,11 @@ No exemplo abaixo `id` é modificado como um atributo, e nós podemos ver a prop ``` +<<<<<<< HEAD Mas há algumas exceções, por exemplo, `input.value` sincroniza a partir de atributo -> propriedade, mas o contrário não ocorre: +======= +But there are exclusions, for instance `input.value` synchronizes only from attribute -> property, but not back: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```html run 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 35ba10611..416d9ec69 100644 --- a/2-ui/1-document/08-styles-and-classes/article.md +++ b/2-ui/1-document/08-styles-and-classes/article.md @@ -135,8 +135,25 @@ document.body.style.background = 'red'; // define a cor de fundo para vermelho setTimeout(() => document.body.style.removeProperty('background'), 1000); // remove o fundo após um segundo ``` +<<<<<<< HEAD ````smart header="Reescrita completa com `style.cssText`" Normalmente, usamos `style.*` para atribuir propriedades de estilos individuais. Não podemos definir o estilo completo como `div.style="color: red; width: 100px"`, pois `div.style` é um objeto sendo somente para leitura. +======= +If we set `style.display` to an empty string, then the browser applies CSS classes and its built-in styles normally, as if there were no such `style.display` property at all. + +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. + +To set the full style as a string, there's a special property `style.cssText`: +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b Para definir o estilo completo como uma string, existe uma propriedade especial `style.cssText`: ```html run @@ -263,8 +280,12 @@ Portanto, hoje em dia, `getComputedStyle` na verdade retorna o valor resolvido d ````warn header="`getComputedStyle` requer o nome completo da propriedade" Devemos sempre solicitar a propriedade exata que queremos, como `paddingLeft`, `marginTop` ou `borderTopWidth`. Caso contrário, o resultado correto não é garantido. +<<<<<<< HEAD Por exemplo, se existem propriedades `paddingLeft/paddingTop`, então o que deveríamos obter para `getComputedStyle(elem).padding`? Nada, ou talvez um valor "gerado" a partir de propriedades de paddings conhecidos? Não há uma regra padrão aqui. +======= +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. +>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b ```` ```smart header="Os estilos aplicados a links `:visited` são ocultados!" diff --git a/2-ui/1-document/11-coordinates/article.md b/2-ui/1-document/11-coordinates/article.md index 4775ff0eb..fc605c414 100644 --- a/2-ui/1-document/11-coordinates/article.md +++ b/2-ui/1-document/11-coordinates/article.md @@ -36,7 +36,7 @@ Additionally, there are derived properties: ```online For instance click this button to see its window coordinates: -

+