more typos
This commit is contained in:
parent
dc1a4fb6ad
commit
fb6b393f0c
6 changed files with 23 additions and 23 deletions
|
@ -43,7 +43,7 @@ let user = new User("John");
|
||||||
user.sayHi();
|
user.sayHi();
|
||||||
```
|
```
|
||||||
|
|
||||||
It's easy to see that the two examples are alike. So, what exactly the `class` does? We may think that it defines a new language-level entity, but that would be wrong.
|
It's easy to see that the two examples are alike. So, what exactly does `class` do? We may think that it defines a new language-level entity, but that would be wrong.
|
||||||
|
|
||||||
The `class User {...}` here actually does two things:
|
The `class User {...}` here actually does two things:
|
||||||
|
|
||||||
|
@ -98,11 +98,11 @@ Class definition sets `enumerable` flag to `false` for all methods in the `"prot
|
||||||
```
|
```
|
||||||
|
|
||||||
```smart header="What if there's no constructor?"
|
```smart header="What if there's no constructor?"
|
||||||
If there's no `constructor` in the `class` construct, then an empty function is generated, same as if write `constructor() {}`.
|
If there's no `constructor` in the `class` construct, then an empty function is generated, same as if we had written `constructor() {}`.
|
||||||
```
|
```
|
||||||
|
|
||||||
```smart header="Classes always `use strict`"
|
```smart header="Classes always `use strict`"
|
||||||
All code inside the class construct is automatically in the strict mode.
|
All code inside the class construct is automatically in strict mode.
|
||||||
```
|
```
|
||||||
|
|
||||||
### Getters/setters
|
### Getters/setters
|
||||||
|
@ -273,7 +273,7 @@ articles.sort(Article.compare);
|
||||||
alert( articles[0].title ); // Body
|
alert( articles[0].title ); // Body
|
||||||
```
|
```
|
||||||
|
|
||||||
Here `Article.compare` stands "over" the articles, as a meants to compare them.
|
Here `Article.compare` stands "over" the articles, as a means to compare them.
|
||||||
|
|
||||||
Another example would be a so-called "factory" method, that creates an object with specific parameters.
|
Another example would be a so-called "factory" method, that creates an object with specific parameters.
|
||||||
|
|
||||||
|
|
|
@ -163,7 +163,7 @@ setTimeout(function() { super.stop() }, 1000);
|
||||||
|
|
||||||
With constructors, things are is a little bit tricky.
|
With constructors, things are is a little bit tricky.
|
||||||
|
|
||||||
Till now, `Rabbit` had no its own `constructor`.
|
Till now, `Rabbit` did not have its own `constructor`.
|
||||||
|
|
||||||
According to the [specification](https://tc39.github.io/ecma262/#sec-runtime-semantics-classdefinitionevaluation), if a class extends another class and has no `constructor`, then the following `constructor` is generated:
|
According to the [specification](https://tc39.github.io/ecma262/#sec-runtime-semantics-classdefinitionevaluation), if a class extends another class and has no `constructor`, then the following `constructor` is generated:
|
||||||
|
|
||||||
|
@ -271,7 +271,7 @@ Yeah, indeed, let's ask ourselves, how it could technically work? When an object
|
||||||
|
|
||||||
Maybe we can get it `[[Prototype]]` of `this`, as `this.__proto__.method`? Unfortunately, that won't work.
|
Maybe we can get it `[[Prototype]]` of `this`, as `this.__proto__.method`? Unfortunately, that won't work.
|
||||||
|
|
||||||
Let's try to do it. Without classes, using plain objects for sheer simplicity.
|
Let's try to do it. Without classes, using plain objects for the sake of simplicity.
|
||||||
|
|
||||||
Here, `rabbit.eat()` should call `animal.eat()` method of the parent object:
|
Here, `rabbit.eat()` should call `animal.eat()` method of the parent object:
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,7 @@ alert( rabbit instanceof Rabbit ); // false
|
||||||
*/!*
|
*/!*
|
||||||
```
|
```
|
||||||
|
|
||||||
That's one of reasons to evade changing `prototype`. Just to keep safe.
|
That's one of reasons to avoid changing `prototype`. Just to keep safe.
|
||||||
|
|
||||||
## Bonus: Object toString for the type
|
## Bonus: Object toString for the type
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ new User("Dude").sayHi(); // Hi Dude!
|
||||||
|
|
||||||
There's no inheritance, there's a simple method copying. So `User` may extend some other class and also include the mixin to "mix-in" the additional methods.
|
There's no inheritance, there's a simple method copying. So `User` may extend some other class and also include the mixin to "mix-in" the additional methods.
|
||||||
|
|
||||||
Mixins also can also make use of inheritance.
|
Mixins also can make use of inheritance.
|
||||||
|
|
||||||
For instance, here `sayHiMixin` inherits from `sayMixin`:
|
For instance, here `sayHiMixin` inherits from `sayMixin`:
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ Now a mixin for the real life.
|
||||||
|
|
||||||
The important feature of many objects is working with events.
|
The important feature of many objects is working with events.
|
||||||
|
|
||||||
That is: an object should have a method to "generate an event" when something important happens to him, and other objects should be able to "subscribe" to receive such notifications.
|
That is: an object should have a method to "generate an event" when something important happens to it, and other objects should be able to "subscribe" to receive such notifications.
|
||||||
|
|
||||||
An event must have a name and, if necessary, the attached data.
|
An event must have a name and, if necessary, the attached data.
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ Or, the object `menu` can generate the event `"select"` when a menu item is sele
|
||||||
|
|
||||||
Events is a way to "share information" with anyone who wants it.
|
Events is a way to "share information" with anyone who wants it.
|
||||||
|
|
||||||
The `eventMixin` to implement the corresponding methods:
|
Here is `eventMixin` that implements the corresponding methods:
|
||||||
|
|
||||||
```js run
|
```js run
|
||||||
let eventMixin = {
|
let eventMixin = {
|
||||||
|
@ -156,7 +156,7 @@ let eventMixin = {
|
||||||
|
|
||||||
There are 3 methods here:
|
There are 3 methods here:
|
||||||
|
|
||||||
1. `.on(eventName, handler)` -- assigns the function `handler` to run when the event with that name happens. The handlers are stored in `_eventHandlers` property.
|
1. `.on(eventName, handler)` -- assigns function `handler` to run when the event with that name happens. The handlers are stored in the `_eventHandlers` property.
|
||||||
2. `.off(eventName, handler)` -- removes the function from the handlers list.
|
2. `.off(eventName, handler)` -- removes the function from the handlers list.
|
||||||
3. `.trigger(eventName, ...args)` -- generates the event: all assigned handlers are called and `args` are passed as arguments to them.
|
3. `.trigger(eventName, ...args)` -- generates the event: all assigned handlers are called and `args` are passed as arguments to them.
|
||||||
|
|
||||||
|
@ -192,8 +192,8 @@ And the `eventMixin` can add such behavior to as many classes as we'd like, with
|
||||||
|
|
||||||
*Mixin* -- is a generic object-oriented programming term: a class that contains methods for other classes.
|
*Mixin* -- is a generic object-oriented programming term: a class that contains methods for other classes.
|
||||||
|
|
||||||
In JavaScript that can be implemented as copying them into the prototype.
|
Some other languages like e.g. python allow to create mixins using multiple inheritance. JavaScript does not support multiple inheritance, but mixins can be implemented by copying them into the prototype.
|
||||||
|
|
||||||
We can use mixins as a way to augment a class by multiple behaviors like event-handling that we overlooked above.
|
We can use mixins as a way to augment a class by multiple behaviors, like event-handling as we have seen above.
|
||||||
|
|
||||||
Mixins may become a point of conflict if they occasionally overwrite native class methods. So generally one should think well about the naming for a mixin, to minimalize such possibility.
|
Mixins may become a point of conflict if they occasionally overwrite native class methods. So generally one should think well about the naming for a mixin, to minimize such possibility.
|
||||||
|
|
|
@ -110,7 +110,7 @@ try {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
That's because `try..catch` actually wraps the `setTimeout` call that schedules the function. But the function itself is executed later, when the engine has already have left `try..catch` contruct.
|
That's because `try..catch` actually wraps the `setTimeout` call that schedules the function. But the function itself is executed later, when the engine has already have left the `try..catch` construct.
|
||||||
|
|
||||||
To catch an exception inside a scheduled function, `try..catch` must be inside that function:
|
To catch an exception inside a scheduled function, `try..catch` must be inside that function:
|
||||||
```js run
|
```js run
|
||||||
|
@ -222,7 +222,7 @@ try {
|
||||||
|
|
||||||
Here we use `catch` block only to show the message, but we can do much more: a new network request, suggest an alternative to the visitor, send the information about the error to a logging facility... All much better than just dying.
|
Here we use `catch` block only to show the message, but we can do much more: a new network request, suggest an alternative to the visitor, send the information about the error to a logging facility... All much better than just dying.
|
||||||
|
|
||||||
## Throwing own errors
|
## Throwing our own errors
|
||||||
|
|
||||||
What if `json` is syntactically correct... But doesn't have a required `"name"` property?
|
What if `json` is syntactically correct... But doesn't have a required `"name"` property?
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ try {
|
||||||
|
|
||||||
Here `JSON.parse` runs normally, but the absence of `"name"` is actually an error for us.
|
Here `JSON.parse` runs normally, but the absence of `"name"` is actually an error for us.
|
||||||
|
|
||||||
To unify error handling, we'll use `throw` operator.
|
To unify error handling, we'll use the `throw` operator.
|
||||||
|
|
||||||
### "Throw" operator
|
### "Throw" operator
|
||||||
|
|
||||||
|
@ -344,7 +344,7 @@ try {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Of course, everything's possible! Programmers do make mistakes. Even in open-source utilities used by millions for decades -- suddenly a crazy bug may be discovered that leads to terrible hacks (like it happened with `ssh` tool).
|
Of course, everything's possible! Programmers do make mistakes. Even in open-source utilities used by millions for decades -- suddenly a crazy bug may be discovered that leads to terrible hacks (like it happened with the `ssh` tool).
|
||||||
|
|
||||||
In our case, `try..catch` is meant to catch "incorrect data" errors. But by its nature, `catch` gets *all* errors from `try`. Here it gets an unexpected error, but still shows the same `"JSON Error"` message. That's wrong and also makes the code more difficult to debug.
|
In our case, `try..catch` is meant to catch "incorrect data" errors. But by its nature, `catch` gets *all* errors from `try`. Here it gets an unexpected error, but still shows the same `"JSON Error"` message. That's wrong and also makes the code more difficult to debug.
|
||||||
|
|
||||||
|
@ -368,7 +368,7 @@ The "rethrowing" technique can be explained in more detail as:
|
||||||
|
|
||||||
1. Catch gets all errors.
|
1. Catch gets all errors.
|
||||||
2. In `catch(err) {...}` block we analyze the error object `err`.
|
2. In `catch(err) {...}` block we analyze the error object `err`.
|
||||||
2. If we don't know how to handle it, then do `throw err`.
|
2. If we don't know how to handle it, then we do `throw err`.
|
||||||
|
|
||||||
In the code below, we use rethrowing so that `catch` only handles `SyntaxError`:
|
In the code below, we use rethrowing so that `catch` only handles `SyntaxError`:
|
||||||
|
|
||||||
|
@ -401,7 +401,7 @@ try {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The error throwin in the line `(*)` from inside `catch` block "falls out" of `try..catch` and can be either caught by an outer `try..catch` construct (if exists), or it kills the script.
|
The error throwing on line `(*)` from inside `catch` block "falls out" of `try..catch` and can be either caught by an outer `try..catch` construct (if it exists), or it kills the script.
|
||||||
|
|
||||||
So the `catch` block actually handles only errors that it knows how to deal with and "skips" all others.
|
So the `catch` block actually handles only errors that it knows how to deal with and "skips" all others.
|
||||||
|
|
||||||
|
@ -480,7 +480,7 @@ The code has two ways of execution:
|
||||||
|
|
||||||
The `finally` clause is often used when we start doing something before `try..catch` and want to finalize it in any case of outcome.
|
The `finally` clause is often used when we start doing something before `try..catch` and want to finalize it in any case of outcome.
|
||||||
|
|
||||||
For instance, we want to measure time that a Fibonacci numbers function `fib(n)` takes. Naturally, we can start measuring before it runs and finish afterwards. But what is there's an error during the function call? In particular, the implementation of `fib(n)` in the code below returns an error for negative or non-integer numbers.
|
For instance, we want to measure time that a Fibonacci numbers function `fib(n)` takes. Naturally, we can start measuring before it runs and finish afterwards. But what if there's an error during the function call? In particular, the implementation of `fib(n)` in the code below returns an error for negative or non-integer numbers.
|
||||||
|
|
||||||
The `finally` clause is a great place to finish the measurements no matter what.
|
The `finally` clause is a great place to finish the measurements no matter what.
|
||||||
|
|
||||||
|
@ -577,7 +577,7 @@ The information from this section is not a part of the core JavaScript.
|
||||||
|
|
||||||
Let's imagine we've got a fatal error outside of `try..catch`, and the script died. Like a programming error or something else terrible.
|
Let's imagine we've got a fatal error outside of `try..catch`, and the script died. Like a programming error or something else terrible.
|
||||||
|
|
||||||
Is there a way to react on such a happening? We may want to log the error, show something to the user (normally he doesn't see error messages) etc.
|
Is there a way to react on such occurrences? We may want to log the error, show something to the user (normally he doesn't see error messages) etc.
|
||||||
|
|
||||||
There is none in the specification, but environments usually provide it, because it's really useful. For instance, Node.JS has [process.on('uncaughtException')](https://nodejs.org/api/process.html#process_event_uncaughtexception) for that. And in the browser we can assign a function to special [window.onerror](mdn:api/GlobalEventHandlers/onerror) property. It will run in case of an uncaught error.
|
There is none in the specification, but environments usually provide it, because it's really useful. For instance, Node.JS has [process.on('uncaughtException')](https://nodejs.org/api/process.html#process_event_uncaughtexception) for that. And in the browser we can assign a function to special [window.onerror](mdn:api/GlobalEventHandlers/onerror) property. It will run in case of an uncaught error.
|
||||||
|
|
||||||
|
|
|
@ -168,7 +168,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.
|
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.
|
||||||
|
|
||||||
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.
|
Please note that `this.name` in `PropertyRequiredError` once again is 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.
|
||||||
|
|
||||||
Here we go:
|
Here we go:
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue