Skip to content

Commit

Permalink
Merge pull request #5 from javascript-tutorial/master
Browse files Browse the repository at this point in the history
Updated Repo
  • Loading branch information
aniketkudale committed Feb 20, 2020
2 parents 5a71d10 + 3e93486 commit 4f6356b
Show file tree
Hide file tree
Showing 44 changed files with 178 additions and 188 deletions.
2 changes: 1 addition & 1 deletion 1-js/01-getting-started/1-intro/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ JavaScript's abilities in the browser are limited for the sake of the user's saf

Examples of such restrictions include:

- JavaScript on a webpage may not read/write arbitrary files on the hard disk, copy them or execute programs. It has no direct access to OS system functions.
- JavaScript on a webpage may not read/write arbitrary files on the hard disk, copy them or execute programs. It has no direct access to OS functions.

Modern browsers allow it to work with files, but the access is limited and only provided if the user does certain actions, like "dropping" a file into a browser window or selecting it via an `<input>` tag.

Expand Down
4 changes: 2 additions & 2 deletions 1-js/02-first-steps/02-structure/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ But it should be two separate statements, not one. Such a merging in this case i

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.

## Comments
## Comments [#code-comments]

As time goes on, programs become more and more complex. It becomes necessary to add *comments* which describe what the code does and why.

Expand Down Expand Up @@ -136,7 +136,7 @@ alert('World');
```

```smart header="Use hotkeys!"
In most editors, a line of code can be commented out by pressing the `key:Ctrl+/` hotkey for a single-line comment and something like `key:Ctrl+Shift+/` -- for multiline comments (select a piece of code and press the hotkey). For Mac, try `key:Cmd` instead of `key:Ctrl`.
In most editors, a line of code can be commented out by pressing the `key:Ctrl+/` hotkey for a single-line comment and something like `key:Ctrl+Shift+/` -- for multiline comments (select a piece of code and press the hotkey). For Mac, try `key:Cmd` instead of `key:Ctrl` and `key:Option` instead of `key:Shift`.
```

````warn header="Nested comments are not supported!"
Expand Down
8 changes: 4 additions & 4 deletions 1-js/02-first-steps/07-operators/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,10 @@ Here's an extract from the [precedence table](https://developer.mozilla.org/en/J
| Precedence | Name | Sign |
|------------|------|------|
| ... | ... | ... |
| 16 | unary plus | `+` |
| 16 | unary negation | `-` |
| 14 | multiplication | `*` |
| 14 | division | `/` |
| 17 | unary plus | `+` |
| 17 | unary negation | `-` |
| 15 | multiplication | `*` |
| 15 | division | `/` |
| 13 | addition | `+` |
| 13 | subtraction | `-` |
| ... | ... | ... |
Expand Down
4 changes: 2 additions & 2 deletions 1-js/02-first-steps/12-while-for/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ For even values of `i`, the `continue` directive stops executing the body and pa
````smart header="The `continue` directive helps decrease nesting"
A loop that shows odd values could look like this:

```js
```js run
for (let i = 0; i < 10; i++) {

if (i % 2) {
Expand All @@ -268,7 +268,7 @@ for (let i = 0; i < 10; i++) {

From a technical point of view, this is identical to the example above. Surely, we can just wrap the code in an `if` block instead of using `continue`.

But as a side-effect, this created one more level of nesting (the `alert` call inside the curly braces). If the code inside of`if` is longer than a few lines, that may decrease the overall readability.
But as a side-effect, this created one more level of nesting (the `alert` call inside the curly braces). If the code inside of `if` is longer than a few lines, that may decrease the overall readability.
````
````warn header="No `break/continue` to the right side of '?'"
Expand Down
2 changes: 1 addition & 1 deletion 1-js/03-code-quality/02-coding-style/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ For example:
```js
// backtick quotes ` allow to split the string into multiple lines
let str = `
Ecma International's TC39 is a group of JavaScript developers,
ECMA International's TC39 is a group of JavaScript developers,
implementers, academics, and more, collaborating with the community
to maintain and evolve the definition of JavaScript.
`;
Expand Down
99 changes: 60 additions & 39 deletions 1-js/04-object-basics/01-object/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ For multiword properties, the dot access doesn't work:
user.likes birds = true
```

That's because the dot requires the key to be a valid variable identifier. That is: no spaces and other limitations.
JavaScript doesn't understand that. It thinks that we address `user.likes`, and then gives a syntax error when comes across unexpected `birds`.

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).

There's an alternative "square bracket notation" that works with any string:

Expand Down Expand Up @@ -203,43 +205,6 @@ Square brackets are much more powerful than the dot notation. They allow any pro

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.



````smart header="Reserved words are allowed as property names"
A variable cannot have a name equal to one of language-reserved words like "for", "let", "return" etc.
But for an object property, there's no such restriction. Any name is fine:
```js run
let obj = {
for: 1,
let: 2,
return: 3
};
alert( obj.for + obj.let + obj.return ); // 6
```
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:
```js run
let obj = {};
obj.__proto__ = 5;
alert(obj.__proto__); // [object Object], didn't work as intended
```
As we see from the code, the assignment to a primitive `5` is ignored.
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.
In that case the visitor may choose `__proto__` as the key, and the assignment logic will be ruined (as shown above).
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.
There's also another data structure [Map](info:map-set), that we'll learn in the chapter <info:map-set>, which supports arbitrary keys.
````


## Property value shorthand

In real code we often use existing variables as values for property names.
Expand Down Expand Up @@ -284,7 +249,63 @@ let user = {
};
```

