Skip to content

Commit

Permalink
fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
iliakan committed Jun 21, 2019
1 parent 2ca9d97 commit 1b858a0
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ The latest draft is at <https://tc39.es/ecma262/>.

To read about bleeding-edge features, that are not yet widely supported, see proposals at <https://github.com/tc39/proposals>.


Also, if you're in developing for the browser, then there are other specs covered in the [second part](info:browser-environment) of the tutorial.

## Manuals
Expand Down
24 changes: 18 additions & 6 deletions 1-js/06-advanced-functions/04-var/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,19 @@ alert(test); // true, the variable lives after if
*/!*
```

If we used `let test` on the 2nd line, then it wouldn't be visible to `alert`. But `var` ignores code blocks, so we've got a global `test`.
`var` ignores code blocks, so we've got a global variable `test`.

If we used `let test` instead of `var test`, then the variable would only be visible inside `if`:

```js run
if (true) {
let test = true; // use "let"
}

*!*
alert(test); // Error: test is not defined
*/!*
```

The same thing for loops: `var` cannot be block- or loop-local:

Expand Down Expand Up @@ -76,7 +88,7 @@ alert(phrase); // Error: phrase is not defined (Check the Developer Console)

As we can see, `var` pierces through `if`, `for` or other code blocks. That's because a long time ago in JavaScript blocks had no Lexical Environments. And `var` is a remnant of that.

## "var" are processed at the function start
## "var" declarations are processed at the function start

`var` declarations are processed when the function starts (or script starts for globals).

Expand Down Expand Up @@ -178,11 +190,11 @@ In both examples above `alert` runs without an error, because the variable `phra

## Summary

There are two main differences of `var`:
There are two main differences of `var` compared to `let/const`:

1. Variables have no block scope, they are visible minimum at the function level.
2. Variable declarations are processed at function start.
1. `var` variables have no block scope, they are visible minimum at the function level.
2. `var` declarations are processed at function start (script start for globals).

There's one more minor difference related to the global object, we'll cover that in the next chapter.

These differences are actually a bad thing most of the time. Block-level variables is such a great thing. That's why `let` was introduced in the standard long ago, and is now a major way (along with `const`) to declare a variable.
These differences make `var` worse than `let` most of the time. Block-level variables is such a great thing. That's why `let` was introduced in the standard long ago, and is now a major way (along with `const`) to declare a variable.
45 changes: 23 additions & 22 deletions 1-js/09-classes/07-mixins/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,23 +99,25 @@ Please note that the call to the parent method `super.say()` from `sayHiMixin` l

![](mixin-inheritance.png)

That's because methods from `sayHiMixin` have `[[HomeObject]]` set to it. So `super` actually means `sayHiMixin.__proto__`, not `User.__proto__`.
That's because methods `sayHi` and `sayBye` were initially created in `sayHiMixin`. So their `[[HomeObject]]` internal property references `sayHiMixin`, as shown on the picture above.

As `super` looks for parent methods in `[[HomeObject]].__proto__`, that means it searches `sayHiMixin.__proto__` for `super.say`, not `User.__proto__`.

## EventMixin

Now let's make a mixin for real life.

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 it, and other objects should be able to "listen" to such events.
The important feature of many browser objects (not only) is working with events. Events is a way to "broadcast information" to anyone who wants it. So let's make a mixin that allows to easily add event-related functions to any class/object.

An event must have a name and, optionally, bundle some additional data.
- The mixin will provide a method `.trigger(name, [data])` to "generate an event" when something important happens to it. The `name` argument is a name of the event, and the optional additional data may follow.
- Also the method `.on(name, handler)` that adds `handler` function as the listener to events with the given name. It will be called when the event triggers.
- ...And the method `.off(name, handler)` that removes `handler` listener.

For instance, an object `user` can generate an event `"login"` when the visitor logs in. And another object `calendar` may want to receive such events to load the calendar for the logged-in person.
After adding the mixin, an object `user` will become able to generate an event `"login"` when the visitor logs in. And another object `calendar` may want to receive such events to load the calendar for the logged-in person.

Or, a `menu` can generate the event `"select"` when a menu item is selected, and other objects may want to get that information and react on that event.
Or, a `menu` can generate the event `"select"` when a menu item is selected, and other objects may want to get that information and react on that event. And so on.

Events is a way to "share information" with anyone who wants it. They can be useful in any class, so let's make a mixin for them:
Here's the code:

```js run
let eventMixin = {
Expand Down Expand Up @@ -146,7 +148,7 @@ let eventMixin = {
},

/**
* Generate the event and attach the data to it
* Generate an event with the given name and data
* this.trigger('select', data1, data2);
*/
trigger(eventName, ...args) {
Expand All @@ -160,12 +162,10 @@ let eventMixin = {
};
```

There are 3 methods here:

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.
3. `.trigger(eventName, ...args)` -- generates the event: all assigned handlers are called and `args` are passed as arguments to them.

- `.on(eventName, handler)` -- assigns function `handler` to run when the event with that name happens. Technically, there's `_eventHandlers` property, that stores an array of handlers for each event name. So it just adds it to the list.
- `.off(eventName, handler)` -- removes the function from the handlers list.
- `.trigger(eventName, ...args)` -- generates the event: all handlers from `_eventHandlers[eventName]` are called, with a list of arguments `...args`.

Usage:

Expand All @@ -176,30 +176,31 @@ class Menu {
this.trigger("select", value);
}
}
// Add the mixin
// Add the mixin with event-related methods
Object.assign(Menu.prototype, eventMixin);

let menu = new Menu();

// call the handler on selection:
// add a handler, to be called on selection:
*!*
menu.on("select", value => alert(`Value selected: ${value}`));
*/!*

// triggers the event => shows Value selected: 123
menu.choose("123"); // value selected
// triggers the event => the handler above runs and shows:
// Value selected: 123
menu.choose("123");
```

Now if we have the code interested to react on user selection, we can bind it with `menu.on(...)`.
Now if we'd like any code to react on menu selection, we can listen to it with `menu.on(...)`.

And the `eventMixin` can add such behavior to as many classes as we'd like, without interfering with the inheritance chain.
And `eventMixin` mixin makes it easy to add such behavior to as many classes as we'd like, without interfering with the inheritance chain.

## Summary

*Mixin* -- is a generic object-oriented programming term: a class that contains methods for other classes.

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.
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 methods into prototype.

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 minimize 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 methods of a mixin, to minimize the probability of that.

0 comments on commit 1b858a0

Please sign in to comment.