Skip to content

Commit

Permalink
Merge pull request #1 from javascript-tutorial/master
Browse files Browse the repository at this point in the history
update
  • Loading branch information
DouglasMV authored Jun 11, 2019
2 parents e4300bb + e1c0d62 commit 88b8604
Show file tree
Hide file tree
Showing 37 changed files with 202 additions and 186 deletions.
12 changes: 10 additions & 2 deletions 1-js/02-first-steps/03-strict-mode/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,17 @@ For the future, when you use a browser console to test features, please note tha
Sometimes, when `use strict` makes a difference, you'll get incorrect results.
Even if we press `key:Shift+Enter` to input multiple lines, and put `use strict` on top, it doesn't work. That's because of how the console executes the code internally.
You can try to press `key:Shift+Enter` to input multiple lines, and put `use strict` on top, like this:
The reliable way to ensure `use strict` would be to input the code into console like this:
```js
'use strict'; <Shift+Enter for a newline>
// ...your code
<Enter to run>
```

It works in most browsers, namely Firefox and Chrome.

If it doesn't, the most reliable way to ensure `use strict` would be to input the code into console like this:

```js
(function() {
Expand Down
9 changes: 4 additions & 5 deletions 1-js/03-code-quality/04-ninja-code/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ Instead, reuse existing names. Just write new values into them.

In a function try to use only variables passed as parameters.

That would make it really hard to identify what's exactly in the variable *now*. And also where it comes from. A person with weak intuition would have to analyze the code line-by-line and track the changes through every code branch.
That would make it really hard to identify what's exactly in the variable *now*. And also where it comes from. The purpose is to develop the intuition and memory of a person reading the code. A person with weak intuition would have to analyze the code line-by-line and track the changes through every code branch.

**An advanced variant of the approach is to covertly (!) replace the value with something alike in the middle of a loop or a function.**

Expand All @@ -155,7 +155,7 @@ function ninjaFunction(elem) {

A fellow programmer who wants to work with `elem` in the second half of the function will be surprised... Only during the debugging, after examining the code they will find out that they're working with a clone!

Seen in code regularly. Deadly effective even against an experienced ninja.
Seen in code regularly. Deadly effective even against an experienced ninja.

## Underscores for fun

Expand All @@ -169,8 +169,7 @@ A smart ninja puts underscores at one spot of code and evades them at other plac

Let everyone see how magnificent your entities are! Names like `superElement`, `megaFrame` and `niceItem` will definitely enlighten a reader.

Indeed, from one hand, something is written: `super..`, `mega..`, `nice..` But from the other hand -- that brings no details. A reader may decide to look for a hidden meaning and meditate for an hour or two.

Indeed, from one hand, something is written: `super..`, `mega..`, `nice..` But from the other hand -- that brings no details. A reader may decide to look for a hidden meaning and meditate for an hour or two of their paid working time.


## Overlap outer variables
Expand All @@ -180,7 +179,7 @@ When in the light, can't see anything in the darkness.<br>
When in the darkness, can see everything in the light.
```

Use same names for variables inside and outside a function. As simple. No efforts required.
Use same names for variables inside and outside a function. As simple. No efforts to invent new names.