## Existence check
## Property names limitations

Property names (keys) must be either strings or symbols (a special type for identifiers, to be covered later).

Other types are automatically converted to strings.

For instance, a number `0` becomes a string `"0"` when used as a property key:

```js run
let obj = {
0: "test" // same as "0": "test"
};

// both alerts access the same property (the number 0 is converted to string "0")
alert( obj["0"] ); // test
alert( obj[0] ); // test (same property)
```

**Reserved words are allowed as property names.**

As we already know, a variable cannot have a name equal to one of language-reserved words like "for", "let", "return" etc.

But for an object property, there's no such restriction. Any name is fine:

```js run
let obj = {
for: 1,
let: 2,
return: 3
};

alert( obj.for + obj.let + obj.return ); // 6
```

We can use any string as a key, but there's a special property named `__proto__` that gets special treatment for historical reasons.

For instance, we can't set it to a non-object value:

```js run
let obj = {};
obj.__proto__ = 5; // assign a number
alert(obj.__proto__); // [object Object] - the value is an object, didn't work as intended
```

As we see from the code, the assignment to a primitive `5` is ignored.

The nature of `__proto__` will be revealed in detail later in the chapter [](info:prototype-inheritance).

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.

The problem is that a visitor may choose `__proto__` as the key, and the assignment logic will be ruined (as shown above).

There are two workarounds for the problem:
1. Modify the object's behavior to treat `__proto__` as a regular property. We'll learn how to do it in the chapter [](info:prototype-methods).
2. Using [Map](info:map-set) data structure which supports arbitrary keys. We'll learn it in the chapter <info:map-set>.

## Property existence test, "in" operator

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:

Expand Down
20 changes: 2 additions & 18 deletions 1-js/04-object-basics/03-symbol/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ let id = Symbol();

Upon creation, we can give symbol a description (also called a symbol name), mostly useful for debugging purposes:

```js run
```js
// id is a symbol with the description "id"
let id = Symbol("id");
```
Expand Down Expand Up @@ -178,22 +178,6 @@ alert( clone[id] ); // 123

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`).

