Skip to content

Commit

Permalink
Merge branch 'master' of github.com:javascript-tutorial/en.javascript…
Browse files Browse the repository at this point in the history
….info into sync-30e3fa72
  • Loading branch information
iliakan committed Oct 21, 2019
2 parents ef6fe59 + 30e3fa7 commit 28eb055
Show file tree
Hide file tree
Showing 41 changed files with 169 additions and 112 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Let's store read messages in `WeakSet`:

```js
```js run
let messages = [
{text: "Hello", from: "John"},
{text: "How goes?", from: "John"},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ let messages = [

Your code can access it, but the messages are managed by someone else's code. New messages are added, old ones are removed regularly by that code, and you don't know the exact moments when it happens.

Now, which data structure you could use to store information whether the message "have been read"? The structure must be well-suited to give the answer "was it read?" for the given message object.
Now, which data structure could you use to store information about whether the message "has been read"? The structure must be well-suited to give the answer "was it read?" for the given message object.

P.S. When a message is removed from `messages`, it should disappear from your structure as well.

Expand Down
4 changes: 2 additions & 2 deletions 1-js/05-data-types/11-date/6-get-seconds-today/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ importance: 5

---

# How many seconds has passed today?
# How many seconds have passed today?

Write a function `getSecondsToday()` that returns the number of seconds from the beginning of today.

For instance, if now `10:00 am`, and there was no daylight savings shift, then:
For instance, if now were `10:00 am`, and there was no daylight savings shift, then:

```js
getSecondsToday() == 36000 // (3600 * 10)
Expand Down
2 changes: 1 addition & 1 deletion 1-js/05-data-types/11-date/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ To create a new `Date` object call `new Date()` with one of the following argume
For instance:

```js
new Date(2011, 0, 1, 0, 0, 0, 0); // // 1 Jan 2011, 00:00:00
new Date(2011, 0, 1, 0, 0, 0, 0); // 1 Jan 2011, 00:00:00
new Date(2011, 0, 1); // the same, hours etc are 0 by default
```

Expand Down
36 changes: 18 additions & 18 deletions 1-js/06-advanced-functions/03-closure/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ To summarize:

### Function Declaration

Till now, we only observed variables. Now enter Function Declarations.
Until now, we only observed variables. Now enter Function Declarations.

**Unlike `let` variables, they are fully initialized not when the execution reaches them, but earlier, when a Lexical Environment is created.**

Expand All @@ -117,7 +117,7 @@ The code below demonstrates that the Lexical Environment is non-empty from the b

Now let's go on and explore what happens when a function accesses an outer variable.

During the call, `say()` uses the outer variable `phrase`, let's look at the details of what's going on.
During the call, `say()` uses the outer variable `phrase`. Let's look at the details of what's going on.

When a function runs, a new Lexical Environment is created automatically to store local variables and parameters of the call.

Expand Down Expand Up @@ -149,7 +149,7 @@ The inner Lexical Environment has a reference to the `outer` one.
**When the code wants to access a variable -- the inner Lexical Environment is searched first, then the outer one, then the more outer one and so on until the global one.**
If a variable is not found anywhere, that's an error in strict mode (without `use strict`, an assignment to a non-existing variable, like `user = "John"` creates a new global variable `user`, that's for backwards compatibility).
If a variable is not found anywhere, that's an error in strict mode. Without `use strict`, an assignment to a non-existing variable like `user = "John"` creates a new global variable `user`. That's for backwards compatibility.
Let's see how the search proceeds in our example:
Expand Down Expand Up @@ -184,8 +184,8 @@ sayHi(); // Pete
The execution flow of the code above:

1. The global Lexical Environment has `name: "John"`.
2. At the line `(*)` the global variable is changed, now it has `name: "Pete"`.
3. When the function `sayHi()`, is executed and takes `name` from outside. Here that's from the global Lexical Environment where it's already `"Pete"`.
2. At the line `(*)` the global variable is changed. Now it has `name: "Pete"`.
3. When the function `sayHi()` is executed it takes `name` from outside, the global Lexical Environment, where its value is already `"Pete"`.


```smart header="One call -- one Lexical Environment"
Expand Down Expand Up @@ -313,25 +313,25 @@ Hopefully, the situation with outer variables is clear now. For most situations

## Environments in detail

Here's what's going on in the `makeCounter` example step-by-step, follow it to make sure that you understand how it works in detail.
Here's what's going on in the `makeCounter` example step-by-step. Follow it to make sure that you understand how it works in detail.

Please note the additional `[[Environment]]` property is covered here. We didn't mention it before for simplicity.

1. When the script has just started, there is only global Lexical Environment:
1. When the script has just started, there is only the global Lexical Environment:

![](lexenv-nested-makecounter-1.svg)

At that starting moment there is only `makeCounter` function, because it's a Function Declaration. It did not run yet.
At that starting moment there is only the `makeCounter` function, because it's a Function Declaration. It did not run yet.

**All functions "on birth" receive a hidden property `[[Environment]]` with a reference to the Lexical Environment of their creation.**

We didn't talk about it yet, that's how the function knows where it was made.
We didn't talk about it before. That's how the function knows where it was made.

Here, `makeCounter` is created in the global Lexical Environment, so `[[Environment]]` keeps a reference to it.

In other words, a function is "imprinted" with a reference to the Lexical Environment where it was born. And `[[Environment]]` is the hidden function property that has that reference.

2. The code runs on, the new global variable `counter` is declared and gets the result of `makeCounter()` call. Here's a snapshot of the moment when the execution is on the first line inside `makeCounter()`:
2. The code runs on, the new global variable `counter` is declared and gets the result of the `makeCounter()` call. Here's a snapshot of the moment when the execution is on the first line inside `makeCounter()`:

![](lexenv-nested-makecounter-2.svg)

Expand Down Expand Up @@ -392,7 +392,7 @@ A [closure](https://en.wikipedia.org/wiki/Closure_(computer_programming)) is a f
That is: they automatically remember where they were created using a hidden `[[Environment]]` property, and all of them can access outer variables.
When on an interview, a frontend developer gets a question about "what's a closure?", a valid answer would be a definition of the closure and an explanation that all functions in JavaScript are closures, and maybe few more words about technical details: the `[[Environment]]` property and how Lexical Environments work.
When on an interview, a frontend developer gets a question about "what's a closure?", a valid answer would be a definition of the closure and an explanation that all functions in JavaScript are closures, and maybe a few more words about technical details: the `[[Environment]]` property and how Lexical Environments work.
```

## Code blocks and loops, IIFE
Expand Down Expand Up @@ -469,13 +469,13 @@ 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 environments in JavaScript.

So programmers had to invent something. And what they did is called "immediately-invoked function expressions" (abbreviated as IIFE).
So programmers had to invent something. And what they did was called "immediately-invoked function expressions" (abbreviated as IIFE).

That's not a thing we should use nowadays, but you can find them in old scripts, so it's better to understand them.

IIFE looks like this:
An IIFE looks like this:

```js run
(function() {
Expand Down Expand Up @@ -511,7 +511,7 @@ function go() {
}(); // <-- can't call Function Declaration immediately
```

So, parentheses around the function is a trick to show JavaScript that the function is created in the context of another expression, and hence it's a Function Expression: it needs no name and can be called immediately.
So, the parentheses around the function is a trick to show JavaScript that the function is created in the context of another expression, and hence it's a Function Expression: it needs no name and can be called immediately.

There exist other ways besides parentheses to tell JavaScript that we mean a Function Expression:

Expand Down Expand Up @@ -539,7 +539,7 @@ In all the above cases we declare a Function Expression and run it immediately.

## Garbage collection

Usually, a Lexical Environment is cleaned up and deleted after the function run. For instance:
Usually, a Lexical Environment is cleaned up and deleted after the function runs. For instance:

```js
function f() {
Expand All @@ -550,7 +550,7 @@ function f() {
f();
```

Here two values are technically the properties of the Lexical Environment. But after `f()` finishes that Lexical Environment becomes unreachable, so it's deleted from the memory.
Here, two values are technically the properties of the Lexical Environment. But after `f()` finishes, that Lexical Environment becomes unreachable, so it's deleted from the memory.

...But if there's a nested function that is still reachable after the end of `f`, then it has `[[Environment]]` property that references the outer lexical environment, so it's also reachable and alive:

Expand Down Expand Up @@ -584,7 +584,7 @@ let arr = [f(), f(), f()];

A Lexical Environment object dies when it becomes unreachable (just like any other object). In other words, it exists only while there's at least one nested function referencing it.

In the code below, after `g` becomes unreachable, enclosing Lexical Environment (and hence the `value`) is cleaned from memory;
In the code below, after `g` becomes unreachable, its enclosing Lexical Environment (and hence the `value`) is cleaned from memory;

```js
function f() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ describe("debounce", function() {
this.clock.restore();
});

it("trigger the fuction execution immediately", function () {
let mode;
const f = () => mode='leading';

debounce(f, 1000)(); // runs without a delay

assert.equal(mode, 'leading');
});

it("calls the function at maximum once in ms milliseconds", function() {
let log = '';

Expand Down Expand Up @@ -38,4 +47,4 @@ describe("debounce", function() {
obj.f("test");
});

});
});
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ function throttle(func, ms) {
A call to `throttle(func, ms)` returns `wrapper`.

1. During the first call, the `wrapper` just runs `func` and sets the cooldown state (`isThrottled = true`).
2. In this state all calls memorized in `savedArgs/savedThis`. Please note that both the context and the arguments are equally important and should be memorized. We need them simultaneously to reproduce the call.
3. ...Then after `ms` milliseconds pass, `setTimeout` triggers. The cooldown state is removed (`isThrottled = false`). And if we had ignored calls, then `wrapper` is executed with last memorized arguments and context.
2. In this state all calls are memorized in `savedArgs/savedThis`. Please note that both the context and the arguments are equally important and should be memorized. We need them simultaneously to reproduce the call.
3. After `ms` milliseconds pass, `setTimeout` triggers. The cooldown state is removed (`isThrottled = false`) and, if we had ignored calls, `wrapper` is executed with the last memorized arguments and context.

The 3rd step runs not `func`, but `wrapper`, because we not only need to execute `func`, but once again enter the cooldown state and setup the timeout to reset it.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Let's check the real-life application to better understand that requirement and

**For instance, we want to track mouse movements.**

In browser we can setup a function to run at every mouse movement and get the pointer location as it moves. During an active mouse usage, this function usually runs very frequently, can be something like 100 times per second (every 10 ms).
In a browser we can setup a function to run at every mouse movement and get the pointer location as it moves. During an active mouse usage, this function usually runs very frequently, can be something like 100 times per second (every 10 ms).

**We'd like to update some information on the web-page when the pointer moves.**

Expand All @@ -31,8 +31,8 @@ A code example:

```js
function f(a) {
console.log(a)
};
console.log(a);
}

// f1000 passes calls to f at maximum once per 1000 ms
let f1000 = throttle(f, 1000);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ let worker = {
},

slow(x) {
// actually, there can be a scary CPU-heavy task here
// scary CPU-heavy task here
alert("Called with " + x);
return x * this.someMethod(); // (*)
}
Expand Down Expand Up @@ -372,7 +372,7 @@ hash(1, 2);

The trick is called *method borrowing*.

We take (borrow) a join method from a regular array `[].join`. And use `[].join.call` to run it in the context of `arguments`.
We take (borrow) a join method from a regular array (`[].join`) and use `[].join.call` to run it in the context of `arguments`.

Why does it work?

Expand Down
26 changes: 18 additions & 8 deletions 1-js/11-async/01-callbacks/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@

# Introduction: callbacks

Many actions in JavaScript are *asynchronous*.
```warn header="We use browser methods here"
To demonstrate the use of callbacks, promises and other abstract concepts, we'll be using some browser methods; specifically, loading scripts and performing simple document manipulations.
For instance, take a look at the function `loadScript(src)`:
If you're not familiar with these methods, and their usage in the examples is confusing, or if you would just like to understand them better, you may want to read a few chapters from the [next part](/document) of the tutorial.
```

Many actions in JavaScript are *asynchronous*. In other words, we initiate them now, but they finish later.

For instance, we can schedule such actions using `setTimeout`.

There are other real-world examples of asynchronous actions, e.g. loading scripts and modules (we'll cover them in later chapters).

Take a look at the function `loadScript(src)`, that loads a script with the given `src`:

```js
function loadScript(src) {
Expand All @@ -14,18 +24,18 @@ function loadScript(src) {
}
```

The purpose of the function is to load a new script. When it adds the `<script src="…">` to the document, the browser loads and executes it.
It appends to the document the new, dynamically created, tag `<script src="…">`, the browser loads and executes it.

We can use it like this:
We can use this function like this:

```js
// loads and executes the script
// load and execute the script at the given path
loadScript('/my/script.js');
```

The function is called "asynchronously," because the action (script loading) finishes not now, but later.
The script is executed "asynchronously", as it starts loading starts now, but runs later, when the function has already finished.

If there's a code below `loadScript(…)`, it doesn't wait until the loading finishes.
If there's a code below `loadScript(…)`, it doesn't wait until the script loading finishes.

```js
loadScript('/my/script.js');
Expand All @@ -34,7 +44,7 @@ loadScript('/my/script.js');
// ...
```

We'd like to use the new script as soon as it loads. It declares new functions, and we want to run them.
Let's say we need to use the new script as soon as it loads. It declares new functions, and we want to run them.

But if we do that immediately after the `loadScript(…)` call, that wouldn't work:

Expand Down
2 changes: 1 addition & 1 deletion 1-js/99-js-misc/01-proxy/01-error-nonexisting/solution.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@ function wrap(target) {
user = wrap(user);

alert(user.name); // John
alert(user.age); // Error: Property doesn't exist
alert(user.age); // ReferenceError: Property doesn't exist
```
Loading

0 comments on commit 28eb055

Please sign in to comment.