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/05-data-types/04-array/10-maximal-subarray/solution.md
+5-6Lines changed: 5 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
-
# The slow solution
1
+
# The slow solution
2
2
3
-
We can calculate all possible subsums.
3
+
We can calculate all possible subsums.
4
4
5
5
The simplest way is to take every element and calculate sums of all subarrays starting from it.
6
6
@@ -61,7 +61,7 @@ The solution has a time complexety of [O(n<sup>2</sup>)](https://en.wikipedia.or
61
61
62
62
For big arrays (1000, 10000 or more items) such algorithms can lead to a seroius sluggishness.
63
63
64
-
# Fast solution
64
+
# Fast solution
65
65
66
66
Let's walk the array and keep the current partial sum of elements in the variable `s`. If `s` becomes negative at some point, then assign `s=0`. The maximum of all such `s` will be the answer.
67
67
@@ -72,7 +72,7 @@ function getMaxSubSum(arr) {
72
72
let maxSum =0;
73
73
let partialSum =0;
74
74
75
-
for (let item of arr; i++) { // for each item of arr
75
+
for (let item of arr) { // for each item of arr
76
76
partialSum += item; // add it to partialSum
77
77
maxSum =Math.max(maxSum, partialSum); // remember the maximum
78
78
if (partialSum <0) partialSum =0; // zero if negative
The algorithm requires exactly 1 array pass, so the time complexity is O(n).
93
93
94
-
You can find more detail information about the algorithm here: [Maximum subarray problem](http://en.wikipedia.org/wiki/Maximum_subarray_problem). If it's still not obvious why that works, then please trace the algorithm on the examples above, see how it works, that's better than any words.
95
-
94
+
You can find more detail information about the algorithm here: [Maximum subarray problem](http://en.wikipedia.org/wiki/Maximum_subarray_problem). If it's still not obvious why that works, then please trace the algorithm on the examples above, see how it works, that's better than any words.
Copy file name to clipboardExpand all lines: 1-js/05-data-types/05-array-methods/article.md
+19-7Lines changed: 19 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -519,7 +519,7 @@ let arr = [1, 2, 3, 4, 5]
519
519
520
520
let result =arr.reduce((sum, current) => sum + current), 0);
521
521
522
-
alert(result); // 15
522
+
alert(result); // 15
523
523
```
524
524
525
525
Here we used the most common variant of `reduce` which uses only 2 arguments.
@@ -562,10 +562,22 @@ The result is the same. That's because if there's no initial, then `reduce` take
562
562
563
563
The calculation table is the same as above, minus the first row.
564
564
565
-
But such use requires an extreme care. If the array is empty, then `reduce` call without initial value gives an error. So it's generally advised to specify the initial value.
565
+
But such use requires an extreme care. If the array is empty, then `reduce` call without initial value gives an error.
566
566
567
-
The method [arr.reduceRight](mdn:js/Array/reduceRight) does the same, but goes from right to left.
567
+
Here's an example:
568
568
569
+
```js run
570
+
let arr = [];
571
+
572
+
// Error: Reduce of empty array with no initial value
573
+
// if the initial value existed, reduce would return it for the empty arr.
574
+
arr.reduce((sum, current) => sum + current);
575
+
```
576
+
577
+
578
+
So it's advised to always specify the initial value.
579
+
580
+
The method [arr.reduceRight](mdn:js/Array/reduceRight) does the same, but goes from right to left.
Almost all array methods that call functions -- like `find`, `filter`, `map`, with a notable exception of `sort`, accept an optional additional parameter `thisArg`.
621
633
622
-
In the sections above that parameter is not explained, because it's rarely used.
634
+
That parameter is not explained in the sections above, because it's rarely used. But for completeness we have to cover it.
623
635
624
-
But for completeness here's the full syntax:
636
+
Here's the full syntax of these methods:
625
637
626
638
```js
627
639
arr.find(func, thisArg);
@@ -633,7 +645,7 @@ arr.map(func, thisArg);
633
645
634
646
The value of `thisArg` parameter becomes `this` for `func`.
635
647
636
-
For instance, here we use an object method as a filter:
648
+
For instance, here we use an object method as a filter and `thisArg` comes in handy:
Copy file name to clipboardExpand all lines: 1-js/08-error-handling/2-custom-errors/article.md
+48-25Lines changed: 48 additions & 25 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,11 +2,11 @@
2
2
3
3
When we develop something, we often need our own error classes to reflect specific things that may go wrong in our tasks. For errors in network operations we may need `HttpError`, for database operations `DbError`, for searching operations `NotFoundError` and so on.
4
4
5
-
Our errors should inherit from basic `Error` class and support basic error properties like `message`, `name` and, preferably, `stack`. But they also may have other properties of their own, e.g. `HttpError` objects may have `statusCode` property with a value like `404` or `403` or `500`.
5
+
Our errors should support basic error properties like `message`, `name` and, preferably, `stack`. But they also may have other properties of their own, e.g. `HttpError` objects may have `statusCode` property with a value like `404` or `403` or `500`.
6
6
7
-
Technically, we can use standalone classes for our errors, because JavaScript allows to use `throw` with any argument. But if we inherit from `Error`, then it becomes possible to use `obj instanceof Error` check to identify error objects. So it's better to inherit from it.
7
+
JavaScript allows to use `throw` with any argument, so technically our custom error classes don't need to inherit from `Error`. But if we inherit, then it becomes possible to use `obj instanceof Error` to identify error objects. So it's better to inherit from it.
8
8
9
-
As we build our application, our own errors naturally form a hierarchy, for instance `HttpTimeoutError` may inherit from `HttpError`. Examples will follow soon.
9
+
As we build our application, our own errors naturally form a hierarchy, for instance `HttpTimeoutError` may inherit from `HttpError`, and so on.
10
10
11
11
## Extending Error
12
12
@@ -17,14 +17,20 @@ Here's an example of how a valid `json` may look:
17
17
let json =`{ "name": "John", "age": 30 }`;
18
18
```
19
19
20
-
If `JSON.parse`receives malformed `json`, then it throws `SyntaxError`. But even if `json` is syntactically correct, it may don't have the necessary data. For instance, if may not have `name` and `age` properties that are essential for our users.
20
+
Internally, we'll use `JSON.parse`. If it receives malformed `json`, then it throws `SyntaxError`.
21
21
22
-
That's called "data validation" -- we need to ensure that the data has all the necessary fields. And if the validation fails, then it not really a `SyntaxError`, because the data is syntactically correct. Let's create `ValidationError` -- the error object of our own with additional information about the offending field.
22
+
But even if `json` is syntactically correct, that doesn't mean that it's a valid user, right? It may miss the necessary data. For instance, if may not have `name` and `age` properties that are essential for our users.
23
23
24
-
Our `ValidationError` should inherit from the built-in `Error` class. To better understand what we're extending -- here's the approximate code for built-in [Error class](https://tc39.github.io/ecma262/#sec-error-message):
24
+
Our function `readUser(json)` will not only read JSON, but check ("validate") the data. If there are no required fields, or the format is wrong, then that's an error. And that's not a `SyntaxError`, because the data is syntactically correct, but another kind of error. We'll call it `ValidationError` and create a class for it. An error of that kind should also carry the information about the offending field.
25
+
26
+
Our `ValidationError` class should inherit from the built-in `Error` class.
27
+
28
+
That class is built-in, but we should have its approximate code before our eyes, to understand what we're extending.
29
+
30
+
So here you are:
25
31
26
32
```js
27
-
// "pseudocode" for the built-in Error class defined by JavaScript itself
33
+
//The "pseudocode" for the built-in Error class defined by JavaScript itself
28
34
classError {
29
35
constructor(message) {
30
36
this.message= message;
@@ -34,7 +40,7 @@ class Error {
34
40
}
35
41
```
36
42
37
-
Now let's inherit from it:
43
+
Now let's go on and inherit`ValidationError` from it:
38
44
39
45
```js run untrusted
40
46
*!*
@@ -59,10 +65,10 @@ try {
59
65
}
60
66
```
61
67
62
-
Please note:
68
+
Please take a look at the constructor:
63
69
64
-
1. In the line `(1)` we call the parent constructor to set the message. JavaScript requires us to call `super` in the child constructor.
65
-
2. The parent constructor sets the `name` property to `"Error"`, so here we reset it to the right value.
70
+
1. In the line `(1)` we call the parent constructor. JavaScript requires us to call `super` in the child constructor, so that's obligatory. The parent constructor sets the `message` property.
71
+
2. The parent constructor also sets the `name` property to `"Error"`, so in the line `(2)` we reset it to the right value.
66
72
67
73
Let's try to use it in `readUser(json)`:
68
74
@@ -97,23 +103,34 @@ try {
97
103
*!*
98
104
alert("Invalid data: "+err.message); // Invalid data: No field: name
99
105
*/!*
100
-
} elseif (err instanceofSyntaxError) {
106
+
} elseif (err instanceofSyntaxError) {// (*)
101
107
alert("JSON Syntax Error: "+err.message);
102
108
} else {
103
-
throw err; // unknown error, rethrow it
109
+
throw err; // unknown error, rethrow it (**)
104
110
}
105
111
}
106
112
```
107
113
108
-
Everything works -- both our `ValidationError` and the built-in `SyntaxError` from `JSON.parse` can be generated and handled.
114
+
The `try..catch` block in the code above handles both our `ValidationError` and the built-in `SyntaxError` from `JSON.parse`.
115
+
116
+
Please take a look at how we use `instanceof` to check for the specific error type in the line `(*)`.
109
117
110
-
Please take a look at how the code checks for the error type in `catch (err) { ... }`. We could use `if (err.name == "ValidationError")`, but `if (err instanceof ValidationError)` is much better, because in the future we are going to extend `ValidationError`, make new subtypes of it, namely `PropertyRequiredError`. And `instanceof` check will continue to work. So that's future-proof.
118
+
We could also look at `err.name`, like this:
111
119
112
-
Also it's important that if `catch` meets an unknown error, then it rethrows it. The `catch` only knows how to handle validation and syntax errors, other kinds (due to a typo in the code or such) should fall through.
120
+
```js
121
+
// ...
122
+
// instead of (err instanceof SyntaxError)
123
+
} elseif (err.name=="SyntaxError") { // (*)
124
+
// ...
125
+
```
126
+
127
+
The `instanceof` version is much better, because in the future we are going to extend `ValidationError`, make subtypes of it, like `PropertyRequiredError`. And `instanceof` check will continue to work for new inheriting classes. So that's future-proof.
128
+
129
+
Also it's important that if `catch` meets an unknown error, then it rethrows it in the line `(**)`. The `catch` only knows how to handle validation and syntax errors, other kinds (due to a typo in the code or such) should fall through.
113
130
114
131
## Further inheritance
115
132
116
-
The `ValidationError` class is very generic. Many things may be wrong. The property may be absent or it may be in a wrong format (like a string value for `age`). Let's make a more concrete class `PropertyRequiredError`, exactly for absent properties. It will carry additional information about the property that's missing.
133
+
The `ValidationError` class is very generic. Many things may go wrong. The property may be absent or it may be in a wrong format (like a string value for `age`). Let's make a more concrete class `PropertyRequiredError`, exactly for absent properties. It will carry additional information about the property that's missing.
117
134
118
135
```js run
119
136
classValidationErrorextendsError {
@@ -168,9 +185,11 @@ try {
168
185
169
186
The new class `PropertyRequiredError` is easy to use: we only need to pass the property name: `newPropertyRequiredError(property)`. The human-readable `message` is generated by the constructor.
170
187
171
-
Plese note that `this.name` in `PropertyRequiredError`once again assigned manually. We could make our own "basic error" class, name it `MyError` that removes this burden from our shoulders by using `this.constructor.name` for `this.name` in the constructor. And then inherit from it.
188
+
Please note that `this.name` in `PropertyRequiredError`constructor is again assigned manually. That may become a bit tedius -- to assign `this.name=<classname>` when creating each custom error. But there's a way out. We can make our own "basic error" class that removes this burden from our shoulders by using `this.constructor.name` for `this.name` in the constructor. And then inherit from it.
172
189
173
-
Here we go:
190
+
Let's call it `MyError`.
191
+
192
+
Here's the code with `MyError` and other custom error classes, simplified:
174
193
175
194
```js run
176
195
classMyErrorextendsError {
@@ -195,17 +214,19 @@ class PropertyRequiredError extends ValidationError {
Now the inheritance became simpler, as we got rid of the `"this.name = ..."` line in the constructor.
217
+
Now custom errors are much shorter, especially `ValidationError`, as we got rid of the `"this.name = ..."` line in the constructor.
199
218
200
219
## Wrapping exceptions
201
220
202
-
The purpose of the function `readUser` in the code above is "to read the user data", right? There may occur different kinds of errors in the process. Right now we have `SyntaxError` and `ValidationError`, but there may appear more if we put more stuff into it.
221
+
The purpose of the function `readUser` in the code above is "to read the user data", right? There may occur different kinds of errors in the process. Right now we have `SyntaxError` and `ValidationError`, but in the future `readUser` function may grow: the new code will probably generate other kinds of errors.
222
+
223
+
The code which calls `readUser` should handle these errors. Right now it uses multiple `if` in the `catch` block to check for different error types and rethrow the unknown ones. But if `readUser` function generates several kinds of errors -- then we should ask ourselves: do we really want to check for all error types one-by-one in every code that calls `readUser`?
203
224
204
-
Right now the code which calls `readUser` uses multiple `if` in `catch`to check for different error types. The important questions is: do we really want to check for all error types one-by-one every time we call `readUser`?
225
+
Often the answer is "No": the outer code wants to be "one level above all that". It wants to have some kind of "data reading error". Why exactly it happened -- is often irrelevant (the error message describes it). Or, even better if there is a way to get error details, but only if we need to.
205
226
206
-
Often the answer is: "No". The outer code wants to be "one level above all that". It wants to have some kind of "data reading error". Why exactly it happened -- is usually irrelevant (the message has the info). Or, even better if there is a way to get more details, but only if we need to.
227
+
So let's make a new class `ReadError`to represent such errors. If an error occurs inside `readUser`, we'll catch it there and generate `ReadError`. We'll also keep the reference to the original error in the `cause` property. Then the outer code will only have to check for `ReadError`.
207
228
208
-
So let's make a new class`ReadError`to represent such errors. If an error occurs inside `readUser`, we'll catch it there and generate `ReadError`. We'll also keep the reference to the original error in the `cause` property.
229
+
Here's the code that defines`ReadError`and demonstrates its use in `readUser`and `try..catch`:
209
230
210
231
```js run
211
232
classReadErrorextendsError {
@@ -273,7 +294,9 @@ try {
273
294
}
274
295
```
275
296
276
-
In the code above, `readUser` does exactly as described -- catches syntax and validation errors and throws `ReadError` errors instead (unknown errors are rethrown as usual).
297
+
In the code above, `readUser` works exactly as described -- catches syntax and validation errors and throws `ReadError` errors instead (unknown errors are rethrown as usual).
298
+
299
+
So the outer code checks `instanceof ReadError` and that's it. No need to list possible all error types.
277
300
278
301
The approach is called "wrapping exceptions", because we take "low level exceptions" and "wrap" them into `ReadError` that is more abstract and more convenient to use for the calling code. It is widely used in object-oriented programming.
Copy file name to clipboardExpand all lines: 6-async/05-async-await/article.md
+5-4Lines changed: 5 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -119,18 +119,19 @@ async function showAvatar() {
119
119
showAvatar();
120
120
```
121
121
122
-
Pretty clean and easy to read, right?
122
+
Pretty clean and easy to read, right? Much better than before.
123
123
124
-
Please note that we can't write `await` in the top-level code. That wouldn't work:
124
+
````smart header="`await` won't work in the top-level code"
125
+
People who are just starting to use `await` tend to forget that, but we can't write `await` in the top-level code. That wouldn't work:
125
126
126
127
```js run
127
128
// syntax error in top-level code
128
129
let response = await fetch('/article/promise-chaining/user.json');
129
130
let user = await response.json();
130
131
```
131
132
132
-
So we need to have a wrapping async function for the code that awaits.
133
-
133
+
So we need to have a wrapping async function for the code that awaits. Just as in the example above.
134
+
````
134
135
````smart header="`await` accepts thenables"
135
136
Like `promise.then`, `await` allows to use thenable objects (those with a callable `then` method). Again, the idea is that a 3rd-party object may be not a promise, but promise-compatible: if it supports `.then`, that's enough to use with `await`.
0 commit comments