````smart header="Property keys of other types are coerced to strings"
We can only use strings or symbols as keys in objects. Other types are converted to strings.
For instance, a number `0` becomes a string `"0"` when used as a property key:
```js run
let obj = {
0: "test" // same as "0": "test"
};
// both alerts access the same property (the number 0 is converted to string "0")
alert( obj["0"] ); // test
alert( obj[0] ); // test (same property)
```
````

## Global symbols

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.
Expand Down Expand Up @@ -241,7 +225,7 @@ alert( Symbol.keyFor(sym) ); // name
alert( Symbol.keyFor(sym2) ); // id
```

The `Symbol.keyFor` internally uses the global symbol registry to look up the key for the symbol. So it doesn't work for non-global symbols. If the symbol is not global, it won't be able to find it and return `undefined`.
The `Symbol.keyFor` internally uses the global symbol registry to look up the key for the symbol. So it doesn't work for non-global symbols. If the symbol is not global, it won't be able to find it and returns `undefined`.

That said, any symbols have `description` property.

Expand Down
2 changes: 1 addition & 1 deletion 1-js/05-data-types/03-string/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ The "right" algorithm to do string comparisons is more complex than it may seem,

So, the browser needs to know the language to compare.

Luckily, all modern browsers (IE10- requires the additional library [Intl.JS](https://github.com/andyearnshaw/Intl.js/)) support the internationalization standard [ECMA 402](http://www.ecma-international.org/ecma-402/1.0/ECMA-402.pdf).
Luckily, all modern browsers (IE10- requires the additional library [Intl.js](https://github.com/andyearnshaw/Intl.js/)) support the internationalization standard [ECMA-402](http://www.ecma-international.org/ecma-402/1.0/ECMA-402.pdf).

It provides a special method to compare strings in different languages, following their rules.

Expand Down
14 changes: 7 additions & 7 deletions 1-js/05-data-types/04-array/10-maximal-subarray/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ The task is: find the contiguous subarray of `arr` with the maximal sum of items

Write the function `getMaxSubSum(arr)` that will return that sum.

For instance:
For instance:

```js
getMaxSubSum([-1, *!*2, 3*/!*, -9]) = 5 (the sum of highlighted items)
getMaxSubSum([*!*2, -1, 2, 3*/!*, -9]) = 6
getMaxSubSum([-1, 2, 3, -9, *!*11*/!*]) = 11
getMaxSubSum([-2, -1, *!*1, 2*/!*]) = 3
getMaxSubSum([*!*100*/!*, -9, 2, -3, 5]) = 100
getMaxSubSum([*!*1, 2, 3*/!*]) = 6 (take all)
getMaxSubSum([-1, *!*2, 3*/!*, -9]) == 5 (the sum of highlighted items)
getMaxSubSum([*!*2, -1, 2, 3*/!*, -9]) == 6
getMaxSubSum([-1, 2, 3, -9, *!*11*/!*]) == 11
getMaxSubSum([-2, -1, *!*1, 2*/!*]) == 3
getMaxSubSum([*!*100*/!*, -9, 2, -3, 5]) == 100
getMaxSubSum([*!*1, 2, 3*/!*]) == 6 (take all)
```

If all items are negative, it means that we take none (the subarray is empty), so the sum is zero:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ let users = [
let usersById = groupById(users);

/*
// after the call we have:
// after the call we should have:
usersById = {
john: {id: 'john', name: "John Smith", age: 20}
Expand Down
4 changes: 2 additions & 2 deletions 1-js/05-data-types/06-iterable/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ If an object isn't technically an array, but represents a collection (list, set)

We can easily grasp the concept of iterables by making one of our own.

For instance, we have an object, that is not an array, but looks suitable for `for..of`.
For instance, we have an object that is not an array, but looks suitable for `for..of`.

Like a `range` object that represents an interval of numbers:

Expand Down Expand Up @@ -294,7 +294,7 @@ Objects that can be used in `for..of` are called *iterable*.

- Technically, iterables must implement the method named `Symbol.iterator`.
- The result of `obj[Symbol.iterator]` is called an *iterator*. It handles the further iteration process.
- 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.
- 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.
- The `Symbol.iterator` method is called automatically by `for..of`, but we also can do it directly.
- Built-in iterables like strings or arrays, also implement `Symbol.iterator`.
- String iterator knows about surrogate pairs.
Expand Down
1 change: 0 additions & 1 deletion 1-js/05-data-types/08-weakmap-weakset/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ And here's another part of the code, maybe another file using it:
let john = { name: "John" };

countUser(john); // count his visits
countUser(john);

// later john leaves us
john = null;
Expand Down
6 changes: 3 additions & 3 deletions 1-js/06-advanced-functions/01-recursion/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ let company = {
salary: 1000
}, {
name: 'Alice',
salary: 600
salary: 1600
}],
development: {
Expand Down Expand Up @@ -350,7 +350,7 @@ The algorithm is probably even easier to read from the code:
```js run
let company = { // the same object, compressed for brevity
sales: [{name: 'John', salary: 1000}, {name: 'Alice', salary: 600 }],
sales: [{name: 'John', salary: 1000}, {name: 'Alice', salary: 1600 }],
development: {
sites: [{name: 'Peter', salary: 2000}, {name: 'Alex', salary: 1800 }],
internals: [{name: 'Jack', salary: 1300}]
Expand All @@ -372,7 +372,7 @@ function sumSalaries(department) {
}
*/!*
alert(sumSalaries(company)); // 6700
alert(sumSalaries(company)); // 7700
```
The code is short and easy to understand (hopefully?). That's the power of recursion. It also works for any level of subdepartment nesting.
Expand Down
2 changes: 1 addition & 1 deletion 1-js/08-prototypes/01-prototype-inheritance/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The prototype is a little bit "magical". When we want to read a property from `o

The property `[[Prototype]]` is internal and hidden, but there are many ways to set it.

One of them is to use `__proto__`, like this:
One of them is to use the special name `__proto__`, like this:

```js run
let animal = {
Expand Down
2 changes: 1 addition & 1 deletion 1-js/09-classes/01-class/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ class User {
let user = new User("John");
alert(user.name); // John

user = new User(""); // Name too short.
user = new User(""); // Name is too short.
```

The class declaration creates getters and setters in `User.prototype`, like this:
Expand Down
10 changes: 5 additions & 5 deletions 1-js/10-error-handling/1-try-catch/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ No matter how great we are at programming, sometimes our scripts have errors. Th

Usually, a script "dies" (immediately stops) in case of an error, printing it to console.

But there's a syntax construct `try..catch` that allows to "catch" errors and, instead of dying, do something more reasonable.
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.

## The "try..catch" syntax

Expand All @@ -26,13 +26,13 @@ It works like this:

1. First, the code in `try {...}` is executed.
2. If there were no errors, then `catch(err)` is ignored: the execution reaches the end of `try` and goes on, skipping `catch`.
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.
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.

![](try-catch-flow.svg)

So, an error inside the `try {…}` block does not kill the script: we have a chance to handle it in `catch`.
So, an error inside the `try {…}` block does not kill the script -- we have a chance to handle it in `catch`.

Let's see examples.
Let's look at some examples.

- An errorless example: shows `alert` `(1)` and `(2)`:

Expand Down Expand Up @@ -87,7 +87,7 @@ try {
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.
So, `try..catch` can only handle errors that occur in the valid code. Such errors are called "runtime errors" or, sometimes, "exceptions".
So, `try..catch` can only handle errors that occur in valid code. Such errors are called "runtime errors" or, sometimes, "exceptions".
````
Expand Down
2 changes: 1 addition & 1 deletion 1-js/11-async/03-promise-chaining/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ fetch('/article/promise-chaining/user.json')
});
```

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.
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.

We'll also use arrow functions for brevity:

Expand Down
Loading

0 comments on commit 4f6356b

Please sign in to comment.