You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 1-js/02-first-steps/02-structure/article.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -94,7 +94,7 @@ But it should be two separate statements, not one. Such a merging in this case i
94
94
95
95
We recommend putting semicolons between statements even if they are separated by newlines. This rule is widely adopted by the community. Let's note once again -- *it is possible* to leave out semicolons most of the time. But it's safer -- especially for a beginner -- to use them.
96
96
97
-
## Comments
97
+
## Comments[#code-comments]
98
98
99
99
As time goes on, programs become more and more complex. It becomes necessary to add *comments* which describe what the code does and why.
Copy file name to clipboardExpand all lines: 1-js/04-object-basics/01-object/article.md
+60-39Lines changed: 60 additions & 39 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -101,7 +101,9 @@ For multiword properties, the dot access doesn't work:
101
101
user.likes birds =true
102
102
```
103
103
104
-
That's because the dot requires the key to be a valid variable identifier. That is: no spaces and other limitations.
104
+
JavaScript doesn't understand that. It thinks that we address `user.likes`, and then gives a syntax error when comes across unexpected `birds`.
105
+
106
+
The dot requires the key to be a valid variable identifier. That implies: contains no spaces, doesn't start with a digit and doesn't include special characters (`$` и `_` are allowed).
105
107
106
108
There's an alternative "square bracket notation" that works with any string:
107
109
@@ -203,43 +205,6 @@ Square brackets are much more powerful than the dot notation. They allow any pro
203
205
204
206
So most of the time, when property names are known and simple, the dot is used. And if we need something more complex, then we switch to square brackets.
205
207
206
-
207
-
208
-
````smart header="Reserved words are allowed as property names"
209
-
A variable cannot have a name equal to one of language-reserved words like "for", "let", "return" etc.
210
-
211
-
But for an object property, there's no such restriction. Any name is fine:
212
-
213
-
```js run
214
-
let obj = {
215
-
for: 1,
216
-
let: 2,
217
-
return: 3
218
-
};
219
-
220
-
alert( obj.for + obj.let + obj.return ); // 6
221
-
```
222
-
223
-
Basically, any name is allowed, but there's a special one: `"__proto__"` that gets special treatment for historical reasons. For instance, we can't set it to a non-object value:
224
-
225
-
```js run
226
-
let obj = {};
227
-
obj.__proto__ = 5;
228
-
alert(obj.__proto__); // [object Object], didn't work as intended
229
-
```
230
-
231
-
As we see from the code, the assignment to a primitive `5` is ignored.
232
-
233
-
That can become a source of bugs and even vulnerabilities if we intend to store arbitrary key-value pairs in an object, and allow a visitor to specify the keys.
234
-
235
-
In that case the visitor may choose `__proto__` as the key, and the assignment logic will be ruined (as shown above).
236
-
237
-
There is a way to make objects treat `__proto__` as a regular property, which we'll cover later, but first we need to know more about objects.
238
-
239
-
There's also another data structure [Map](info:map-set), that we'll learn in the chapter <info:map-set>, which supports arbitrary keys.
240
-
````
241
-
242
-
243
208
## Property value shorthand
244
209
245
210
In real code we often use existing variables as values for property names.
@@ -284,7 +249,63 @@ let user = {
284
249
};
285
250
```
286
251
287
-
## Existence check
252
+
## Property names limitations
253
+
254
+
Property names (keys) must be either strings or symbols (a special type for identifiers, to be covered later).
255
+
256
+
Other types are automatically converted to strings.
257
+
258
+
For instance, a number `0` becomes a string `"0"` when used as a property key:
259
+
260
+
```js run
261
+
let obj = {
262
+
0:"test"// same as "0": "test"
263
+
};
264
+
265
+
// both alerts access the same property (the number 0 is converted to string "0")
266
+
alert( obj["0"] ); // test
267
+
alert( obj[0] ); // test (same property)
268
+
```
269
+
270
+
**Reserved words are allowed as property names.**
271
+
272
+
As we already know, a variable cannot have a name equal to one of language-reserved words like "for", "let", "return" etc.
273
+
274
+
But for an object property, there's no such restriction. Any name is fine:
275
+
276
+
```js run
277
+
let obj = {
278
+
for:1,
279
+
let:2,
280
+
return:3
281
+
};
282
+
283
+
alert( obj.for+obj.let+obj.return ); // 6
284
+
```
285
+
286
+
We can use any string as a key, but there's a special property named `__proto__` that gets special treatment for historical reasons.
287
+
288
+
For instance, we can't set it to a non-object value:
289
+
290
+
```js run
291
+
let obj = {};
292
+
obj.__proto__=5; // assign a number
293
+
alert(obj.__proto__); // [object Object] - the value is an object, didn't work as intended
294
+
```
295
+
296
+
As we see from the code, the assignment to a primitive `5` is ignored.
297
+
298
+
The nature of `__proto__` will be revealed in detail later in the chapter [](info:prototype-inheritance).
299
+
300
+
As for now, it's important to know that such behavior of `__proto__` can become a source of bugs and even vulnerabilities if we intend to store user-provided keys in an object.
301
+
302
+
The problem is that a visitor may choose `__proto__` as the key, and the assignment logic will be ruined (as shown above).
303
+
304
+
Later we'll see workarounds for the problem:
305
+
1. We'll see how to make an objects treat `__proto__` as a regular property in the chapter [](info:prototype-methods).
306
+
2. There's also study another data structure [Map](info:map-set) in the chapter <info:map-set>, which supports arbitrary keys.
307
+
308
+
## Property existance test, "in" operator
288
309
289
310
A notable objects feature is that it's possible to access any property. There will be no error if the property doesn't exist! Accessing a non-existing property just returns `undefined`. It provides a very common way to test whether the property exists -- to get it and compare vs undefined:
Copy file name to clipboardExpand all lines: 1-js/04-object-basics/03-symbol/article.md
-16Lines changed: 0 additions & 16 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -178,22 +178,6 @@ alert( clone[id] ); // 123
178
178
179
179
There's no paradox here. That's by design. The idea is that when we clone an object or merge objects, we usually want *all* properties to be copied (including symbols like `id`).
180
180
181
-
````smart header="Property keys of other types are coerced to strings"
182
-
We can only use strings or symbols as keys in objects. Other types are converted to strings.
183
-
184
-
For instance, a number `0` becomes a string `"0"` when used as a property key:
185
-
186
-
```js run
187
-
let obj = {
188
-
0: "test" // same as "0": "test"
189
-
};
190
-
191
-
// both alerts access the same property (the number 0 is converted to string "0")
192
-
alert( obj["0"] ); // test
193
-
alert( obj[0] ); // test (same property)
194
-
```
195
-
````
196
-
197
181
## Global symbols
198
182
199
183
As we've seen, usually all symbols are different, even if they have the same name. But sometimes we want same-named symbols to be same entities. For instance, different parts of our application want to access symbol `"id"` meaning exactly the same property.
Copy file name to clipboardExpand all lines: 1-js/05-data-types/06-iterable/article.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,7 +12,7 @@ If an object isn't technically an array, but represents a collection (list, set)
12
12
13
13
We can easily grasp the concept of iterables by making one of our own.
14
14
15
-
For instance, we have an object, that is not an array, but looks suitable for `for..of`.
15
+
For instance, we have an object that is not an array, but looks suitable for `for..of`.
16
16
17
17
Like a `range` object that represents an interval of numbers:
18
18
@@ -294,7 +294,7 @@ Objects that can be used in `for..of` are called *iterable*.
294
294
295
295
- Technically, iterables must implement the method named `Symbol.iterator`.
296
296
- The result of `obj[Symbol.iterator]` is called an *iterator*. It handles the further iteration process.
297
-
- An iterator must have the method named `next()` that returns an object `{done: Boolean, value: any}`, here `done:true` denotes the iteration end, otherwise the `value` is the next value.
297
+
- An iterator must have the method named `next()` that returns an object `{done: Boolean, value: any}`, here `done:true` denotes the end of the iteration process, otherwise the `value` is the next value.
298
298
- The `Symbol.iterator` method is called automatically by `for..of`, but we also can do it directly.
299
299
- Built-in iterables like strings or arrays, also implement `Symbol.iterator`.
Copy file name to clipboardExpand all lines: 1-js/10-error-handling/1-try-catch/article.md
+5-5Lines changed: 5 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@ No matter how great we are at programming, sometimes our scripts have errors. Th
4
4
5
5
Usually, a script "dies" (immediately stops) in case of an error, printing it to console.
6
6
7
-
But there's a syntax construct `try..catch` that allows to "catch" errors and, instead of dying, do something more reasonable.
7
+
But there's a syntax construct `try..catch` that allows us to "catch" errors so the script can, instead of dying, do something more reasonable.
8
8
9
9
## The "try..catch" syntax
10
10
@@ -26,13 +26,13 @@ It works like this:
26
26
27
27
1. First, the code in `try {...}` is executed.
28
28
2. If there were no errors, then `catch(err)` is ignored: the execution reaches the end of `try` and goes on, skipping `catch`.
29
-
3. If an error occurs, then `try` execution is stopped, and the control flows to the beginning of `catch(err)`. The `err` variable (can use any name for it) will contain an error object with details about what happened.
29
+
3. If an error occurs, then the `try` execution is stopped, and control flows to the beginning of `catch(err)`. The `err` variable (we can use any name for it) will contain an error object with details about what happened.
30
30
31
31

