diff --git a/1-js/01-getting-started/1-intro/article.md b/1-js/01-getting-started/1-intro/article.md index a611d960..f4f921d4 100644 --- a/1-js/01-getting-started/1-intro/article.md +++ b/1-js/01-getting-started/1-intro/article.md @@ -45,7 +45,7 @@ The engine applies optimizations at each step of the process. It even watches th Modern JavaScript is a "safe" programming language. It does not provide low-level access to memory or CPU, because it was initially created for browsers which do not require it. -Javascript's capabilities greatly depend on the environment it's running in. For instance, [Node.JS](https://wikipedia.org/wiki/Node.js) supports functions that allow JavaScript to read/write arbitrary files, perform network requests, etc. +JavaScript's capabilities greatly depend on the environment it's running in. For instance, [Node.js](https://wikipedia.org/wiki/Node.js) supports functions that allow JavaScript to read/write arbitrary files, perform network requests, etc. In-browser JavaScript can do everything related to webpage manipulation, interaction with the user, and the webserver. @@ -88,7 +88,7 @@ There are at least *three* great things about JavaScript: + Simple things are done simply. + Support by all major browsers and enabled by default. ``` -Javascript is the only browser technology that combines these three things. +JavaScript is the only browser technology that combines these three things. That's what makes JavaScript unique. That's why it's the most widespread tool for creating browser interfaces. diff --git a/1-js/01-getting-started/3-devtools/article.md b/1-js/01-getting-started/3-devtools/article.md index 6aa9b7c5..ae5b3845 100644 --- a/1-js/01-getting-started/3-devtools/article.md +++ b/1-js/01-getting-started/3-devtools/article.md @@ -54,7 +54,7 @@ Now `key:Cmd+Opt+C` can toggle the console. Also, note that the new top menu ite Usually, when we put a line of code into the console, and then press `key:Enter`, it executes. -To insert multiple line, press `key:Shift+Enter`. +To insert multiple lines, press `key:Shift+Enter`. ## Summary diff --git a/1-js/02-first-steps/01-hello-world/article.md b/1-js/02-first-steps/01-hello-world/article.md index a24d3dca..d96ffd76 100644 --- a/1-js/02-first-steps/01-hello-world/article.md +++ b/1-js/02-first-steps/01-hello-world/article.md @@ -1,10 +1,10 @@ # Hello, world! -The tutorial that you're reading is about core JavaScript, which is platform-independent. Later on, you'll learn about Node.JS and other platforms that use it. +The tutorial that you're reading is about core JavaScript, which is platform-independent. Later on, you'll learn about Node.js and other platforms that use it. -But we need a working environment to run our scripts and, since this book is online, the browser is a good choice. We'll keep the amount of browser-specific commands (like `alert`) to a minimum so that you don't spend time on them if you plan to concentrate on another environment (like Node.JS). We'll focus on JavaScript in the browser in the [next part](/ui) of the tutorial. +But we need a working environment to run our scripts and, since this book is online, the browser is a good choice. We'll keep the amount of browser-specific commands (like `alert`) to a minimum so that you don't spend time on them if you plan to concentrate on another environment (like Node.js). We'll focus on JavaScript in the browser in the [next part](/ui) of the tutorial. -So first, let's see how we attach a script to a webpage. For server-side environments (like Node.JS), you can execute the script with a command like `"node my.js"`. +So first, let's see how we attach a script to a webpage. For server-side environments (like Node.js), you can execute the script with a command like `"node my.js"`. ## The "script" tag diff --git a/1-js/02-first-steps/04-variables/article.md b/1-js/02-first-steps/04-variables/article.md index dcf8a9ca..8fe13a97 100644 --- a/1-js/02-first-steps/04-variables/article.md +++ b/1-js/02-first-steps/04-variables/article.md @@ -157,7 +157,7 @@ let userName; let test123; ``` -When the name contains multiple words, [camelCase](https://en.wikipedia.org/wiki/CamelCase) is commonly used. That is: words go one after another, each word starting with a capital letter: `myVeryLongName`. +When the name contains multiple words, [camelCase](https://en.wikipedia.org/wiki/CamelCase) is commonly used. That is: words go one after another, each word except first starting with a capital letter: `myVeryLongName`. What's interesting -- the dollar sign `'$'` and the underscore `'_'` can also be used in names. They are regular symbols, just like letters, without any special meaning. diff --git a/1-js/02-first-steps/06-type-conversions/article.md b/1-js/02-first-steps/06-type-conversions/article.md index 95d0fa46..6ac695e8 100644 --- a/1-js/02-first-steps/06-type-conversions/article.md +++ b/1-js/02-first-steps/06-type-conversions/article.md @@ -1,6 +1,6 @@ # Type Conversions -Most of the time, operators and functions automatically convert the values given to them to the right type. This is called "type conversion". +Most of the time, operators and functions automatically convert the values given to them to the right type. For example, `alert` automatically converts any value to a string to show it. Mathematical operations convert values to numbers. diff --git a/1-js/02-first-steps/14-function-basics/article.md b/1-js/02-first-steps/14-function-basics/article.md index 874890ab..18833cbf 100644 --- a/1-js/02-first-steps/14-function-basics/article.md +++ b/1-js/02-first-steps/14-function-basics/article.md @@ -382,7 +382,7 @@ These examples assume common meanings of prefixes. What they mean for you is det ```smart header="Ultrashort function names" Functions that are used *very often* sometimes have ultrashort names. -For example, the [jQuery](http://jquery.com) framework defines a function with `$`. The [LoDash](http://lodash.com/) library has its core function named `_`. +For example, the [jQuery](http://jquery.com) framework defines a function with `$`. The [Lodash](http://lodash.com/) library has its core function named `_`. These are exceptions. Generally functions names should be concise and descriptive. ``` diff --git a/1-js/03-code-quality/02-coding-style/article.md b/1-js/03-code-quality/02-coding-style/article.md index 290028a8..926a772c 100644 --- a/1-js/03-code-quality/02-coding-style/article.md +++ b/1-js/03-code-quality/02-coding-style/article.md @@ -287,7 +287,7 @@ Most linters are integrated with many popular editors: just enable the plugin in For instance, for ESLint you should do the following: -1. Install [Node.JS](https://nodejs.org/). +1. Install [Node.js](https://nodejs.org/). 2. Install ESLint with the command `npm install -g eslint` (npm is a JavaScript package installer). 3. Create a config file named `.eslintrc` in the root of your JavaScript project (in the folder that contains all your files). 4. Install/enable the plugin for your editor that integrates with ESLint. The majority of editors have one. 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 a40fdf55..a2dcceb1 100644 --- a/1-js/05-data-types/01-primitives-methods/article.md +++ b/1-js/05-data-types/01-primitives-methods/article.md @@ -48,7 +48,7 @@ The solution looks a little bit awkward, but here it is: 1. Primitives are still primitive. A single value, as desired. 2. The language allows access to methods and properties of strings, numbers, booleans and symbols. -3. When this happens, a special "object wrapper" is created that provides the extra functionality, and then is destroyed. +3. When this happens, a special "object wrapper" that provides the extra functionality is created, and then is destroyed. The "object wrappers" are different for each primitive type and are called: `String`, `Number`, `Boolean` and `Symbol`. Thus, they provide different sets of methods. diff --git a/1-js/05-data-types/02-number/9-random-int-min-max/task.md b/1-js/05-data-types/02-number/9-random-int-min-max/task.md index 29341b2a..4ac7b5fb 100644 --- a/1-js/05-data-types/02-number/9-random-int-min-max/task.md +++ b/1-js/05-data-types/02-number/9-random-int-min-max/task.md @@ -12,9 +12,9 @@ Any number from the interval `min..max` must appear with the same probability. Examples of its work: ```js -alert( random(1, 5) ); // 1 -alert( random(1, 5) ); // 3 -alert( random(1, 5) ); // 5 +alert( randomInteger(1, 5) ); // 1 +alert( randomInteger(1, 5) ); // 3 +alert( randomInteger(1, 5) ); // 5 ``` You can use the solution of the [previous task](info:task/random-min-max) as the base. diff --git a/1-js/05-data-types/04-array/10-maximal-subarray/solution.md b/1-js/05-data-types/04-array/10-maximal-subarray/solution.md index edf39289..daadf494 100644 --- a/1-js/05-data-types/04-array/10-maximal-subarray/solution.md +++ b/1-js/05-data-types/04-array/10-maximal-subarray/solution.md @@ -29,8 +29,8 @@ For instance, for `[-1, 2, 3, -9, 11]`: -9 -9 + 11 -// Starting from -11 --11 +// Starting from 11 +11 ``` The code is actually a nested loop: the external loop over array elements, and the internal counts subsums starting with the current element. diff --git a/1-js/05-data-types/10-date/article.md b/1-js/05-data-types/10-date/article.md index d4c71e57..8a75f1cb 100644 --- a/1-js/05-data-types/10-date/article.md +++ b/1-js/05-data-types/10-date/article.md @@ -424,4 +424,4 @@ alert(`Loading started ${performance.now()}ms ago`); // more than 3 digits after the decimal point are precision errors, but only the first 3 are correct ``` -Node.JS has `microtime` module and other ways. Technically, any device and environment allows to get more precision, it's just not in `Date`. +Node.js has `microtime` module and other ways. Technically, any device and environment allows to get more precision, it's just not in `Date`. diff --git a/1-js/06-advanced-functions/03-closure/article.md b/1-js/06-advanced-functions/03-closure/article.md index ac0e44c6..465ba311 100644 --- a/1-js/06-advanced-functions/03-closure/article.md +++ b/1-js/06-advanced-functions/03-closure/article.md @@ -221,7 +221,7 @@ function sayHiBye(firstName, lastName) { } ``` -Here the *nested* function `getFullName()` is made for convenience. It can access the outer variables and so can return the full name. Nested functions are quite common in Javascript. +Here the *nested* function `getFullName()` is made for convenience. It can access the outer variables and so can return the full name. Nested functions are quite common in JavaScript. What's much more interesting, a nested function can be returned: either as a property of a new object (if the outer function creates an object with methods) or as a result by itself. It can then be used somewhere else. No matter where, it still has access to the same outer variables. @@ -473,7 +473,7 @@ The code outside of the block (or inside another script) doesn't see variables i ### IIFE -In the past, there were no block-level lexical environment in Javascript. +In the past, there were no block-level lexical environment in JavaScript. So programmers had to invent something. And what they did is called "immediately-invoked function expressions" (abbreviated as IIFE). 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 4d480a03..da4adc2b 100644 --- a/1-js/06-advanced-functions/05-global-object/article.md +++ b/1-js/06-advanced-functions/05-global-object/article.md @@ -3,7 +3,7 @@ The global object provides variables and functions that are available anywhere. Mostly, the ones that are built into the language or the host environment. -In a browser it is named "window", for Node.JS it is "global", for other environments it may have another name. +In a browser it is named "window", for Node.js it is "global", for other environments it may have another name. For instance, we can call `alert` as a method of `window`: @@ -79,7 +79,7 @@ No, it's not, because it may lead to naming conflicts: the same variable name ca As of now, the multi-purpose `window` is considered a design mistake in the language. -Luckily, there's a "road out of hell", called "Javascript modules". +Luckily, there's a "road out of hell", called "JavaScript modules". If we set `type="module"` attribute on a ` - - - - diff --git a/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/source.view/index.html b/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/source.view/index.html deleted file mode 100644 index fdee13d0..00000000 --- a/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/source.view/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Console clock - - - - - - - - - - diff --git a/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/task.md b/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/task.md deleted file mode 100644 index 71131816..00000000 --- a/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/task.md +++ /dev/null @@ -1,9 +0,0 @@ -importance: 5 - ---- - -# Rewrite to prototypes - -The `Clock` class is written in functional style. Rewrite it using prototypes. - -P.S. The clock ticks in the console, open it to see. diff --git a/1-js/09-classes/01-class-patterns/article.md b/1-js/09-classes/01-class-patterns/article.md deleted file mode 100644 index ca120f71..00000000 --- a/1-js/09-classes/01-class-patterns/article.md +++ /dev/null @@ -1,240 +0,0 @@ - -# Class patterns - -```quote author="Wikipedia" -In object-oriented programming, a *class* is an extensible program-code-template for creating objects, providing initial values for state (member variables) and implementations of behavior (member functions or methods). -``` - -There's a special syntax construct and a keyword `class` in JavaScript. But before studying it, we should consider that the term "class" comes from the theory of object-oriented programming. The definition is cited above, and it's language-independent. - -In JavaScript there are several well-known programming patterns to make classes even without using the `class` keyword. People talk about "classes" meaning not only those defined with `class`, but also with these patterns. - -The `class` construct will be described in the next chapter, but in JavaScript it's a "syntax sugar" and an extension of the prototypal class pattern described here. - - -## Functional class pattern - -The constructor function below can be considered a "class" according to the definition: - -```js run -function User(name) { - this.sayHi = function() { - alert(name); - }; -} - -let user = new User("John"); -user.sayHi(); // John -``` - -It follows all parts of the definition: - -1. It is a "program-code-template" for creating objects (callable with `new`). -2. It provides initial values for the state (`name` from parameters). -3. It provides methods (`sayHi`). - -This is called *functional class pattern*. - -In the functional class pattern, local variables and nested functions inside `User`, that are not assigned to `this`, are visible from inside, but not accessible by the outer code. - -So we can easily add internal functions and variables, like `calcAge()` here: - -```js run -function User(name, birthday) { -*!* - // only visible from other methods inside User - function calcAge() { - return new Date().getFullYear() - birthday.getFullYear(); - } -*/!* - - this.sayHi = function() { - alert(`${name}, age:${calcAge()}`); - }; -} - -let user = new User("John", new Date(2000, 0, 1)); -user.sayHi(); // John, age:17 -``` - -In this code variables `name`, `birthday` and the function `calcAge()` are internal, *private* to the object. They are only visible from inside of it. - -On the other hand, `sayHi` is the external, *public* method. The external code that creates `user` can access it. - -This way we can hide internal implementation details and helper methods from the outer code. Only what's assigned to `this` becomes visible outside. - -## Factory class pattern - -We can create a class without using `new` at all. - -Like this: - -```js run -function User(name, birthday) { - // only visible from other methods inside User - function calcAge() { - return new Date().getFullYear() - birthday.getFullYear(); - } - - return { - sayHi() { - alert(`${name}, age:${calcAge()}`); - } - }; -} - -*!* -let user = User("John", new Date(2000, 0, 1)); -*/!* -user.sayHi(); // John, age:17 -``` - -As we can see, the function `User` returns an object with public properties and methods. The only benefit of this method is that we can omit `new`: write `let user = User(...)` instead of `let user = new User(...)`. In other aspects it's almost the same as the functional pattern. - -## Prototype-based classes - -Prototype-based classes are the most important and generally the best. Functional and factory class patterns are rarely used in practice. - -Soon you'll see why. - -Here's the same class rewritten using prototypes: - -```js run -function User(name, birthday) { -*!* - this._name = name; - this._birthday = birthday; -*/!* -} - -*!* -User.prototype._calcAge = function() { -*/!* - return new Date().getFullYear() - this._birthday.getFullYear(); -}; - -User.prototype.sayHi = function() { - alert(`${this._name}, age:${this._calcAge()}`); -}; - -let user = new User("John", new Date(2000, 0, 1)); -user.sayHi(); // John, age:17 -``` - -The code structure: - -- The constructor `User` only initializes the current object state. -- Methods are added to `User.prototype`. - -As we can see, methods are lexically not inside `function User`, they do not share a common lexical environment. If we declare variables inside `function User`, then they won't be visible to methods. - -So, there is a widely known agreement that internal properties and methods are prepended with an underscore `"_"`. Like `_name` or `_calcAge()`. Technically, that's just an agreement, the outer code still can access them. But most developers recognize the meaning of `"_"` and try not to touch prefixed properties and methods in the external code. - -Here are the advantages over the functional pattern: - -- In the functional pattern, each object has its own copy of every method. We assign a separate copy of `this.sayHi = function() {...}` and other methods in the constructor. -- In the prototypal pattern, all methods are in `User.prototype` that is shared between all user objects. An object itself only stores the data. - -So the prototypal pattern is more memory-efficient. - -...But not only that. Prototypes allow us to setup the inheritance in a really efficient way. Built-in JavaScript objects all use prototypes. Also there's a special syntax construct: "class" that provides nice-looking syntax for them. And there's more, so let's go on with them. - -## Prototype-based inheritance for classes - -Let's say we have two prototype-based classes. - -`Rabbit`: - -```js -function Rabbit(name) { - this.name = name; -} - -Rabbit.prototype.jump = function() { - alert(`${this.name} jumps!`); -}; - -let rabbit = new Rabbit("My rabbit"); -``` - -![](rabbit-animal-independent-1.png) - -...And `Animal`: - -```js -function Animal(name) { - this.name = name; -} - -Animal.prototype.eat = function() { - alert(`${this.name} eats.`); -}; - -let animal = new Animal("My animal"); -``` - -![](rabbit-animal-independent-2.png) - -Right now they are fully independent. - -But we'd want `Rabbit` to extend `Animal`. In other words, rabbits should be based on animals, have access to methods of `Animal` and extend them with its own methods. - -What does it mean in the language of prototypes? - -Right now methods for `rabbit` objects are in `Rabbit.prototype`. We'd like `rabbit` to use `Animal.prototype` as a "fallback", if the method is not found in `Rabbit.prototype`. - -So the prototype chain should be `rabbit` -> `Rabbit.prototype` -> `Animal.prototype`. - -Like this: - -![](class-inheritance-rabbit-animal.png) - -The code to implement that: - -```js run -// Same Animal as before -function Animal(name) { - this.name = name; -} - -// All animals can eat, right? -Animal.prototype.eat = function() { - alert(`${this.name} eats.`); -}; - -// Same Rabbit as before -function Rabbit(name) { - this.name = name; -} - -Rabbit.prototype.jump = function() { - alert(`${this.name} jumps!`); -}; - -*!* -// setup the inheritance chain -Rabbit.prototype.__proto__ = Animal.prototype; // (*) -*/!* - -let rabbit = new Rabbit("White Rabbit"); -*!* -rabbit.eat(); // rabbits can eat too -*/!* -rabbit.jump(); -``` - -The line `(*)` sets up the prototype chain. So that `rabbit` first searches methods in `Rabbit.prototype`, then `Animal.prototype`. And then, just for completeness, let's mention that if the method is not found in `Animal.prototype`, then the search continues in `Object.prototype`, because `Animal.prototype` is a regular plain object, so it inherits from it. - -So here's the full picture: - -![](class-inheritance-rabbit-animal-2.png) - -## Summary - -The term "class" comes from the object-oriented programming. In JavaScript it usually means the functional class pattern or the prototypal pattern. The prototypal pattern is more powerful and memory-efficient, so it's recommended to stick to it. - -According to the prototypal pattern: -1. Methods are stored in `Class.prototype`. -2. Prototypes inherit from each other. - -In the next chapter we'll study `class` keyword and construct. It allows to write prototypal classes shorter and provides some additional benefits. diff --git a/1-js/09-classes/01-class-patterns/rabbit-animal-independent-1.png b/1-js/09-classes/01-class-patterns/rabbit-animal-independent-1.png deleted file mode 100644 index f4a11d6c..00000000 Binary files a/1-js/09-classes/01-class-patterns/rabbit-animal-independent-1.png and /dev/null differ diff --git a/1-js/09-classes/01-class-patterns/rabbit-animal-independent-1@2x.png b/1-js/09-classes/01-class-patterns/rabbit-animal-independent-1@2x.png deleted file mode 100644 index 60451263..00000000 Binary files a/1-js/09-classes/01-class-patterns/rabbit-animal-independent-1@2x.png and /dev/null differ diff --git a/1-js/09-classes/01-class-patterns/rabbit-animal-independent-2.png b/1-js/09-classes/01-class-patterns/rabbit-animal-independent-2.png deleted file mode 100644 index 7dfee817..00000000 Binary files a/1-js/09-classes/01-class-patterns/rabbit-animal-independent-2.png and /dev/null differ diff --git a/1-js/09-classes/01-class-patterns/rabbit-animal-independent-2@2x.png b/1-js/09-classes/01-class-patterns/rabbit-animal-independent-2@2x.png deleted file mode 100644 index 473c2d29..00000000 Binary files a/1-js/09-classes/01-class-patterns/rabbit-animal-independent-2@2x.png and /dev/null differ diff --git a/1-js/09-classes/03-class-inheritance/2-clock-class-extended/source.view/clock.js b/1-js/09-classes/01-class/1-rewrite-to-class/_js.view/solution.js similarity index 91% rename from 1-js/09-classes/03-class-inheritance/2-clock-class-extended/source.view/clock.js rename to 1-js/09-classes/01-class/1-rewrite-to-class/_js.view/solution.js index d701c0ca..0b31cf33 100644 --- a/1-js/09-classes/03-class-inheritance/2-clock-class-extended/source.view/clock.js +++ b/1-js/09-classes/01-class/1-rewrite-to-class/_js.view/solution.js @@ -32,3 +32,7 @@ class Clock { this.timer = setInterval(() => this.render(), 1000); } } + + +let clock = new Clock({template: 'h:m:s'}); +clock.start(); diff --git a/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/source.view/clock.js b/1-js/09-classes/01-class/1-rewrite-to-class/_js.view/source.js similarity index 90% rename from 1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/source.view/clock.js rename to 1-js/09-classes/01-class/1-rewrite-to-class/_js.view/source.js index c4bfaa0f..f1749c8b 100644 --- a/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/source.view/clock.js +++ b/1-js/09-classes/01-class/1-rewrite-to-class/_js.view/source.js @@ -32,3 +32,6 @@ function Clock({ template }) { }; } + +let clock = new Clock({template: 'h:m:s'}); +clock.start(); diff --git a/1-js/09-classes/02-class/1-rewrite-to-class/solution.md b/1-js/09-classes/01-class/1-rewrite-to-class/solution.md similarity index 100% rename from 1-js/09-classes/02-class/1-rewrite-to-class/solution.md rename to 1-js/09-classes/01-class/1-rewrite-to-class/solution.md diff --git a/1-js/09-classes/02-class/1-rewrite-to-class/task.md b/1-js/09-classes/01-class/1-rewrite-to-class/task.md similarity index 53% rename from 1-js/09-classes/02-class/1-rewrite-to-class/task.md rename to 1-js/09-classes/01-class/1-rewrite-to-class/task.md index a29d347f..05365e41 100644 --- a/1-js/09-classes/02-class/1-rewrite-to-class/task.md +++ b/1-js/09-classes/01-class/1-rewrite-to-class/task.md @@ -4,6 +4,6 @@ importance: 5 # Rewrite to class -Rewrite the `Clock` class from prototypes to the modern "class" syntax. +The `Clock` class is written in functional style. Rewrite it the "class" syntax. P.S. The clock ticks in the console, open it to see. diff --git a/1-js/09-classes/01-class/article.md b/1-js/09-classes/01-class/article.md new file mode 100644 index 00000000..d78d0091 --- /dev/null +++ b/1-js/09-classes/01-class/article.md @@ -0,0 +1,368 @@ + +# Class basic syntax + +```quote author="Wikipedia" +In object-oriented programming, a *class* is an extensible program-code-template for creating objects, providing initial values for state (member variables) and implementations of behavior (member functions or methods). +``` + +In practice, we often need to create many objects of the same kind, like users, or goods or whatever. + +As we already know from the chapter , `new function` can help with that. + +But in the modern JavaScript, there's a more advanced "class" construct, that introduces great new features which are useful for object-oriented programming. + +## The "class" syntax + +The basic syntax is: +```js +class MyClass { + // class methods + constructor() { ... } + method1() { ... } + method2() { ... } + method3() { ... } + ... +} +``` + +Then `new MyClass()` creates a new object with all the listed methods. + +The `constructor()` method is called automatically by `new`, so we can initialize the object there. + +For example: + +```js run +class User { + + constructor(name) { + this.name = name; + } + + sayHi() { + alert(this.name); + } + +} + +// Usage: +let user = new User("John"); +user.sayHi(); +``` + +When `new User("John")` is called: +1. A new object is created. +2. The `constructor` runs with the given argument and assigns `this.name` to it. + +...Then we can call methods, such as `user.sayHi`. + + +```warn header="No comma between class methods" +A common pitfall for novice developers is to put a comma between class methods, which would result in a syntax error. + +The notation here is not to be confused with object literals. Within the class, no commas are required. +``` + +## What is a class? + +So, what exactly is a `class`? That's not an entirely new language-level entity, as one might think. + +Let's unveil any magic and see what a class really is. That'll help in understanding many complex aspects. + +In JavaScript, a class is a kind of a function. + +Here, take a look: + +```js run +class User { + constructor(name) { this.name = name; } + sayHi() { alert(this.name); } +} + +// proof: User is a function +*!* +alert(typeof User); // function +*/!* +``` + +What `class User {...}` construct really does is: +1. Creates a function named `User`, that becomes the result of the class declaration. + - The function code is taken from the `constructor` method (assumed empty if we don't write such method). +3. Stores all methods, such as `sayHi`, in `User.prototype`. + +Afterwards, for new objects, when we call a method, it's taken from the prototype, just as described in the chapter . So `new User` object has access to class methods. + +We can illustrate the result of `class User` as: + +![](class-user.png) + +Here's the code to introspect it: + + +```js run +class User { + constructor(name) { this.name = name; } + sayHi() { alert(this.name); } +} + +// class is a function +alert(typeof User); // function + +// ...or, more precisely, the constructor method +alert(User === User.prototype.constructor); // true + +// The methods are in User.prototype, e.g: +alert(User.prototype.sayHi); // alert(this.name); + +// there are exactly two methods in the prototype +alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi +``` + +## Not just a syntax sugar + +Sometimes people say that `class` is a "syntax sugar" in JavaScript, because we could actually declare the same without `class` keyword at all: + +```js run +// rewriting class User in pure functions + +// 1. Create constructor function +function User(name) { + this.name = name; +} +// any function prototype has constructor property by default, +// so we don't need to create it + +// 2. Add the method to prototype +User.prototype.sayHi = function() { + alert(this.name); +}; + +// Usage: +let user = new User("John"); +user.sayHi(); +``` + +The result of this definition is about the same. So, there are indeed reasons why `class` can be considered a syntax sugar to define a constructor together with its prototype methods. + +Although, there are important differences. + +1. First, a function created by `class` is labelled by a special internal property `[[FunctionKind]]:"classConstructor"`. So it's not entirely the same as creating it manually. + + Unlike a regular function, a class constructor can't be called without `new`: + + ```js run + class User { + constructor() {} + } + + alert(typeof User); // function + User(); // Error: Class constructor User cannot be invoked without 'new' + ``` + + Also, a string representation of a class constructor in most JavaScript engines starts with the "class..." + + ```js run + class User { + constructor() {} + } + + alert(User); // class User { ... } + ``` + +2. Class methods are non-enumerable + A class definition sets `enumerable` flag to `false` for all methods in the `"prototype"`. + + That's good, because if we `for..in` over an object, we usually don't want its class methods. + +3. Classes always `use strict` + All code inside the class construct is automatically in strict mode. + + +Also, in addition to its basic operation, the `class` syntax brings many other features with it which we'll explore later. + +## Class Expression + +Just like functions, classes can be defined inside another expression, passed around, returned, assigned etc. + +Here's an example of a class expression: + +```js +let User = class { + sayHi() { + alert("Hello"); + } +}; +``` + +Similar to Named Function Expressions, class expressions may or may not have a name. + +If a class expression has a name, it's visible inside the class only: + +```js run +// "Named Class Expression" (alas, no such term, but that's what's going on) +let User = class *!*MyClass*/!* { + sayHi() { + alert(MyClass); // MyClass is visible only inside the class + } +}; + +new User().sayHi(); // works, shows MyClass definition + +alert(MyClass); // error, MyClass not visible outside of the class +``` + + +We can even make classes dynamically "on-demand", like this: + +```js run +function makeClass(phrase) { + // declare a class and return it + return class { + sayHi() { + alert(phrase); + }; + }; +} + +// Create a new class +let User = makeClass("Hello"); + +new User().sayHi(); // Hello +``` + + +## Getters/setters, other shorthands + +Classes also include getters/setters, generators, computed properties etc. + +Here's an example for `user.name` implemented using `get/set`: + +```js run +class User { + + constructor(name) { + // invokes the setter + this._name = name; + } + +*!* + get name() { +*/!* + return this._name; + } + +*!* + set name(value) { +*/!* + if (value.length < 4) { + alert("Name is too short."); + return; + } + this._name = value; + } + +} + +let user = new User("John"); +alert(user.name); // John + +user = new User(""); // Name too short. +``` + +Internally, getters and setters are created on `User.prototype`, like this: + +```js +Object.defineProperties(User.prototype, { + name: { + get() { + return this._name + }, + set(name) { + // ... + } + } +}); +``` + +Here's an example with computed properties: + +```js run +function f() { return "sayHi"; } + +class User { + [f()]() { + alert("Hello"); + } + +} + +new User().sayHi(); +``` + +For a generator method, similarly, prepend it with `*`. + +## Class properties + +```warn header="Old browsers may need a polyfill" +Class-level properties are a recent addition to the language. +``` + +In the example above, `User` only had methods. Let's add a property: + +```js run +class User { + name = "Anonymous"; + + sayHi() { + alert(`Hello, ${this.name}!`); + } +} + +new User().sayHi(); +``` + +The property is not placed into `User.prototype`. Instead, it is created by `new`, separately for every object. So, the property will never be shared between different objects of the same class. + + +## Summary + +JavaScript provides many ways to create a class. + +First, as per the general object-oriented terminology, a class is something that provides "object templates", allows to create same-structured objects. + +When we say "a class", that doesn't necessary means the `class` keyword. + +This is a class: + +```js +function User(name) { + this.sayHi = function() { + alert(name); + } +} +``` + +...But in most cases `class` keyword is used, as it provides great syntax and many additional features. + +The basic class syntax looks like this: + +```js +class MyClass { + prop = value; // field + + constructor(...) { // constructor + // ... + } + + method(...) {} // method + + get something(...) {} // getter method + set something(...) {} // setter method + + [Symbol.iterator]() {} // method with computed name/symbol name + // ... +} +``` + +`MyClass` is technically a function, while methods are written to `MyClass.prototype`. + +In the next chapters we'll learn more about classes, including inheritance and other features. diff --git a/1-js/09-classes/02-class/class-user.png b/1-js/09-classes/01-class/class-user.png similarity index 100% rename from 1-js/09-classes/02-class/class-user.png rename to 1-js/09-classes/01-class/class-user.png diff --git a/1-js/09-classes/02-class/class-user@2x.png b/1-js/09-classes/01-class/class-user@2x.png similarity index 100% rename from 1-js/09-classes/02-class/class-user@2x.png rename to 1-js/09-classes/01-class/class-user@2x.png diff --git a/1-js/09-classes/03-class-inheritance/1-class-constructor-error/solution.md b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/solution.md similarity index 100% rename from 1-js/09-classes/03-class-inheritance/1-class-constructor-error/solution.md rename to 1-js/09-classes/02-class-inheritance/1-class-constructor-error/solution.md diff --git a/1-js/09-classes/03-class-inheritance/1-class-constructor-error/task.md b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md similarity index 100% rename from 1-js/09-classes/03-class-inheritance/1-class-constructor-error/task.md rename to 1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md diff --git a/1-js/09-classes/03-class-inheritance/2-clock-class-extended/solution.md b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.md similarity index 100% rename from 1-js/09-classes/03-class-inheritance/2-clock-class-extended/solution.md rename to 1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.md diff --git a/1-js/09-classes/02-class/1-rewrite-to-class/solution.view/clock.js b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/clock.js similarity index 100% rename from 1-js/09-classes/02-class/1-rewrite-to-class/solution.view/clock.js rename to 1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/clock.js diff --git a/1-js/09-classes/03-class-inheritance/2-clock-class-extended/solution.view/extended-clock.js b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/extended-clock.js similarity index 100% rename from 1-js/09-classes/03-class-inheritance/2-clock-class-extended/solution.view/extended-clock.js rename to 1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/extended-clock.js diff --git a/1-js/09-classes/03-class-inheritance/2-clock-class-extended/solution.view/index.html b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/index.html similarity index 100% rename from 1-js/09-classes/03-class-inheritance/2-clock-class-extended/solution.view/index.html rename to 1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/index.html diff --git a/1-js/09-classes/03-class-inheritance/2-clock-class-extended/solution.view/clock.js b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/clock.js similarity index 100% rename from 1-js/09-classes/03-class-inheritance/2-clock-class-extended/solution.view/clock.js rename to 1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/clock.js diff --git a/1-js/09-classes/03-class-inheritance/2-clock-class-extended/source.view/index.html b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/index.html similarity index 100% rename from 1-js/09-classes/03-class-inheritance/2-clock-class-extended/source.view/index.html rename to 1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/index.html diff --git a/1-js/09-classes/03-class-inheritance/2-clock-class-extended/task.md b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/task.md similarity index 100% rename from 1-js/09-classes/03-class-inheritance/2-clock-class-extended/task.md rename to 1-js/09-classes/02-class-inheritance/2-clock-class-extended/task.md diff --git a/1-js/09-classes/03-class-inheritance/3-class-extend-object/rabbit-extends-object.png b/1-js/09-classes/02-class-inheritance/3-class-extend-object/rabbit-extends-object.png similarity index 100% rename from 1-js/09-classes/03-class-inheritance/3-class-extend-object/rabbit-extends-object.png rename to 1-js/09-classes/02-class-inheritance/3-class-extend-object/rabbit-extends-object.png diff --git a/1-js/09-classes/03-class-inheritance/3-class-extend-object/rabbit-extends-object@2x.png b/1-js/09-classes/02-class-inheritance/3-class-extend-object/rabbit-extends-object@2x.png similarity index 100% rename from 1-js/09-classes/03-class-inheritance/3-class-extend-object/rabbit-extends-object@2x.png rename to 1-js/09-classes/02-class-inheritance/3-class-extend-object/rabbit-extends-object@2x.png diff --git a/1-js/09-classes/03-class-inheritance/3-class-extend-object/solution.md b/1-js/09-classes/02-class-inheritance/3-class-extend-object/solution.md similarity index 100% rename from 1-js/09-classes/03-class-inheritance/3-class-extend-object/solution.md rename to 1-js/09-classes/02-class-inheritance/3-class-extend-object/solution.md diff --git a/1-js/09-classes/03-class-inheritance/3-class-extend-object/task.md b/1-js/09-classes/02-class-inheritance/3-class-extend-object/task.md similarity index 100% rename from 1-js/09-classes/03-class-inheritance/3-class-extend-object/task.md rename to 1-js/09-classes/02-class-inheritance/3-class-extend-object/task.md diff --git a/1-js/09-classes/02-class-inheritance/animal-rabbit-extends.png b/1-js/09-classes/02-class-inheritance/animal-rabbit-extends.png new file mode 100644 index 00000000..0d887dbc Binary files /dev/null and b/1-js/09-classes/02-class-inheritance/animal-rabbit-extends.png differ diff --git a/1-js/09-classes/02-class-inheritance/animal-rabbit-extends@2x.png b/1-js/09-classes/02-class-inheritance/animal-rabbit-extends@2x.png new file mode 100644 index 00000000..af09271a Binary files /dev/null and b/1-js/09-classes/02-class-inheritance/animal-rabbit-extends@2x.png differ diff --git a/1-js/09-classes/03-class-inheritance/article.md b/1-js/09-classes/02-class-inheritance/article.md similarity index 88% rename from 1-js/09-classes/03-class-inheritance/article.md rename to 1-js/09-classes/02-class-inheritance/article.md index 1541a965..7d00d9bd 100644 --- a/1-js/09-classes/03-class-inheritance/article.md +++ b/1-js/09-classes/02-class-inheritance/article.md @@ -1,7 +1,53 @@ # Class inheritance -Classes can extend one another. There's a nice syntax, technically based on the prototypal inheritance. +Let's say we have two classes. + +`Animal`: + +```js +class Animal { + constructor(name) { + this.speed = 0; + this.name = name; + } + run(speed) { + this.speed += speed; + alert(`${this.name} runs with speed ${this.speed}.`); + } + stop() { + this.speed = 0; + alert(`${this.name} stopped.`); + } +} + +let animal = new Animal("My animal"); +``` + +![](rabbit-animal-independent-animal.png) + + +...And `Rabbit`: + +```js +class Rabbit { + constructor(name) { + this.name = name; + } + hide() { + alert(`${this.name} hides!`); + } +} + +let rabbit = new Rabbit("My rabbit"); +``` + +![](rabbit-animal-independent-rabbit.png) + + +Right now they are fully independent. + +But we'd want `Rabbit` to extend `Animal`. In other words, rabbits should be based on animals, have access to methods of `Animal` and extend them with its own methods. To inherit from another class, we should specify `"extends"` and the parent class before the brackets `{..}`. @@ -9,32 +55,28 @@ Here `Rabbit` inherits from `Animal`: ```js run class Animal { - constructor(name) { this.speed = 0; this.name = name; } - run(speed) { this.speed += speed; alert(`${this.name} runs with speed ${this.speed}.`); } - stop() { this.speed = 0; alert(`${this.name} stopped.`); } - } +// Inherit from Animal by specifying "extends Animal" *!* -// Inherit from Animal class Rabbit extends Animal { +*/!* hide() { alert(`${this.name} hides!`); } } -*/!* let rabbit = new Rabbit("White Rabbit"); @@ -42,11 +84,15 @@ rabbit.run(5); // White Rabbit runs with speed 5. rabbit.hide(); // White Rabbit hides! ``` -The `extends` keyword actually adds a `[[Prototype]]` reference from `Rabbit.prototype` to `Animal.prototype`, just as you expect it to be, and as we've seen before. +Now the `Rabbit` code became a bit shorter, as it uses `Animal` constructor by default, and it also can `run`, as animals do. + +Internally, `extends` keyword adds `[[Prototype]]` reference from `Rabbit.prototype` to `Animal.prototype`: ![](animal-rabbit-extends.png) -So now `rabbit` has access both to its own methods and to methods of `Animal`. +So, if a method is not found in `Rabbit.prototype`, JavaScript takes it from `Animal.prototype`. + +As we can recall from the chapter , JavaScript uses the same prototypal inheritance for build-in objects. E.g. `Date.prototype.[[Prototype]]` is `Object.prototype`, so dates have generic object methods. ````smart header="Any expression is allowed after `extends`" Class syntax allows to specify not just a class, but any expression after `extends`. diff --git a/1-js/09-classes/03-class-inheritance/class-inheritance-array-object.png b/1-js/09-classes/02-class-inheritance/class-inheritance-array-object.png similarity index 100% rename from 1-js/09-classes/03-class-inheritance/class-inheritance-array-object.png rename to 1-js/09-classes/02-class-inheritance/class-inheritance-array-object.png diff --git a/1-js/09-classes/03-class-inheritance/class-inheritance-array-object@2x.png b/1-js/09-classes/02-class-inheritance/class-inheritance-array-object@2x.png similarity index 100% rename from 1-js/09-classes/03-class-inheritance/class-inheritance-array-object@2x.png rename to 1-js/09-classes/02-class-inheritance/class-inheritance-array-object@2x.png diff --git a/1-js/09-classes/01-class-patterns/class-inheritance-rabbit-animal-2.png b/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal-2.png similarity index 100% rename from 1-js/09-classes/01-class-patterns/class-inheritance-rabbit-animal-2.png rename to 1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal-2.png diff --git a/1-js/09-classes/01-class-patterns/class-inheritance-rabbit-animal-2@2x.png b/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal-2@2x.png similarity index 100% rename from 1-js/09-classes/01-class-patterns/class-inheritance-rabbit-animal-2@2x.png rename to 1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal-2@2x.png diff --git a/1-js/09-classes/01-class-patterns/class-inheritance-rabbit-animal.png b/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal.png similarity index 100% rename from 1-js/09-classes/01-class-patterns/class-inheritance-rabbit-animal.png rename to 1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal.png diff --git a/1-js/09-classes/01-class-patterns/class-inheritance-rabbit-animal@2x.png b/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal@2x.png similarity index 100% rename from 1-js/09-classes/01-class-patterns/class-inheritance-rabbit-animal@2x.png rename to 1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal@2x.png diff --git a/1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-run-animal.png b/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-run-animal.png similarity index 100% rename from 1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-run-animal.png rename to 1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-run-animal.png diff --git a/1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-run-animal@2x.png b/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-run-animal@2x.png similarity index 100% rename from 1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-run-animal@2x.png rename to 1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-run-animal@2x.png diff --git a/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-animal.png b/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-animal.png new file mode 100644 index 00000000..79351a75 Binary files /dev/null and b/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-animal.png differ diff --git a/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-animal@2x.png b/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-animal@2x.png new file mode 100644 index 00000000..346574e0 Binary files /dev/null and b/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-animal@2x.png differ diff --git a/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-rabbit.png b/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-rabbit.png new file mode 100644 index 00000000..3d3b78cc Binary files /dev/null and b/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-rabbit.png differ diff --git a/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-rabbit@2x.png b/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-rabbit@2x.png new file mode 100644 index 00000000..a923d10e Binary files /dev/null and b/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-rabbit@2x.png differ diff --git a/1-js/09-classes/03-class-inheritance/this-super-loop.png b/1-js/09-classes/02-class-inheritance/this-super-loop.png similarity index 100% rename from 1-js/09-classes/03-class-inheritance/this-super-loop.png rename to 1-js/09-classes/02-class-inheritance/this-super-loop.png diff --git a/1-js/09-classes/03-class-inheritance/this-super-loop@2x.png b/1-js/09-classes/02-class-inheritance/this-super-loop@2x.png similarity index 100% rename from 1-js/09-classes/03-class-inheritance/this-super-loop@2x.png rename to 1-js/09-classes/02-class-inheritance/this-super-loop@2x.png diff --git a/1-js/09-classes/02-class/1-rewrite-to-class/solution.view/index.html b/1-js/09-classes/02-class/1-rewrite-to-class/solution.view/index.html deleted file mode 100644 index fdee13d0..00000000 --- a/1-js/09-classes/02-class/1-rewrite-to-class/solution.view/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Console clock - - - - - - - - - - diff --git a/1-js/09-classes/02-class/1-rewrite-to-class/source.view/clock.js b/1-js/09-classes/02-class/1-rewrite-to-class/source.view/clock.js deleted file mode 100644 index 537f7268..00000000 --- a/1-js/09-classes/02-class/1-rewrite-to-class/source.view/clock.js +++ /dev/null @@ -1,34 +0,0 @@ - - -function Clock({ template }) { - this.template = template; -} - -Clock.prototype.render = function() { - let date = new Date(); - - let hours = date.getHours(); - if (hours < 10) hours = '0' + hours; - - let mins = date.getMinutes(); - if (mins < 10) mins = '0' + mins; - - let secs = date.getSeconds(); - if (secs < 10) secs = '0' + secs; - - let output = this.template - .replace('h', hours) - .replace('m', mins) - .replace('s', secs); - - console.log(output); -}; - -Clock.prototype.stop = function() { - clearInterval(this.timer); -}; - -Clock.prototype.start = function() { - this.render(); - this.timer = setInterval(() => this.render(), 1000); -}; diff --git a/1-js/09-classes/02-class/1-rewrite-to-class/source.view/index.html b/1-js/09-classes/02-class/1-rewrite-to-class/source.view/index.html deleted file mode 100644 index fdee13d0..00000000 --- a/1-js/09-classes/02-class/1-rewrite-to-class/source.view/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Console clock - - - - - - - - - - diff --git a/1-js/09-classes/02-class/article.md b/1-js/09-classes/02-class/article.md deleted file mode 100644 index 74a6e808..00000000 --- a/1-js/09-classes/02-class/article.md +++ /dev/null @@ -1,272 +0,0 @@ - -# Classes - -The "class" construct allows one to define prototype-based classes with a clean, nice-looking syntax. It also introduces great new features which are useful for object-oriented programming. - -## The "class" syntax - -The `class` syntax is versatile, we'll start with a simple example first. - -Here's a prototype-based class `User`: - -```js run -function User(name) { - this.name = name; -} - -User.prototype.sayHi = function() { - alert(this.name); -} - -let user = new User("John"); -user.sayHi(); -``` - -...And here's the same using `class` syntax: - -```js run -class User { - - constructor(name) { - this.name = name; - } - - sayHi() { - alert(this.name); - } - -} - -let user = new User("John"); -user.sayHi(); -``` - -It's easy to see that these two examples are alike. Be sure to note that methods in a class do not have a comma between them. A common pitfall for novice developers is to put a comma between class methods, which would result in a syntax error. The notation here is not to be confused with object literals. Within the class syntactical sugar, no commas are required. - -## What is a class? - -So, what exactly is a `class`? We may think that it defines a new language-level entity, but that would be wrong. - -In Javascript, a class is a kind of function. - -The definition `class User {...}` creates a function under the same name and puts the methods into `User.prototype`. So the structure is similar. - -This is demonstrated in the following code, which you can run yourself: - -```js run -class User { - constructor(name) { this.name = name; } - sayHi() { alert(this.name); } -} - -*!* -// proof: User is a function -alert(typeof User); // function -*/!* - -*!* -// proof: User is the "constructor" function -*/!* -alert(User === User.prototype.constructor); // true - -*!* -// proof: there are two methods in its "prototype" -*/!* -alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi -``` - -Abstractly, we can illustrate this process of `class User` creating a function as: - -![](class-user.png) - -`Class` is a special syntax to define a constructor together with its prototype methods. In addition to its basic operation, the `Class` syntax brings many other features with it which we'll explore later. - -## Class Expression - -Just like functions, classes can be defined inside another expression, passed around, returned etc. - -Here's a class-returning function - otherwise known as a "class factory": - -```js run -function makeClass(phrase) { -*!* - // declare a class and return it - return class { - sayHi() { - alert(phrase); - }; - }; -*/!* -} - -let User = makeClass("Hello"); - -new User().sayHi(); // Hello -``` - -That's quite normal if we recall that `class` is just a special form of a function-with-prototype definition. - -And, like Named Function Expressions, such classes also may have a name, that is visible inside that class only: - -```js run -// "Named Class Expression" (alas, no such term, but that's what's going on) -let User = class *!*MyClass*/!* { - sayHi() { - alert(MyClass); // MyClass is visible only inside the class - } -}; - -new User().sayHi(); // works, shows MyClass definition - -alert(MyClass); // error, MyClass not visible outside of the class -``` - -## Differences between classes and functions - -Classes have some differences compared to regular functions: - -Constructors require `new` -: Unlike a regular function, a class `constructor` can't be called without `new`: - -```js run -class User { - constructor() {} -} - -alert(typeof User); // function -User(); // Error: Class constructor User cannot be invoked without 'new' -``` - -Different string output -: If we output it like `alert(User)`, some engines show `"class User..."`, while others show `"function User..."`. - -Please don't be confused: the string representation may vary, but that's still a function, there is no separate "class" entity in JavaScript language. - -Class methods are non-enumerable -: A class definition sets `enumerable` flag to `false` for all methods in the `"prototype"`. That's good, because if we `for..in` over an object, we usually don't want its class methods. - -Classes have a default `constructor() {}` -: If there's no `constructor` in the `class` construct, then an empty function is generated, just as if we had written `constructor() {}`. - -Classes always `use strict` -: All code inside the class construct is automatically in strict mode. - - -## Getters/setters, other shorthands - -Classes also include getters/setters, generators, computed properties etc. - -Here's an example for `user.name` implemented using `get/set`: - -```js run -class User { - - constructor(name) { - // invokes the setter - this._name = name; - } - -*!* - get name() { -*/!* - return this._name; - } - -*!* - set name(value) { -*/!* - if (value.length < 4) { - alert("Name is too short."); - return; - } - this._name = value; - } - -} - -let user = new User("John"); -alert(user.name); // John - -user = new User(""); // Name too short. -``` - -Internally, getters and setters are created on `User.prototype`, like this: - -```js -Object.defineProperties(User.prototype, { - name: { - get() { - return this._name - }, - set(name) { - // ... - } - } -}); -``` - -Here's an example with computed properties: - -```js run -function f() { return "sayHi"; } - -class User { - [f()]() { - alert("Hello"); - } - -} - -new User().sayHi(); -``` - -For a generator method, similarly, prepend it with `*`. - -## Class properties - -```warn header="Old browsers may need a polyfill" -Class-level properties are a recent addition to the language. -``` - -In the example above, `User` only had methods. Let's add a property: - -```js run -class User { - name = "Anonymous"; - - sayHi() { - alert(`Hello, ${this.name}!`); - } -} - -new User().sayHi(); -``` - -The property is not placed into `User.prototype`. Instead, it is created by `new`, separately for every object. So, the property will never be shared between different objects of the same class. - - -## Summary - -The basic class syntax looks like this: - -```js -class MyClass { - prop = value; - - constructor(...) { - // ... - } - - method(...) {} - - get something(...) {} - set something(...) {} - - [Symbol.iterator]() {} - // ... -} -``` - -`MyClass` is technically a function, while methods are written to `MyClass.prototype`. - -In the next chapters we'll learn more about classes, including inheritance and other features. diff --git a/1-js/09-classes/03-class-inheritance/animal-rabbit-extends.png b/1-js/09-classes/03-class-inheritance/animal-rabbit-extends.png deleted file mode 100644 index c9fadf77..00000000 Binary files a/1-js/09-classes/03-class-inheritance/animal-rabbit-extends.png and /dev/null differ diff --git a/1-js/09-classes/03-class-inheritance/animal-rabbit-extends@2x.png b/1-js/09-classes/03-class-inheritance/animal-rabbit-extends@2x.png deleted file mode 100644 index 95979c2f..00000000 Binary files a/1-js/09-classes/03-class-inheritance/animal-rabbit-extends@2x.png and /dev/null differ diff --git a/1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-animal.png b/1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-animal.png deleted file mode 100644 index a6f8964e..00000000 Binary files a/1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-animal.png and /dev/null differ diff --git a/1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-animal@2x.png b/1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-animal@2x.png deleted file mode 100644 index 2e3f4d7f..00000000 Binary files a/1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-animal@2x.png and /dev/null differ diff --git a/1-js/09-classes/04-static-properties-methods/animal-rabbit-static.png b/1-js/09-classes/03-static-properties-methods/animal-rabbit-static.png similarity index 100% rename from 1-js/09-classes/04-static-properties-methods/animal-rabbit-static.png rename to 1-js/09-classes/03-static-properties-methods/animal-rabbit-static.png diff --git a/1-js/09-classes/04-static-properties-methods/animal-rabbit-static@2x.png b/1-js/09-classes/03-static-properties-methods/animal-rabbit-static@2x.png similarity index 100% rename from 1-js/09-classes/04-static-properties-methods/animal-rabbit-static@2x.png rename to 1-js/09-classes/03-static-properties-methods/animal-rabbit-static@2x.png diff --git a/1-js/09-classes/04-static-properties-methods/article.md b/1-js/09-classes/03-static-properties-methods/article.md similarity index 100% rename from 1-js/09-classes/04-static-properties-methods/article.md rename to 1-js/09-classes/03-static-properties-methods/article.md diff --git a/1-js/09-classes/05-private-protected-properties-methods/article.md b/1-js/09-classes/04-private-protected-properties-methods/article.md similarity index 97% rename from 1-js/09-classes/05-private-protected-properties-methods/article.md rename to 1-js/09-classes/04-private-protected-properties-methods/article.md index 7f891aba..6cd9cc5f 100644 --- a/1-js/09-classes/05-private-protected-properties-methods/article.md +++ b/1-js/09-classes/04-private-protected-properties-methods/article.md @@ -55,9 +55,9 @@ In JavaScript, there are three types of properties and members: In many other languages there also exist "protected" fields: accessible only from inside the class and those extending it. They are also useful for the internal interface. They are in a sense more widespread than private ones, because we usually want inheriting classes to gain access to properly do the extension. -Protected fields are not implemented in Javascript on the language level, but in practice they are very convenient, so they are emulated. +Protected fields are not implemented in JavaScript on the language level, but in practice they are very convenient, so they are emulated. -In the next step we'll make a coffee machine in Javascript with all these types of properties. A coffee machine has a lot of details, we won't model them to stay simple (though we could). +In the next step we'll make a coffee machine in JavaScript with all these types of properties. A coffee machine has a lot of details, we won't model them to stay simple (though we could). ## Protecting "waterAmount" @@ -186,7 +186,7 @@ So protected fields are naturally inheritable. Unlike private ones that we'll se [recent browser=none] -There's a finished Javascript proposal, almost in the standard, that provides language-level support for private properties and methods. +There's a finished JavaScript proposal, almost in the standard, that provides language-level support for private properties and methods. Privates should start with `#`. They are only accessible from inside the class. @@ -325,6 +325,6 @@ Hiding complexity To hide internal interface we use either protected or public properties: - Protected fields start with `_`. That's a well-known convention, not enforced at the language level. Programmers should only access a field starting with `_` from its class and classes inheriting from it. -- Private fields start with `#`. Javascript makes sure we only can access those from inside the class. +- Private fields start with `#`. JavaScript makes sure we only can access those from inside the class. Right now, private fields are not well-supported among browsers, but can be polyfilled. diff --git a/1-js/09-classes/05-private-protected-properties-methods/coffee-inside.jpg b/1-js/09-classes/04-private-protected-properties-methods/coffee-inside.jpg similarity index 100% rename from 1-js/09-classes/05-private-protected-properties-methods/coffee-inside.jpg rename to 1-js/09-classes/04-private-protected-properties-methods/coffee-inside.jpg diff --git a/1-js/09-classes/05-private-protected-properties-methods/coffee.jpg b/1-js/09-classes/04-private-protected-properties-methods/coffee.jpg similarity index 100% rename from 1-js/09-classes/05-private-protected-properties-methods/coffee.jpg rename to 1-js/09-classes/04-private-protected-properties-methods/coffee.jpg diff --git a/1-js/09-classes/06-extend-natives/article.md b/1-js/09-classes/05-extend-natives/article.md similarity index 100% rename from 1-js/09-classes/06-extend-natives/article.md rename to 1-js/09-classes/05-extend-natives/article.md diff --git a/1-js/09-classes/06-extend-natives/object-date-inheritance.png b/1-js/09-classes/05-extend-natives/object-date-inheritance.png similarity index 100% rename from 1-js/09-classes/06-extend-natives/object-date-inheritance.png rename to 1-js/09-classes/05-extend-natives/object-date-inheritance.png diff --git a/1-js/09-classes/06-extend-natives/object-date-inheritance@2x.png b/1-js/09-classes/05-extend-natives/object-date-inheritance@2x.png similarity index 100% rename from 1-js/09-classes/06-extend-natives/object-date-inheritance@2x.png rename to 1-js/09-classes/05-extend-natives/object-date-inheritance@2x.png diff --git a/1-js/09-classes/07-instanceof/1-strange-instanceof/solution.md b/1-js/09-classes/06-instanceof/1-strange-instanceof/solution.md similarity index 100% rename from 1-js/09-classes/07-instanceof/1-strange-instanceof/solution.md rename to 1-js/09-classes/06-instanceof/1-strange-instanceof/solution.md diff --git a/1-js/09-classes/07-instanceof/1-strange-instanceof/task.md b/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md similarity index 100% rename from 1-js/09-classes/07-instanceof/1-strange-instanceof/task.md rename to 1-js/09-classes/06-instanceof/1-strange-instanceof/task.md diff --git a/1-js/09-classes/07-instanceof/article.md b/1-js/09-classes/06-instanceof/article.md similarity index 100% rename from 1-js/09-classes/07-instanceof/article.md rename to 1-js/09-classes/06-instanceof/article.md diff --git a/1-js/09-classes/07-instanceof/instanceof.png b/1-js/09-classes/06-instanceof/instanceof.png similarity index 100% rename from 1-js/09-classes/07-instanceof/instanceof.png rename to 1-js/09-classes/06-instanceof/instanceof.png diff --git a/1-js/09-classes/07-instanceof/instanceof@2x.png b/1-js/09-classes/06-instanceof/instanceof@2x.png similarity index 100% rename from 1-js/09-classes/07-instanceof/instanceof@2x.png rename to 1-js/09-classes/06-instanceof/instanceof@2x.png diff --git a/1-js/09-classes/08-mixins/article.md b/1-js/09-classes/07-mixins/article.md similarity index 100% rename from 1-js/09-classes/08-mixins/article.md rename to 1-js/09-classes/07-mixins/article.md diff --git a/1-js/09-classes/08-mixins/head.html b/1-js/09-classes/07-mixins/head.html similarity index 100% rename from 1-js/09-classes/08-mixins/head.html rename to 1-js/09-classes/07-mixins/head.html diff --git a/1-js/09-classes/08-mixins/mixin-inheritance.png b/1-js/09-classes/07-mixins/mixin-inheritance.png similarity index 100% rename from 1-js/09-classes/08-mixins/mixin-inheritance.png rename to 1-js/09-classes/07-mixins/mixin-inheritance.png diff --git a/1-js/09-classes/08-mixins/mixin-inheritance@2x.png b/1-js/09-classes/07-mixins/mixin-inheritance@2x.png similarity index 100% rename from 1-js/09-classes/08-mixins/mixin-inheritance@2x.png rename to 1-js/09-classes/07-mixins/mixin-inheritance@2x.png 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 fbf674fb..79729358 100644 --- a/1-js/10-error-handling/1-try-catch/article.md +++ b/1-js/10-error-handling/1-try-catch/article.md @@ -590,7 +590,7 @@ Let's imagine we've got a fatal error outside of `try..catch`, and the script di Is there a way to react on such occurrences? We may want to log the error, show something to the user (normally they don't see error messages) etc. -There is none in the specification, but environments usually provide it, because it's really useful. For instance, Node.JS has [process.on('uncaughtException')](https://nodejs.org/api/process.html#process_event_uncaughtexception) for that. And in the browser we can assign a function to special [window.onerror](mdn:api/GlobalEventHandlers/onerror) property. It will run in case of an uncaught error. +There is none in the specification, but environments usually provide it, because it's really useful. For instance, Node.js has [process.on('uncaughtException')](https://nodejs.org/api/process.html#process_event_uncaughtexception) for that. And in the browser we can assign a function to special [window.onerror](mdn:api/GlobalEventHandlers/onerror) property. It will run in case of an uncaught error. The syntax: diff --git a/1-js/11-async/02-promise-basics/article.md b/1-js/11-async/02-promise-basics/article.md index 05bbcd23..c4bb84eb 100644 --- a/1-js/11-async/02-promise-basics/article.md +++ b/1-js/11-async/02-promise-basics/article.md @@ -214,7 +214,7 @@ The call `.catch(f)` is a complete analog of `.then(null, f)`, it's just a short ### finally -Just like there's a finally clause in a regular `try {...} catch {...}`, there's `finally` in promises. +Just like there's a `finally` clause in a regular `try {...} catch {...}`, there's `finally` in promises. The call `.finally(f)` is similar to `.then(f, f)` in the sense that it always runs when the promise is settled: be it resolve or reject. diff --git a/1-js/11-async/04-promise-error-handling/article.md b/1-js/11-async/04-promise-error-handling/article.md index f5d6578a..ca67202a 100644 --- a/1-js/11-async/04-promise-error-handling/article.md +++ b/1-js/11-async/04-promise-error-handling/article.md @@ -292,7 +292,7 @@ If an error occurs, and there's no `.catch`, the `unhandledrejection` handler tr Usually such errors are unrecoverable, so our best way out is to inform the user about the problem and probably report the incident to the server. -In non-browser environments like Node.JS there are other similar ways to track unhandled errors. +In non-browser environments like Node.js there are other similar ways to track unhandled errors. ## Summary diff --git a/1-js/11-async/07-microtask-queue/article.md b/1-js/11-async/07-microtask-queue/article.md index dbbe5191..993042e5 100644 --- a/1-js/11-async/07-microtask-queue/article.md +++ b/1-js/11-async/07-microtask-queue/article.md @@ -30,7 +30,7 @@ As said in the [specification](https://tc39.github.io/ecma262/#sec-jobs-and-job- - The queue is first-in-first-out: tasks enqueued first are run first. - Execution of a task is initiated only when nothing else is running. -Or, to say that simply, when a promise is ready, its `.then/catch/finally` handlers are put into the queue. They are not executed yet. Javascript engine takes a task from the queue and executes it, when it becomes free from the current code. +Or, to say that simply, when a promise is ready, its `.then/catch/finally` handlers are put into the queue. They are not executed yet. JavaScript engine takes a task from the queue and executes it, when it becomes free from the current code. That's why "code finished" in the example above shows first. @@ -54,7 +54,7 @@ Now the order is as intended. ## Event loop -In-browser Javascript, as well as Node.js, is based on an *event loop*. +In-browser JavaScript, as well as Node.js, is based on an *event loop*. "Event loop" is a process when the engine sleeps and waits for events, then reacts on those and sleeps again. diff --git a/1-js/11-async/08-async-await/article.md b/1-js/11-async/08-async-await/article.md index 79e51ccf..041a5a46 100644 --- a/1-js/11-async/08-async-await/article.md +++ b/1-js/11-async/08-async-await/article.md @@ -12,7 +12,7 @@ async function f() { } ``` -The word "async" before a function means one simple thing: a function always returns a promise. Even If a function actually returns a non-promise value, prepending the function definition with the "async" keyword directs Javascript to automatically wrap that value in a resolved promise. +The word "async" before a function means one simple thing: a function always returns a promise. Even If a function actually returns a non-promise value, prepending the function definition with the "async" keyword directs JavaScript to automatically wrap that value in a resolved promise. For instance, the code above returns a resolved promise with the result of `1`, let's test it: diff --git a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md index eb1a1da0..c2ac5318 100644 --- a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md +++ b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md @@ -5,7 +5,7 @@ There are many areas where we need random data. One of them is testing. We may need random data: text, numbers etc, to test things out well. -In Javascript, we could use `Math.random()`. But if something goes wrong, we'd like to be able to repeat the test, using exactly the same data. +In JavaScript, we could use `Math.random()`. But if something goes wrong, we'd like to be able to repeat the test, using exactly the same data. For that, so called "seeded pseudo-random generators" are used. They take a "seed", the first value, and then generate next ones using a formula. So that the same seed yields the same sequence, and hence the whole flow is easily reproducible. We only need to remember the seed to repeat it. diff --git a/1-js/12-generators-iterators/1-generators/article.md b/1-js/12-generators-iterators/1-generators/article.md index df5e91a9..93a53777 100644 --- a/1-js/12-generators-iterators/1-generators/article.md +++ b/1-js/12-generators-iterators/1-generators/article.md @@ -462,7 +462,7 @@ If we don't catch the error there, then, as usual, it falls through to the outer - Inside generators (only) there exists a `yield` operator. - The outer code and the generator may exchange results via `next/yield` calls. -In modern Javascript, generators are rarely used. But sometimes they come in handy, because the ability of a function to exchange data with the calling code during the execution is quite unique. +In modern JavaScript, generators are rarely used. But sometimes they come in handy, because the ability of a function to exchange data with the calling code during the execution is quite unique. Also, in the next chapter we'll learn async generators, which are used to read streams of asynchronously generated data in `for` loop. diff --git a/1-js/12-generators-iterators/2-async-iterators-generators/article.md b/1-js/12-generators-iterators/2-async-iterators-generators/article.md index ad393677..45cf7393 100644 --- a/1-js/12-generators-iterators/2-async-iterators-generators/article.md +++ b/1-js/12-generators-iterators/2-async-iterators-generators/article.md @@ -1,5 +1,5 @@ -# Async iteration and generators +# Async iterators and generators Asynchronous iterators allow to iterate over data that comes asynchronously, on-demand. @@ -130,7 +130,7 @@ That's natural, as it expects to find `Symbol.iterator`, same as `for..of` witho ## Async generators -Javascript also provides generators, that are also iterable. +JavaScript also provides generators, that are also iterable. Let's recall a sequence generator from the chapter [](info:generators). It generates a sequence of values from `start` to `end` (could be anything else): @@ -264,7 +264,7 @@ So far we've seen simple examples, to gain basic understanding. Now let's review There are many online APIs that deliver paginated data. For instance, when we need a list of users, then we can fetch it page-by-page: a request returns a pre-defined count (e.g. 100 users), and provides an URL to the next page. -The pattern is very common, it's not about users, but just about anything. For instance, Github allows to retrieve commits in the same, paginated fashion: +The pattern is very common, it's not about users, but just about anything. For instance, GitHub allows to retrieve commits in the same, paginated fashion: - We should make a request to URL in the form `https://api.github.com/repos//commits`. - It responds with a JSON of 30 commits, and also provides a link to the next page in the `Link` header. @@ -273,7 +273,7 @@ The pattern is very common, it's not about users, but just about anything. For i What we'd like to have is an iterable source of commits, so that we could use it like this: ```js -let repo = 'iliakan/javascript-tutorial-en'; // Github repository to get commits from +let repo = 'javascript-tutorial/en.javascript.info'; // GitHub repository to get commits from for await (let commit of fetchCommits(repo)) { // process commit @@ -308,9 +308,9 @@ async function* fetchCommits(repo) { } ``` -1. We use the browser `fetch` method to download from a remote URL. It allows to supply authorization and other headers if needed, here Github requires `User-Agent`. +1. We use the browser `fetch` method to download from a remote URL. It allows to supply authorization and other headers if needed, here GitHub requires `User-Agent`. 2. The fetch result is parsed as JSON, that's again a `fetch`-specific method. -3. We can get the next page URL from the `Link` header of the response. It has a special format, so we use a regexp for that. The next page URL may look like this: `https://api.github.com/repositories/93253246/commits?page=2`, it's generatd by Github itself. +3. We can get the next page URL from the `Link` header of the response. It has a special format, so we use a regexp for that. The next page URL may look like this: `https://api.github.com/repositories/93253246/commits?page=2`, it's generatd by GitHub itself. 4. Then we yield all commits received, and when they finish -- the next `while(url)` iteration will trigger, making one more request. An example of use (shows commit authors in console): @@ -320,7 +320,7 @@ An example of use (shows commit authors in console): let count = 0; - for await (const commit of fetchCommits('iliakan/javascript-tutorial-en')) { + for await (const commit of fetchCommits('javascript-tutorial/en.javascript.info')) { console.log(commit.author.login); @@ -358,4 +358,4 @@ In web-development we often meet streams of data, when it flows chunk-by-chunk. We could use async generators to process such data, but there's also another API called Streams, that may be more convenient, as it provides special interfaces to transform the data and to pass it from one stream to another (e.g. download from one place and immediately send elsewhere). But they are also more complex. -Streams API not a part of Javascript language standard. Streams and async generators complement each other, both are great ways to handle async data flows. +Streams API not a part of JavaScript language standard. Streams and async generators complement each other, both are great ways to handle async data flows. diff --git a/1-js/13-modules/01-modules-intro/article.md b/1-js/13-modules/01-modules-intro/article.md index 19601e16..ad4f2106 100644 --- a/1-js/13-modules/01-modules-intro/article.md +++ b/1-js/13-modules/01-modules-intro/article.md @@ -4,14 +4,14 @@ As our application grows bigger, we want to split it into multiple files, so called 'modules'. A module usually contains a class or a library of useful functions. -For a long time, Javascript existed without a language-level module syntax. That wasn't a problem, because initially scripts were small and simple. So there was no need. +For a long time, JavaScript existed without a language-level module syntax. That wasn't a problem, because initially scripts were small and simple. So there was no need. But eventually scripts became more and more complex, so the community invented a variety of ways to organize code into modules. For instance: - [AMD](https://en.wikipedia.org/wiki/Asynchronous_module_definition) -- one of the most ancient module systems, initially implemented by the library [require.js](http://requirejs.org/). -- [CommonJS](http://wiki.commonjs.org/wiki/Modules/1.1) -- the module system created for Node.JS server. +- [CommonJS](http://wiki.commonjs.org/wiki/Modules/1.1) -- the module system created for Node.js server. - [UMD](https://github.com/umdjs/umd) -- one more module system, suggested as a universal one, compatible with AMD and CommonJS. Now all these slowly become a part of history, but we still can find them in old scripts. The language-level module system appeared in the standard in 2015, gradually evolved since then, and is now supported by all major browsers and in Node.js. @@ -56,7 +56,7 @@ The browser automatically fetches and evaluates imports, then runs the script. What's different in modules, compared to "regular" scripts? -There are core features, valid both for browser and server-side Javascript. +There are core features, valid both for browser and server-side JavaScript. ### Always "use strict" @@ -105,7 +105,7 @@ If we really need to make a "global" in-browser variable, we can explicitly assi ### A module code is evaluated only the first time when imported -If a same module is imported into multiple other places, it's code is executed only the first time, then exports are given to all importers. +If the same module is imported into multiple other places, its code is executed only the first time, then exports are given to all importers. That has important consequences. Let's see that on examples. @@ -222,7 +222,7 @@ In a module, top-level `this` is undefined, as opposed to a global object in non There are also several browser-specific differences of scripts with `type="module"` compared to regular ones. -You may want skip those for now if you're reading for the first time, or if you don't use Javascript in a browser. +You may want skip those for now if you're reading for the first time, or if you don't use JavaScript in a browser. ### Module scripts are deferred @@ -259,7 +259,7 @@ Please note: the second script actually works before the first! So we'll see `un That's because modules are deferred, so way wait for the document to be processed. The regular scripts runs immediately, so we saw its output first. -When using modules, we should be aware that HTML-document can show up before the Javascript application is ready. Some functionality may not work yet. We should put transparent overlays or "loading indicators", or otherwise ensure that the visitor won't be confused because of it. +When using modules, we should be aware that HTML-document can show up before the JavaScript application is ready. Some functionality may not work yet. We should put transparent overlays or "loading indicators", or otherwise ensure that the visitor won't be confused because of it. ### Async works on inline scripts @@ -350,7 +350,7 @@ Build tools do the following: - Unreachable code removed. - Unused exports removed ("tree-shaking"). - Development-specific statements like `console` and `debugger` removed. - - Modern, bleeding-edge Javascript syntax may be transformed to older one with similar functionality using [Babel](https://babeljs.io/). + - Modern, bleeding-edge JavaScript syntax may be transformed to older one with similar functionality using [Babel](https://babeljs.io/). - The resulting file is minified (spaces removed, variables replaced with shorter named etc). That said, native modules are also usable. So we won't be using Webpack here: you can configure it later. diff --git a/1-js/13-modules/02-import-export/article.md b/1-js/13-modules/02-import-export/article.md index 1e1df336..bf31065b 100644 --- a/1-js/13-modules/02-import-export/article.md +++ b/1-js/13-modules/02-import-export/article.md @@ -29,7 +29,7 @@ For instance, here all exports are valid: ````smart header="No semicolons after export class/function" Please note that `export` before a class or a function does not make it a [function expression](info:function-expressions-arrows). It's still a function declaration, albeit exported. -Most Javascript style guides recommend semicolons after statements, but not after function and class declarations. +Most JavaScript style guides recommend semicolons after statements, but not after function and class declarations. That's why there should be no semicolons at the end of `export class` and `export function`. @@ -355,7 +355,7 @@ export {login, logout}; import User from './user.js'; export {User}; -import Githib from './providers/github.js'; +import Github from './providers/github.js'; export {Github}; ... ``` @@ -370,7 +370,7 @@ export {login, logout} from './helpers.js'; export {default as User} from './user.js'; -export {default as Githib} from './providers/github.js'; +export {default as Github} from './providers/github.js'; ... ``` diff --git a/2-ui/1-document/01-browser-environment/article.md b/2-ui/1-document/01-browser-environment/article.md index 2266a2de..6ff17f9b 100644 --- a/2-ui/1-document/01-browser-environment/article.md +++ b/2-ui/1-document/01-browser-environment/article.md @@ -4,7 +4,7 @@ The JavaScript language was initially created for web browsers. Since then, it h A platform may be a browser, or a web-server, or a washing machine, or another *host*. Each of them provides platform-specific functionality. The JavaScript specification calls that a *host environment*. -A host environment provides platform-specific objects and functions additional to the language core. Web browsers give a means to control web pages. Node.JS provides server-side features, and so on. +A host environment provides platform-specific objects and functions additional to the language core. Web browsers give a means to control web pages. Node.js provides server-side features, and so on. Here's a bird's-eye view of what we have when JavaScript runs in a web-browser: 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 4ddc8db0..18ce24eb 100644 --- a/2-ui/1-document/04-searching-elements-dom/article.md +++ b/2-ui/1-document/04-searching-elements-dom/article.md @@ -1,13 +1,14 @@ -# Searching: getElement* and querySelector* +# Searching: getElement*, querySelector* DOM navigation properties are great when elements are close to each other. What if they are not? How to get an arbitrary element of the page? There are additional searching methods for that. + ## document.getElementById or just id If an element has the `id` attribute, then there's a global variable by the name from that `id`. -We can use it to access the element, like this: +We can use it to immediately access the element no matter where it is: ```html run
@@ -24,7 +25,9 @@ We can use it to access the element, like this: ``` -That's unless we declare the same-named variable by our own: +The behavior is described [in the specification](http://www.whatwg.org/specs/web-apps/current-work/#dom-window-nameditem), but it is supported mainly for compatibility. The browser tries to help us by mixing namespaces of JS and DOM. Good for very simple scripts, but there may be name conflicts. Also, when we look in JS and don't have HTML in view, it's not obvious where the variable comes from. + +If we declare a variable with the same name, it takes precedence: ```html run untrusted height=0
@@ -36,8 +39,6 @@ That's unless we declare the same-named variable by our own: ``` -The behavior is described [in the specification](http://www.whatwg.org/specs/web-apps/current-work/#dom-window-nameditem), but it is supported mainly for compatibility. The browser tries to help us by mixing namespaces of JS and DOM. Good for very simple scripts, but there may be name conflicts. Also, when we look in JS and don't have HTML in view, it's not obvious where the variable comes from. - The better alternative is to use a special method `document.getElementById(id)`. For instance: @@ -68,104 +69,9 @@ If there are multiple elements with the same `id`, then the behavior of correspo The method `getElementById` that can be called only on `document` object. It looks for the given `id` in the whole document. ``` -## getElementsBy* - -There are also other methods to look for nodes: - -- `elem.getElementsByTagName(tag)` looks for elements with the given tag and returns the collection of them. The `tag` parameter can also be a star `"*"` for "any tags". - -For instance: -```js -// get all divs in the document -let divs = document.getElementsByTagName('div'); -``` - -This method is callable in the context of any DOM element. - -Let's find all `input` tags inside the table: - -```html run height=50 - - - - - - -
Your age: - - - -
- - -``` - -```warn header="Don't forget the `\"s\"` letter!" -Novice developers sometimes forget the letter `"s"`. That is, they try to call `getElementByTagName` instead of getElementsByTagName. - -The `"s"` letter is absent in `getElementById`, because it returns a single element. But `getElementsByTagName` returns a collection of elements, so there's `"s"` inside. -``` - -````warn header="It returns a collection, not an element!" -Another widespread novice mistake is to write: - -```js -// doesn't work -document.getElementsByTagName('input').value = 5; -``` - -That won't work, because it takes a *collection* of inputs and assigns the value to it rather than to elements inside it. - -We should either iterate over the collection or get an element by its index, and then assign, like this: - -```js -// should work (if there's an input) -document.getElementsByTagName('input')[0].value = 5; -``` -```` - -There are also other rarely used methods of this kind: - -- `elem.getElementsByClassName(className)` returns elements that have the given CSS class. Elements may have other classes too. -- `document.getElementsByName(name)` returns elements with the given `name` attribute, document-wide. Exists for historical reasons, very rarely used, we mention it here only for completeness. - -For instance: - -```html run height=50 -
-
Article
-
Long article
-
- - -``` - ## querySelectorAll [#querySelectorAll] -Now goes the heavy artillery. - -The call to `elem.querySelectorAll(css)` returns all elements inside `elem` matching the given CSS selector. That's the most often used and powerful method. +By far, the most versatile method, `elem.querySelectorAll(css)` returns all elements inside `elem` matching the given CSS selector. Here we look for all `
  • ` elements that are last children: @@ -195,7 +101,6 @@ This method is indeed powerful, because any CSS selector can be used. Pseudo-classes in the CSS selector like `:hover` and `:active` are also supported. For instance, `document.querySelectorAll(':hover')` will return the collection with elements that the pointer is over now (in nesting order: from the outermost `` to the most nested one). ``` - ## querySelector [#querySelector] The call to `elem.querySelector(css)` returns the first element for the given CSS selector. @@ -230,9 +135,7 @@ For instance: ## closest -All elements that are directly above the given one are called its *ancestors*. - -In other words, ancestors are: parent, the parent of parent, its parent and so on. The ancestors together form the chain of parents from the element to the top. +*Ancestors* of an element are: parent, the parent of parent, its parent and so on. The ancestors together form the chain of parents from the element to the top. The method `elem.closest(css)` looks the nearest ancestor that matches the CSS-selector. The `elem` itself is also included in the search. @@ -260,6 +163,98 @@ For instance: ``` +## getElementsBy* + +There are also other methods to look for nodes by a tag, class, etc. + +Today, they are mostly history, as `querySelector` is more powerful and shorter to write. + +So here we cover them mainly for completeness, while you can still find them in the old scripts. + +- `elem.getElementsByTagName(tag)` looks for elements with the given tag and returns the collection of them. The `tag` parameter can also be a star `"*"` for "any tags". +- `elem.getElementsByClassName(className)` returns elements that have the given CSS class. Elements may have other classes too. +- `document.getElementsByName(name)` returns elements with the given `name` attribute, document-wide. very rarely used. + +For instance: +```js +// get all divs in the document +let divs = document.getElementsByTagName('div'); +``` + +Let's find all `input` tags inside the table: + +```html run height=50 + + + + + + +
    Your age: + + + +
    + + +``` + +```warn header="Don't forget the `\"s\"` letter!" +Novice developers sometimes forget the letter `"s"`. That is, they try to call `getElementByTagName` instead of getElementsByTagName. + +The `"s"` letter is absent in `getElementById`, because it returns a single element. But `getElementsByTagName` returns a collection of elements, so there's `"s"` inside. +``` + +````warn header="It returns a collection, not an element!" +Another widespread novice mistake is to write: + +```js +// doesn't work +document.getElementsByTagName('input').value = 5; +``` + +That won't work, because it takes a *collection* of inputs and assigns the value to it rather than to elements inside it. + +We should either iterate over the collection or get an element by its index, and then assign, like this: + +```js +// should work (if there's an input) +document.getElementsByTagName('input')[0].value = 5; +``` +```` + +Looking for `.article` elements: + +```html run height=50 +
    +
    Article
    +
    Long article
    +
    + + +``` + ## Live collections All methods `"getElementsBy*"` return a *live* collection. Such collections always reflect the current state of the document and "auto-update" when it changes. @@ -327,6 +322,18 @@ There are 6 main methods to search for nodes in DOM: +querySelector +CSS-selector +✔ +- + + +querySelectorAll +CSS-selector +✔ +- + + getElementById id - @@ -350,24 +357,10 @@ There are 6 main methods to search for nodes in DOM: ✔ ✔ - -querySelector -CSS-selector -✔ -- - - -querySelectorAll -CSS-selector -✔ -- - -Please note that methods `getElementById` and `getElementsByName` can only be called in the context of the document: `document.getElementById(...)`. But not on an element: `elem.getElementById(...)` would cause an error. - -Other methods can be called on elements too. For instance `elem.querySelectorAll(...)` will search inside `elem` (in the DOM subtree). +By far the most used are `querySelector` and `querySelectorAll`, but `getElementBy*` can be sporadically helpful or found in the old scripts. Besides that: diff --git a/2-ui/1-document/07-modifying-document/10-clock-setinterval/task.md b/2-ui/1-document/07-modifying-document/10-clock-setinterval/task.md index 70bc2ae9..a1b53e33 100644 --- a/2-ui/1-document/07-modifying-document/10-clock-setinterval/task.md +++ b/2-ui/1-document/07-modifying-document/10-clock-setinterval/task.md @@ -8,4 +8,4 @@ Create a colored clock like here: [iframe src="solution" height=60] -Use HTML/CSS for the styling, Javascript only updates time in elements. +Use HTML/CSS for the styling, JavaScript only updates time in elements. diff --git a/2-ui/2-events/index.md b/2-ui/2-events/index.md index 07f06fdd..f4996083 100644 --- a/2-ui/2-events/index.md +++ b/2-ui/2-events/index.md @@ -1,3 +1,3 @@ -# Introduction into Events +# Introduction to Events An introduction to browser events, event properties and handling patterns. diff --git a/2-ui/5-loading/01-onload-ondomcontentloaded/article.md b/2-ui/5-loading/01-onload-ondomcontentloaded/article.md index 06772873..2d60aa1d 100644 --- a/2-ui/5-loading/01-onload-ondomcontentloaded/article.md +++ b/2-ui/5-loading/01-onload-ondomcontentloaded/article.md @@ -75,7 +75,7 @@ In the example above, we first see "Library loaded...", and then "DOM ready!" (a ```warn header="Scripts with `async`, `defer` or `type=\"module\"` don't block DOMContentLoaded" -Script attributes `async` and `defer`, that we'll cover [a bit later](info:script-async-defer), don't block DOMContentLoaded. [Javascript modules](info:modules) behave like `defer`, they don't block it too. +Script attributes `async` and `defer`, that we'll cover [a bit later](info:script-async-defer), don't block DOMContentLoaded. [JavaScript modules](info:modules) behave like `defer`, they don't block it too. So here we're talking about "regular" scripts, like ``, or ``. ``` diff --git a/2-ui/5-loading/02-script-async-defer/article.md b/2-ui/5-loading/02-script-async-defer/article.md index a5ce0ac4..f5c3faeb 100644 --- a/2-ui/5-loading/02-script-async-defer/article.md +++ b/2-ui/5-loading/02-script-async-defer/article.md @@ -129,7 +129,7 @@ Async scripts are great when we integrate an independant third-party script into ## Dynamic scripts -We can also create a script dynamically using Javascript: +We can also create a script dynamically using JavaScript: ```js run let script = document.createElement('script'); diff --git a/2-ui/5-loading/03-onload-onerror/article.md b/2-ui/5-loading/03-onload-onerror/article.md index 7ff1d3de..e915dedb 100644 --- a/2-ui/5-loading/03-onload-onerror/article.md +++ b/2-ui/5-loading/03-onload-onerror/article.md @@ -23,7 +23,7 @@ document.head.append(script); ...But how to run the function that is declared inside that script? We need to wait until the script loads, and only then we can call it. ```smart -For our own scripts we could use [Javascript modules](info:modules) here, but they are not widely adopted by third-party libraries. +For our own scripts we could use [JavaScript modules](info:modules) here, but they are not widely adopted by third-party libraries. ``` ### script.onload diff --git a/3-frames-and-windows/03-cross-window-communication/article.md b/3-frames-and-windows/03-cross-window-communication/article.md index b4166e20..53cb3cd6 100644 --- a/3-frames-and-windows/03-cross-window-communication/article.md +++ b/3-frames-and-windows/03-cross-window-communication/article.md @@ -246,7 +246,7 @@ The purpose of the `"sandbox"` attribute is only to *add more* restrictions. It The `postMessage` interface allows windows to talk to each other no matter which origin they are from. -So, it's a way around the "Same Origin" policy. It allows a window from `john-smith.com` to talk to `gmail.com` and exchange information, but only if they both agree and call corresponding Javascript functions. That makes it safe for users. +So, it's a way around the "Same Origin" policy. It allows a window from `john-smith.com` to talk to `gmail.com` and exchange information, but only if they both agree and call corresponding JavaScript functions. That makes it safe for users. The interface has two parts. diff --git a/4-binary/01-arraybuffer-binary-arrays/article.md b/4-binary/01-arraybuffer-binary-arrays/article.md index 5f9dec79..d0bb488d 100644 --- a/4-binary/01-arraybuffer-binary-arrays/article.md +++ b/4-binary/01-arraybuffer-binary-arrays/article.md @@ -2,12 +2,12 @@ In web-development we meet binary data mostly while dealing with files (create, upload, download). Another typical use case is image processing. -That's all possible in Javascript, and binary operations are high-performant. +That's all possible in JavaScript, and binary operations are high-performant. Although, there's a bit of confusion, because there are many classes. To name a few: - `ArrayBuffer`, `Uint8Array`, `DataView`, `Blob`, `File`, etc. -Binary data in Javascript is implemented in a non-standard way, compared to other languages. But when we sort things out, everything becomes fairly simple. +Binary data in JavaScript is implemented in a non-standard way, compared to other languages. But when we sort things out, everything becomes fairly simple. **The basic binary object is `ArrayBuffer` -- a reference to a fixed-length contiguos memory area.** @@ -144,7 +144,7 @@ Here's the list of typed arrays: - `Float32Array`, `Float64Array` -- for signed floating-point numbers of 32 and 64 bits. ```warn header="No `int8` or similar single-valued types" -Please note, despite of the names like `Int8Array`, there's no single-value type like `int`, or `int8` in Javascript. +Please note, despite of the names like `Int8Array`, there's no single-value type like `int`, or `int8` in JavaScript. That's logical, as `Int8Array` is not an array of these individual values, but rather a view on `ArrayBuffer`. ``` diff --git a/4-binary/02-text-decoder/article.md b/4-binary/02-text-decoder/article.md index 709a99d5..9287279e 100644 --- a/4-binary/02-text-decoder/article.md +++ b/4-binary/02-text-decoder/article.md @@ -2,7 +2,7 @@ What if the binary data is actually a string? For instance, we received a file with textual data. -The build-in [TextDecoder](https://encoding.spec.whatwg.org/#interface-textdecoder) object allows to read the value into an an actual Javascript string, given the buffer and the encoding. +The build-in [TextDecoder](https://encoding.spec.whatwg.org/#interface-textdecoder) object allows to read the value into an an actual JavaScript string, given the buffer and the encoding. We first need to create it: ```js diff --git a/4-binary/03-blob/article.md b/4-binary/03-blob/article.md index 0cfdab10..d75973ea 100644 --- a/4-binary/03-blob/article.md +++ b/4-binary/03-blob/article.md @@ -1,6 +1,6 @@ # Blob -`ArrayBuffer` and views are a part of ECMA standard, a part of Javascript. +`ArrayBuffer` and views are a part of ECMA standard, a part of JavaScript. In the browser, there are additional higher-level objects, described in [File API](https://www.w3.org/TR/FileAPI/). @@ -52,7 +52,7 @@ The arguments are similar to `array.slice`, negative numbers are allowed too. ```smart header="Blobs are immutable" We can't change data directly in a blob, but we can slice parts of blobs, create new blobs from them, mix them into a new blob and so on. -This behavior is similar to Javascript strings: we can't change a character in a string, but we can make a new corrected string. +This behavior is similar to JavaScript strings: we can't change a character in a string, but we can make a new corrected string. ``` ## Blob as URL @@ -72,7 +72,7 @@ link.href = URL.createObjectURL(blob); ``` -We can also create a link dynamically in Javascript and simulate a click by `link.click()`, then download starts authomatically. +We can also create a link dynamically in JavaScript and simulate a click by `link.click()`, then download starts authomatically. Here's the similar "on the fly" blob creation and download code, but without HTML: diff --git a/4-binary/index.md b/4-binary/index.md index d3f054ba..2b0c5dc8 100644 --- a/4-binary/index.md +++ b/4-binary/index.md @@ -1,3 +1,3 @@ # Binary data, files -Working with binary data and files in Javascript. +Working with binary data and files in JavaScript. diff --git a/5-network/01-fetch-basics/article.md b/5-network/01-fetch-basics/article.md index ab1765b2..783c3996 100644 --- a/5-network/01-fetch-basics/article.md +++ b/5-network/01-fetch-basics/article.md @@ -54,10 +54,10 @@ To get the response body, we need to use an additional method call. - **`response.arrayBuffer()`** -- return the response as [ArrayBuffer](info:arraybuffer-binary-arrays) (pure binary data), - additionally, `response.body` is a [ReadableStream](https://streams.spec.whatwg.org/#rs-class) object, it allows to read the body chunk-by-chunk, we'll see an example later. -For instance, here we get a JSON-object with latest commits from Github: +For instance, here we get a JSON-object with latest commits from GitHub: ```js run async -let response = await fetch('https://api.github.com/repos/iliakan/javascript-tutorial-en/commits'); +let response = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits'); *!* let commits = await response.json(); // read response body and parse as JSON @@ -69,7 +69,7 @@ alert(commits[0].author.login); Or, the same using pure promises syntax: ```js run -fetch('https://api.github.com/repos/iliakan/javascript-tutorial-en/commits') +fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits') .then(response => response.json()) .then(commits => alert(commits[0].author.login)); ``` @@ -119,7 +119,7 @@ There's a Map-like headers object in `response.headers`. We can get individual headers or iterate over them: ```js run async -let response = await fetch('https://api.github.com/repos/iliakan/javascript-tutorial-en/commits'); +let response = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits'); // get one header alert(response.headers.get('Content-Type')); // application/json; charset=utf-8 diff --git a/5-network/02-fetch-progress/article.md b/5-network/02-fetch-progress/article.md index bc6efb0d..e7e945f6 100644 --- a/5-network/02-fetch-progress/article.md +++ b/5-network/02-fetch-progress/article.md @@ -39,7 +39,7 @@ Here's the full code to get response and log the progress, more explanations fol ```js run async // Step 1: start the fetch and obtain a reader -let response = await fetch('https://api.github.com/repos/iliakan/javascript-tutorial-en/commits?per_page=100'); +let response = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits?per_page=100'); const reader = response.body.getReader(); diff --git a/5-network/03-fetch-abort/article.md b/5-network/03-fetch-abort/article.md index 0ee45bd9..3e6f4cb4 100644 --- a/5-network/03-fetch-abort/article.md +++ b/5-network/03-fetch-abort/article.md @@ -1,7 +1,7 @@ # Fetch: Abort -Aborting a `fetch` is a little bit tricky. Remember, `fetch` returns a promise. And Javascript generally has no concept of "aborting" a promise. So how can we cancel a fetch? +Aborting a `fetch` is a little bit tricky. Remember, `fetch` returns a promise. And JavaScript generally has no concept of "aborting" a promise. So how can we cancel a fetch? There's a special built-in object for such purposes: `AbortController`. diff --git a/5-network/04-fetch-crossorigin/article.md b/5-network/04-fetch-crossorigin/article.md index 209fc5fe..e1b669e0 100644 --- a/5-network/04-fetch-crossorigin/article.md +++ b/5-network/04-fetch-crossorigin/article.md @@ -24,7 +24,7 @@ Because cross-origin restrictions protect the internet from evil hackers. Seriously. Let's make a very brief historical digression. -For many years Javascript did not have any special methods to perform network requests. +For many years JavaScript did not have any special methods to perform network requests. **A script from one site could not access the content of another site.** @@ -38,7 +38,7 @@ One way to communicate with another server was to submit a `
    ` there. Peopl - + ...
    @@ -105,7 +105,7 @@ Any other request is considered "non-simple". For instance, a request with `PUT` So, even a very old server should be ready to accept a simple request. -Contrary to that, requests with non-standard headers or e.g. method `DELETE` can't be created this way. For a long time Javascript was unable to do such requests. So an old server may assume that such requests come from a privileged source, "because a webpage is unable to send them". +Contrary to that, requests with non-standard headers or e.g. method `DELETE` can't be created this way. For a long time JavaScript was unable to do such requests. So an old server may assume that such requests come from a privileged source, "because a webpage is unable to send them". When we try to make a non-simple request, the browser sends a special "preflight" request that asks the server -- does it agree to accept such cross-origin requests, or not? @@ -134,7 +134,7 @@ The server can inspect the `Origin` and, if it agrees to accept such a request, The browser plays the role of a trusted mediator here: 1. It ensures that the corrent `Origin` is sent with a cross-domain request. -2. If checks for correct `Access-Control-Allow-Origin` in the response, if it is so, then Javascript access, otherwise forbids with an error. +2. If checks for correct `Access-Control-Allow-Origin` in the response, if it is so, then JavaScript access, otherwise forbids with an error. ![](xhr-another-domain.png) @@ -149,7 +149,7 @@ Access-Control-Allow-Origin: https://javascript.info ## Response headers -For cross-origin request, by default Javascript may only access "simple response headers": +For cross-origin request, by default JavaScript may only access "simple response headers": - `Cache-Control` - `Content-Language` @@ -166,7 +166,7 @@ Please note: there's no `Content-Length` header in the list! So, if we're downloading something and would like to track the percentage of progress, then an additional permission is required to access that header (see below). ``` -To grant Javascript access to any other response header, the server must list it in the `Access-Control-Expose-Headers` header. +To grant JavaScript access to any other response header, the server must list it in the `Access-Control-Expose-Headers` header. For example: @@ -283,20 +283,20 @@ The server should not forget to add `Accept-Control-Allow-Origin` to the respons Access-Control-Allow-Origin: https://javascript.info ``` -Now everything's correct. Javascript is able to read the full response. +Now everything's correct. JavaScript is able to read the full response. ## Credentials A cross-origin request by default does not bring any credentials (cookies or HTTP authentication). -That's uncommon for HTTP-requests. Usually, a request to `http://site.com` is accompanied by all cookies from that domain. But cross-domain requests made by Javascript methods are an exception. +That's uncommon for HTTP-requests. Usually, a request to `http://site.com` is accompanied by all cookies from that domain. But cross-domain requests made by JavaScript methods are an exception. For example, `fetch('http://another.com')` does not send any cookies, even those that belong to `another.com` domain. Why? -That's because a request with credentials is much more powerful than an anonymous one. If allowed, it grants Javascript the full power to act and access sensitive information on behalf of a user. +That's because a request with credentials is much more powerful than an anonymous one. If allowed, it grants JavaScript the full power to act and access sensitive information on behalf of a user. Does the server really trust pages from `Origin` that much? A request with credentials needs an additional header to pass through. @@ -348,7 +348,7 @@ So, practical difference is that simple requests are sent right away, with `Orig - `Access-Control-Allow-Origin` to `Origin` - `Access-Control-Allow-Credentials` to `true` -Additionally, if Javascript wants no access non-simple response headers: +Additionally, if JavaScript wants no access non-simple response headers: - `Cache-Control` - `Content-Language` - `Content-Type` diff --git a/5-network/07-xmlhttprequest/article.md b/5-network/07-xmlhttprequest/article.md index ffc54401..bda4bd1b 100644 --- a/5-network/07-xmlhttprequest/article.md +++ b/5-network/07-xmlhttprequest/article.md @@ -211,7 +211,7 @@ Nowadays, `load/error/progress` handlers deprecate it. If in the `open` method the third parameter `async` is set to `false`, the request is made synchronously. -In other words, Javascript execution pauses at `send()` and resumes when the response is received. Somewhat like `alert` or `prompt` commands. +In other words, JavaScript execution pauses at `send()` and resumes when the response is received. Somewhat like `alert` or `prompt` commands. Here's the rewritten example, the 3rd parameter of `open` is `false`: @@ -232,7 +232,7 @@ try { }; ``` -It might look good, but synchronous calls are used rarely, because they block in-page Javascript till the loading is complete. In some browsers it becomes impossible to scroll. If a synchronous call takes too much time, the browser may suggest to close the "hanging" webpage. +It might look good, but synchronous calls are used rarely, because they block in-page JavaScript till the loading is complete. In some browsers it becomes impossible to scroll. If a synchronous call takes too much time, the browser may suggest to close the "hanging" webpage. Many advanced capabilities of `XMLHttpRequest`, like requesting from another domain or specifying a timeout, are unavailable for synchronous requests. Also, as you can see, no progress indication. @@ -350,7 +350,6 @@ For instance: xhr.open("POST", "/article/xmlhttprequest/post/user"); xhr.send(formData); - xhr. ``` diff --git a/5-network/08-websocket/article.md b/5-network/08-websocket/article.md index 30bfbd77..f7bd1fa2 100644 --- a/5-network/08-websocket/article.md +++ b/5-network/08-websocket/article.md @@ -96,7 +96,7 @@ Sec-WebSocket-Version: 13 - `Sec-WebSocket-Version` -- WebSocket protocol version, 13 is the current one. ```smart header="WebSocket handshake can't be emulated" -We can't use `XMLHttpRequest` or `fetch` to make this kind of HTTP-request, because Javascript is not allowed to set these headers. +We can't use `XMLHttpRequest` or `fetch` to make this kind of HTTP-request, because JavaScript is not allowed to set these headers. ``` If the server agrees to switch to WebSocket, it should send code 101 response: @@ -274,7 +274,7 @@ To get connection state, additionally there's `socket.readyState` property with ## Chat example -Let's review a chat example using browser WebSocket API and Node.JS WebSocket module . +Let's review a chat example using browser WebSocket API and Node.js WebSocket module . HTML: there's a `
    ` to send messages and a `
    ` for incoming messages: @@ -289,7 +289,7 @@ HTML: there's a `` to send messages and a `
    ` for incoming messages:
    ``` -Javascript is also simple. We open a socket, then on form submission -- `socket.send(message)`, on incoming message -- append it to `div#messages`: +JavaScript is also simple. We open a socket, then on form submission -- `socket.send(message)`, on incoming message -- append it to `div#messages`: ```js let socket = new WebSocket("wss://javascript.info/article/websocket/chat/ws"); @@ -314,7 +314,7 @@ socket.onmessage = function(event) { Server-side code is a little bit beyound our scope here. We're using browser WebSocket API, a server may have another library. -Still it can also be pretty simple. We'll use Node.JS with module for websockets. +Still it can also be pretty simple. We'll use Node.js with module for websockets. The algorithm will be: 1. Create `clients = new Set()` -- a set of sockets. diff --git a/6-data-storage/01-cookie/article.md b/6-data-storage/01-cookie/article.md index fcf52f40..e6322fd6 100644 --- a/6-data-storage/01-cookie/article.md +++ b/6-data-storage/01-cookie/article.md @@ -35,7 +35,7 @@ The value of `document.cookie` consists of `name=value` pairs, delimited by `; ` To find a particular cookie, we can split `document.cookie` by `; `, and then find the right name. We can use either a regular expression or array functions to do that. -We leave it as an excercise for the reader. Also, at the end of the chapter you'll find helper functions to manipulate cookies. +We leave it as an exercise for the reader. Also, at the end of the chapter you'll find helper functions to manipulate cookies. ## Writing to document.cookie @@ -167,7 +167,7 @@ document.cookie = "user=John; max-age=0"; The cookie should be transferred only over HTTPS. -**By default, if we set a cookie at `http://site.com`, then it also appears at `https://site.com` and vise versa.** +**By default, if we set a cookie at `http://site.com`, then it also appears at `https://site.com` and vice versa.** That is, cookies are domain-based, they do not distinguish between the protocols. @@ -253,13 +253,13 @@ But we surely can use `samesite` together with other protection measures, like x ## httpOnly -This option has nothing to do with Javascript, but we have to mention it for completeness. +This option has nothing to do with JavaScript, but we have to mention it for completeness. The web-server uses `Set-Cookie` header to set a cookie. And it may set the `httpOnly` option. This option forbids any JavaScript access to the cookie. We can't see such cookie or manipulate it using `document.cookie`. -That's used as a precaution measure, to protect from certain attacks when a hacker injects his own Javascript code into a page and waits for a user to visit that page. That shouldn't be possible at all, a hacker should not be able to inject their code into our site, but there may be bugs that let hackers do it. +That's used as a precaution measure, to protect from certain attacks when a hacker injects his own JavaScript code into a page and waits for a user to visit that page. That shouldn't be possible at all, a hacker should not be able to inject their code into our site, but there may be bugs that let hackers do it. Normally, if such thing happens, and a user visits a web-page with hacker's code, then that code executes and gains access to `document.cookie` with user cookies containing authentication information. That's bad. diff --git a/6-data-storage/03-indexeddb/article.md b/6-data-storage/03-indexeddb/article.md index dbe38674..d7fc5bbb 100644 --- a/6-data-storage/03-indexeddb/article.md +++ b/6-data-storage/03-indexeddb/article.md @@ -142,7 +142,7 @@ To do an upgrade, there are two main ways: 1. We can compare versions and run per-version operations. 2. Or we can get a list of existing object stores as `db.objectStoreNames`. That object is a [DOMStringList](https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#domstringlist), and it provides `contains(name)` method to check for the existance. And then we can do updates depending on what exists. -Here's the demo of thee second approach: +Here's the demo of the second approach: ```js let openRequest = indexedDB.open("db", 1); diff --git a/8-web-components/1-webcomponents-intro/article.md b/8-web-components/1-webcomponents-intro/article.md index e3e175f4..a69cc3fc 100644 --- a/8-web-components/1-webcomponents-intro/article.md +++ b/8-web-components/1-webcomponents-intro/article.md @@ -56,7 +56,8 @@ Components may have subcomponents, e.g. messages may be parts of a higher-level How do we decide, what is a component? That comes from intuition, experience and common sense. Usually it's a separate visual entity that we can describe in terms of what it does and how it interacts with the page. In the case above, the page has blocks, each of them plays its own role, it's logical to make these components. -- A component has its own JavaScript class. +A component has: +- its own JavaScript class. - DOM structure, managed solely by its class, outside code doesn't access it ("encapsulation" principle). - CSS styles, applied to the component. - API: events, class methods etc, to interact with other components. diff --git a/8-web-components/4-template-element/article.md b/8-web-components/4-template-element/article.md index 41dbceb1..4d9df9cb 100644 --- a/8-web-components/4-template-element/article.md +++ b/8-web-components/4-template-element/article.md @@ -3,7 +3,7 @@ A built-in `