```js
let *!*user*/!* = authenticateUser();
Expand Down
2 changes: 1 addition & 1 deletion 1-js/04-object-basics/02-garbage-collection/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,6 @@ A general book "The Garbage Collection Handbook: The Art of Automatic Memory Man

If you are familiar with low-level programming, the more detailed information about V8 garbage collector is in the article [A tour of V8: Garbage Collection](http://jayconrod.com/posts/55/a-tour-of-v8-garbage-collection).

[V8 blog](http://v8project.blogspot.com/) also publishes articles about changes in memory management from time to time. Naturally, to learn the garbage collection, you'd better prepare by learning about V8 internals in general and read the blog of [Vyacheslav Egorov](http://mrale.ph) who worked as one of V8 engineers. I'm saying: "V8", because it is best covered with articles in the internet. For other engines, many approaches are similar, but garbage collection differs in many aspects.
[V8 blog](https://v8.dev/) also publishes articles about changes in memory management from time to time. Naturally, to learn the garbage collection, you'd better prepare by learning about V8 internals in general and read the blog of [Vyacheslav Egorov](http://mrale.ph) who worked as one of V8 engineers. I'm saying: "V8", because it is best covered with articles in the internet. For other engines, many approaches are similar, but garbage collection differs in many aspects.

In-depth knowledge of engines is good when you need low-level optimizations. It would be wise to plan that as the next step after you're familiar with the language.
22 changes: 13 additions & 9 deletions 1-js/04-object-basics/04-object-methods/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ user.sayHi(); // Hello!
```smart header="Object-oriented programming"
When we write our code using objects to represent entities, that's called an [object-oriented programming](https://en.wikipedia.org/wiki/Object-oriented_programming), in short: "OOP".
OOP is a big thing, an interesting science of its own. How to choose the right entities? How to organize the interaction between them? That's architecture, and there are great books on that topic, like "Design Patterns: Elements of Reusable Object-Oriented Software" by E.Gamma, R.Helm, R.Johnson, J.Vissides or "Object-Oriented Analysis and Design with Applications" by G.Booch, and more.
OOP is a big thing, an interesting science of its own. How to choose the right entities? How to organize the interaction between them? That's architecture, and there are great books on that topic, like "Design Patterns: Elements of Reusable Object-Oriented Software" by E.Gamma, R.Helm, R.Johnson, J.Vissides or "Object-Oriented Analysis and Design with Applications" by G.Booch, and more.
```
### Method shorthand

Expand All @@ -72,14 +72,14 @@ There exists a shorter syntax for methods in an object literal:
```js
// these objects do the same