32
32
33
-
So, an error inside the `try {…}` block does not kill the script: we have a chance to handle it in `catch`.
33
+
So, an error inside the `try {…}` block does not kill the script -- we have a chance to handle it in `catch`.
34
34
35
-
Let's see examples.
35
+
Let's look at some examples.
36
36
37
37
- An errorless example: shows `alert``(1)` and `(2)`:
38
38
@@ -87,7 +87,7 @@ try {
87
87
88
88
The JavaScript engine first reads the code, and then runs it. The errors that occur on the reading phase are called "parse-time" errors and are unrecoverable (from inside that code). That's because the engine can't understand the code.
89
89
90
-
So, `try..catch` can only handle errors that occur in the valid code. Such errors are called "runtime errors" or, sometimes, "exceptions".
90
+
So, `try..catch` can only handle errors that occur in valid code. Such errors are called "runtime errors" or, sometimes, "exceptions".
There is also a method `response.json()` that reads the remote data and parses it as JSON. In our case that's even more convenient, so let's switch to it.
255
+
The `response` object returned from `fetch`also includes the method `response.json()` that reads the remote data and parses it as JSON. In our case that's even more convenient, so let's switch to it.
Copy file name to clipboardExpand all lines: 1-js/11-async/08-async-await/article.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -143,7 +143,7 @@ But we can wrap it into an anonymous async function, like this:
143
143
144
144
````
145
145
````smart header="`await` accepts \"thenables\""
146
-
Like `promise.then`, `await` allows to use thenable objects (those with a callable `then` method). The idea is that a third-party object may not be a promise, but promise-compatible: if it supports `.then`, that's enough to use with `await`.
146
+
Like `promise.then`, `await` allows us to use thenable objects (those with a callable `then` method). The idea is that a third-party object may not be a promise, but promise-compatible: if it supports `.then`, that's enough to use it with `await`.
147
147
148
148
Here's a demo `Thenable` class; the `await` below accepts its instances:
Copy file name to clipboardExpand all lines: 1-js/12-generators-iterators/1-generators/article.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -102,7 +102,7 @@ But usually the first syntax is preferred, as the star `*` denotes that it's a g
102
102
103
103
As you probably already guessed looking at the `next()` method, generators are [iterable](info:iterable).
104
104
105
-
We can get loop over values by `for..of`:
105
+
We can loop over their values using `for..of`:
106
106
107
107
```js run
108
108
function* generateSequence() {
@@ -314,11 +314,11 @@ alert(str); // 0..9A..Za..z
314
314
315
315
A generator composition is a natural way to insert a flow of one generator into another. It doesn't use extra memory to store intermediate results.
316
316
317
-
## "yield" is a two-way road
317
+
## "yield" is a two-way street
318
318
319
319
Until this moment, generators were similar to iterable objects, with a special syntax to generate values. But in fact they are much more powerful and flexible.
320
320
321
-
That's because `yield` is a two-way road: it not only returns the result outside, but also can pass the value inside the generator.
321
+
That's because `yield` is a two-way street: it not only returns the result to the outside, but also can pass the value inside the generator.
322
322
323
323
To do so, we should call `generator.next(arg)`, with an argument. That argument becomes the result of `yield`.
0 commit comments