let user = {
user = {
sayHi: function() {
alert("Hello");
}
};

// method shorthand looks better, right?
let user = {
user = {
*!*
sayHi() { // same as "sayHi: function()"
*/!*
Expand Down Expand Up @@ -166,7 +166,7 @@ If we used `this.name` instead of `user.name` inside the `alert`, then the code

## "this" is not bound

In JavaScript, "this" keyword behaves unlike most other programming languages. First, it can be used in any function.
In JavaScript, "this" keyword behaves unlike most other programming languages. It can be used in any function.

There's no syntax error in the code like that:

Expand All @@ -176,9 +176,9 @@ function sayHi() {
}
```

The value of `this` is evaluated during the run-time. And it can be anything.
The value of `this` is evaluated during the run-time, depending on the context. And it can be anything.

For instance, the same function may have different "this" when called from different objects:
For instance, here the same function is assigned to two different objects and has different "this" in the calls:

```js run
let user = { name: "John" };
Expand All @@ -189,7 +189,7 @@ function sayHi() {
}

*!*
// use the same functions in two objects
// use the same function in two objects
user.f = sayHi;
admin.f = sayHi;
*/!*
Expand All @@ -202,7 +202,10 @@ admin.f(); // Admin (this == admin)
admin['f'](); // Admin (dot or square brackets access the method – doesn't matter)
```

Actually, we can call the function without an object at all:
The rule is simple: if `obj.f()` is called, then `this` is `obj` during the call of `f`. So it's either `user` or `admin` in the example above.

````smart header="Calling without an object: `this == undefined`"
We can even call the function without an object at all:

```js run
function sayHi() {
Expand All @@ -216,7 +219,8 @@ In this case `this` is `undefined` in strict mode. If we try to access `this.nam

In non-strict mode the value of `this` in such case will be the *global object* (`window` in a browser, we'll get to it later in the chapter [](info:global-object)). This is a historical behavior that `"use strict"` fixes.

Please note that usually a call of a function that uses `this` without an object is not normal, but rather a programming mistake. If a function has `this`, then it is usually meant to be called in the context of an object.
Usually such call is an programming error. If there's `this` inside a function, it expects to be called in an object context.
````
```smart header="The consequences of unbound `this`"
If you come from another programming language, then you are probably used to the idea of a "bound `this`", where methods defined in an object always have `this` referencing that object.
Expand Down
4 changes: 2 additions & 2 deletions 1-js/05-data-types/07-map-set-weakmap-weakset/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,9 @@ set.forEach((value, valueAgain, set) => {
});
```
Note the funny thing. The `forEach` function in the `Set` has 3 arguments: a value, then *again a value*, and then the target object. Indeed, the same value appears in the arguments twice.
Note the funny thing. The callback function passed in `forEach` has 3 arguments: a value, then *again a value*, and then the target object. Indeed, the same value appears in the arguments twice.
That's for compatibility with `Map` where `forEach` has three arguments. Looks a bit strange, for sure. But may help to replace `Map` with `Set` in certain cases with ease, and vice versa.
That's for compatibility with `Map` where the callback passed `forEach` has three arguments. Looks a bit strange, for sure. But may help to replace `Map` with `Set` in certain cases with ease, and vice versa.
The same methods `Map` has for iterators are also supported:
Expand Down
2 changes: 1 addition & 1 deletion 1-js/05-data-types/11-json/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ alert(json);

The method `JSON.stringify(student)` takes the object and converts it into a string.

The resulting `json` string is a called *JSON-encoded* or *serialized* or *stringified* or *marshalled* object. We are ready to send it over the wire or put into a plain data store.
The resulting `json` string is called a *JSON-encoded* or *serialized* or *stringified* or *marshalled* object. We are ready to send it over the wire or put into a plain data store.


Please note that a JSON-encoded object has several important differences from the object literal:
Expand Down
25 changes: 10 additions & 15 deletions 1-js/06-advanced-functions/11-currying-partials/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ To understand the benefits we definitely need a worthy real-life example.

Advanced currying allows the function to be both callable normally and partially.

For instance, we have the logging function `log(date, importance, message)` that formats and outputs the information. In real projects such functions also have many other useful features like sending logs over the network:
For instance, we have the logging function `log(date, importance, message)` that formats and outputs the information. In real projects such functions also have many other useful features like sending logs over the network, here we just use `alert`:

```js
function log(date, importance, message) {
Expand All @@ -184,34 +184,29 @@ Let's curry it!
log = _.curry(log);
```

After that `log` still works the normal way:

```js
log(new Date(), "DEBUG", "some debug");
```

...But also can be called in the curried form:
After that `log` work both the normal way and in the curried form:

```js
log(new Date(), "DEBUG", "some debug"); // log(a,b,c)
log(new Date())("DEBUG")("some debug"); // log(a)(b)(c)
```

Let's get a convenience function for today's logs:
Now we can easily make a convenience function for current logs:

```js
// todayLog will be the partial of log with fixed first argument
let todayLog = log(new Date());
// currentLog will be the partial of log with fixed first argument
let logNow = log(new Date());

// use it
todayLog("INFO", "message"); // [HH:mm] INFO message
logNow("INFO", "message"); // [HH:mm] INFO message
```

And now a convenience function for today's debug messages:
And here's a convenience function for current debug messages:

```js
let todayDebug = todayLog("DEBUG");
let debugNow = logNow("DEBUG");

todayDebug("message"); // [HH:mm] DEBUG message
debugNow("message"); // [HH:mm] DEBUG message
```

So:
Expand Down
2 changes: 1 addition & 1 deletion 1-js/08-prototypes/02-function-prototype/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ Everything is quite simple, just few notes to make things clear:

- The `F.prototype` property is not the same as `[[Prototype]]`. The only thing `F.prototype` does: it sets `[[Prototype]]` of new objects when `new F()` is called.
- The value of `F.prototype` should be either an object or null: other values won't work.
- The `"prototype"` property only has such a special effect when is set to a constructor function, and invoked with `new`.
- The `"prototype"` property only has such a special effect when set on a constructor function, and invoked with `new`.

On regular objects the `prototype` is nothing special:
```js
Expand Down
9 changes: 5 additions & 4 deletions 1-js/09-classes/01-class/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ The notation here is not to be confused with object literals. Within the class,

## What is a class?

So, what exactly is a `class`? That's not an entirely new language-level entity, as one might think.
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.

Expand All @@ -91,7 +91,7 @@ What `class User {...}` construct really does is:

Afterwards, for new objects, when we call a method, it's taken from the prototype, just as described in the chapter <info:function-prototype>. So `new User` object has access to class methods.

We can illustrate the result of `class User` as:
We can illustrate the result of `class User` declaration as:

![](class-user.png)

Expand Down Expand Up @@ -198,7 +198,8 @@ Similar to Named Function Expressions, class expressions may or may not have a n
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)
// "Named Class Expression"
// (no such term in the spec, but that's similar to Named Function Expression)
let User = class *!*MyClass*/!* {
sayHi() {
alert(MyClass); // MyClass is visible only inside the class
Expand Down Expand Up @@ -268,7 +269,7 @@ alert(user.name); // John
user = new User(""); // Name too short.
```

Internally, getters and setters are created on `User.prototype`, like this:
The class declaration creates getters and setters in `User.prototype`, like this:

```js
Object.defineProperties(User.prototype, {
Expand Down
12 changes: 6 additions & 6 deletions 1-js/10-error-handling/2-custom-errors/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Our errors should support basic error properties like `message`, `name` and, pre

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.

As we build our application, our own errors naturally form a hierarchy, for instance `HttpTimeoutError` may inherit from `HttpError`, and so on.
As the application grows, our own errors naturally form a hierarchy, for instance `HttpTimeoutError` may inherit from `HttpError`, and so on.

## Extending Error

Expand Down Expand Up @@ -126,7 +126,7 @@ We could also look at `err.name`, like this:
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.
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.
Also it's important that if `catch` meets an unknown error, then it rethrows it in the line `(**)`. The `catch` block only knows how to handle validation and syntax errors, other kinds (due to a typo in the code or other unknown ones) should fall through.
## Further inheritance
Expand Down Expand Up @@ -185,7 +185,7 @@ try {
The new class `PropertyRequiredError` is easy to use: we only need to pass the property name: `new PropertyRequiredError(property)`. The human-readable `message` is generated by the constructor.
Please note that `this.name` in `PropertyRequiredError` constructor is again assigned manually. That may become a bit tedious -- to assign `this.name = <class name>` 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.
Please note that `this.name` in `PropertyRequiredError` constructor is again assigned manually. That may become a bit tedious -- to assign `this.name = <class name>` in every custom error class. 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 its constructor. And then inherit all ours custom errors from it.
Let's call it `MyError`.
Expand Down Expand Up @@ -218,7 +218,7 @@ Now custom errors are much shorter, especially `ValidationError`, as we got rid
## Wrapping exceptions
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.
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 and probably generate other kinds of errors.
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`?
Expand Down Expand Up @@ -303,5 +303,5 @@ The approach is called "wrapping exceptions", because we take "low level excepti
## Summary
- We can inherit from `Error` and other built-in error classes normally, just need to take care of `name` property and don't forget to call `super`.
- Most of the time, we should use `instanceof` to check for particular errors. It also works with inheritance. But sometimes we have an error object coming from the 3rd-party library and there's no easy way to get the class. Then `name` property can be used for such checks.
- Wrapping exceptions is a widespread technique when a function handles low-level exceptions and makes a higher-level object to report about the errors. Low-level exceptions sometimes become properties of that object like `err.cause` in the examples above, but that's not strictly required.
- We can use `instanceof` to check for particular errors. It also works with inheritance. But sometimes we have an error object coming from the 3rd-party library and there's no easy way to get the class. Then `name` property can be used for such checks.
- Wrapping exceptions is a widespread technique: a function handles low-level exceptions and creates higher-level errors instead of various low-level ones. Low-level exceptions sometimes become properties of that object like `err.cause` in the examples above, but that's not strictly required.
2 changes: 1 addition & 1 deletion 1-js/11-async/02-promise-basics/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ The good thing is: a `.then` handler is guaranteed to run whether the promise ta

Next, let's see more practical examples of how promises can help us to write asynchronous code.

## Example: loadScript
## Example: loadScript [#loadscript]

We've got the `loadScript` function for loading a script from the previous chapter.

Expand Down
Loading

0 comments on commit 88b8604

Please sign in to comment.