This commit is contained in:
Ilya Kantor 2019-06-18 19:44:34 +03:00
parent 9b95b5ee0e
commit 061ff30189
4 changed files with 42 additions and 33 deletions

View file

@ -17,9 +17,9 @@ Write the destructuring assignment that reads:
- `name` property into the variable `name`. - `name` property into the variable `name`.
- `years` property into the variable `age`. - `years` property into the variable `age`.
- `isAdmin` property into the variable `isAdmin` (false if absent) - `isAdmin` property into the variable `isAdmin` (false, if no such property)
The values after the assignment should be: Here's an example of the values after your assignment:
```js ```js
let user = { name: "John", years: 30 }; let user = { name: "John", years: 30 };

View file

@ -2,9 +2,11 @@
The two most used data structures in JavaScript are `Object` and `Array`. The two most used data structures in JavaScript are `Object` and `Array`.
Objects allow us to pack many pieces of information into a single entity and arrays allow us to store ordered collections. So we can make an object or an array and handle it as a single entity, or maybe pass it to a function call. Objects allow us to create a single entity that stores data items by key, and arrays allow us to gather data items into an ordered collection.
*Destructuring assignment* is a special syntax that allows us to "unpack" arrays or objects into a bunch of variables, as sometimes they are more convenient. Destructuring also works great with complex functions that have a lot of parameters, default values, and soon we'll see how these are handled too. But when we pass those to a function, it may need not an object/array as a whole, but rather individual pieces.
*Destructuring assignment* is a special syntax that allows us to "unpack" arrays or objects into a bunch of variables, as sometimes that's more convenient. Destructuring also works great with complex functions that have a lot of parameters, default values, and so on.
## Array destructuring ## Array destructuring
@ -16,6 +18,8 @@ let arr = ["Ilya", "Kantor"]
*!* *!*
// destructuring assignment // destructuring assignment
// sets firstName = arr[0]
// and surname = arr[1]
let [firstName, surname] = arr; let [firstName, surname] = arr;
*/!* */!*
@ -54,7 +58,7 @@ let [firstName, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic
alert( title ); // Consul alert( title ); // Consul
``` ```
In the code above, the second element of the array is skipped, the third one is assigned to `title`, and the rest of the array is also skipped. In the code above, the second element of the array is skipped, the third one is assigned to `title`, and the rest of the array items is also skipped (as there are no variables for them).
```` ````
````smart header="Works with any iterable on the right-side" ````smart header="Works with any iterable on the right-side"
@ -111,7 +115,7 @@ user.set("name", "John");
user.set("age", "30"); user.set("age", "30");
*!* *!*
for (let [key, value] of user.entries()) { for (let [key, value] of user) {
*/!* */!*
alert(`${key}:${value}`); // name:John, then age:30 alert(`${key}:${value}`); // name:John, then age:30
} }
@ -209,7 +213,7 @@ alert(height); // 200
Properties `options.title`, `options.width` and `options.height` are assigned to the corresponding variables. The order does not matter. This works too: Properties `options.title`, `options.width` and `options.height` are assigned to the corresponding variables. The order does not matter. This works too:
```js ```js
// changed the order of properties in let {...} // changed the order in let {...}
let {height, width, title} = { title: "Menu", height: 200, width: 100 } let {height, width, title} = { title: "Menu", height: 200, width: 100 }
``` ```
@ -293,7 +297,7 @@ alert(h); // 200
What if the object has more properties than we have variables? Can we take some and then assign the "rest" somewhere? What if the object has more properties than we have variables? Can we take some and then assign the "rest" somewhere?
The specification for using the rest operator (three dots) here is almost in the standard, but most browsers do not support it yet. Using the rest operator with objects is not supported by some older browsers (use Babel to polyfill it), but works in modern ones.
It looks like this: It looks like this:
@ -305,6 +309,8 @@ let options = {
}; };
*!* *!*
// title = property named title
// rest = object with the rest of properties
let {title, ...rest} = options; let {title, ...rest} = options;
*/!* */!*
@ -315,8 +321,8 @@ alert(rest.width); // 100
````smart header="Gotcha without `let`" ````smart header="Gotcha if there's no `let`"
In the examples above variables were declared right before the assignment: `let {…} = {…}`. Of course, we could use existing variables too. But there's a catch. In the examples above variables were declared right in the assignment: `let {…} = {…}`. Of course, we could use existing variables too, without `let`. But there's a catch.
This won't work: This won't work:
```js run ```js run
@ -337,13 +343,13 @@ The problem is that JavaScript treats `{...}` in the main code flow (not inside
} }
``` ```
To show JavaScript that it's not a code block, we can wrap the whole assignment in parentheses `(...)`: To show JavaScript that it's not a code block, we can make it a part of an expression by wrapping in parentheses `(...)`:
```js run ```js run
let title, width, height; let title, width, height;
// okay now // okay now
*!*(*/!*{title, width, height} = {title: "Menu", width: 200, height: 100}*!*)*/!*; *!*(*/!*{title, width, height}*!*)*/!* = {title: "Menu", width: 200, height: 100};
alert( title ); // Menu alert( title ); // Menu
``` ```
@ -366,7 +372,7 @@ let options = {
extra: true // something extra that we will not destruct extra: true // something extra that we will not destruct
}; };
// destructuring assignment on multiple lines for clarity // destructuring assignment split in multiple lines for clarity
let { let {
size: { // put size here size: { // put size here
width, width,
@ -391,9 +397,8 @@ Note that `size` and `items` itself is not destructured.
Finally, we have `width`, `height`, `item1`, `item2` and `title` from the default value. Finally, we have `width`, `height`, `item1`, `item2` and `title` from the default value.
That often happens with destructuring assignments. We have a complex object with many properties and want to extract only what we need. If we have a complex object with many properties, we can extract only what we need:
Even here it happens:
```js ```js
// take size as a whole into a variable, ignore the rest // take size as a whole into a variable, ignore the rest
let { size } = options; let { size } = options;
@ -401,7 +406,7 @@ let { size } = options;
## Smart function parameters ## Smart function parameters
There are times when a function may have many parameters, most of which are optional. That's especially true for user interfaces. Imagine a function that creates a menu. It may have a width, a height, a title, items list and so on. There are times when a function has many parameters, most of which are optional. That's especially true for user interfaces. Imagine a function that creates a menu. It may have a width, a height, a title, items list and so on.
Here's a bad way to write such function: Here's a bad way to write such function:
@ -503,11 +508,13 @@ In the code above, the whole arguments object is `{}` by default, so there's alw
- Destructuring assignment allows for instantly mapping an object or array onto many variables. - Destructuring assignment allows for instantly mapping an object or array onto many variables.
- The object syntax: - The object syntax:
```js ```js
let {prop : varName = default, ...} = object let {prop : varName = default, ...rest} = object
``` ```
This means that property `prop` should go into the variable `varName` and, if no such property exists, then the `default` value should be used. This means that property `prop` should go into the variable `varName` and, if no such property exists, then the `default` value should be used.
Object properties that have no mapping are copied to the `rest` object.
- The array syntax: - The array syntax:
```js ```js

View file

@ -3,7 +3,7 @@
There are two kinds of properties. There are two kinds of properties.
The first kind is *data properties*. We already know how to work with them. Actually, all properties that we've been using till now were data properties. The first kind is *data properties*. We already know how to work with them. All properties that we've been using till now were data properties.
The second type of properties is something new. It's *accessor properties*. They are essentially functions that work on getting and setting a value, but look like regular properties to an external code. The second type of properties is something new. It's *accessor properties*. They are essentially functions that work on getting and setting a value, but look like regular properties to an external code.
@ -82,7 +82,7 @@ alert(user.name); // Alice
alert(user.surname); // Cooper alert(user.surname); // Cooper
``` ```
Now we have a "virtual" property. It is readable and writable, but in fact does not exist. As the result, we have a "virtual" property `fullName`. It is readable and writable, but in fact does not exist.
```smart header="Accessor properties are only accessible with get/set" ```smart header="Accessor properties are only accessible with get/set"
Once a property is defined with `get prop()` or `set prop()`, it's an accessor property, not a data property any more. Once a property is defined with `get prop()` or `set prop()`, it's an accessor property, not a data property any more.
@ -181,9 +181,9 @@ Technically, the external code may still access the name directly by using `user
## Using for compatibility ## Using for compatibility
One of the great ideas behind getters and setters -- they allow to take control over a "normal" data property and tweak it at any moment. One of the great ideas behind getters and setters -- they allow to take control over a "regular" data property at any moment by replacing it with getter and setter and tweak its behavior.
For instance, we started implementing user objects using data properties `name` and `age`: Let's say we started implementing user objects using data properties `name` and `age`:
```js ```js
function User(name, age) { function User(name, age) {
@ -209,9 +209,9 @@ let john = new User("John", new Date(1992, 6, 1));
Now what to do with the old code that still uses `age` property? Now what to do with the old code that still uses `age` property?
We can try to find all such places and fix them, but that takes time and can be hard to do if that code is written by other people. And besides, `age` is a nice thing to have in `user`, right? In some places it's just what we want. We can try to find all such places and fix them, but that takes time and can be hard to do if that code is written/used by many other people. And besides, `age` is a nice thing to have in `user`, right? In some places it's just what we want.
Adding a getter for `age` mitigates the problem: Adding a getter for `age` solves the problem:
```js run no-beautify ```js run no-beautify
function User(name, birthday) { function User(name, birthday) {

View file

@ -2,13 +2,13 @@
Forms and control elements, such as `<input>` have a lot of special properties and events. Forms and control elements, such as `<input>` have a lot of special properties and events.
Working with forms can be much more convenient if we know them. Working with forms will be much more convenient when we learn them.
## Navigation: form and elements ## Navigation: form and elements
Document forms are members of the special collection `document.forms`. Document forms are members of the special collection `document.forms`.
That's a *named* collection: we can use both the name and the number to get the form. That's a so-called "named collection": it's both named and ordered. We can use both the name or the number in the document to get the form.
```js no-beautify ```js no-beautify
document.forms.my - the form with name="my" document.forms.my - the form with name="my"
@ -154,7 +154,7 @@ Let's talk about form controls, pay attention to their specific features.
### input and textarea ### input and textarea
Normally, we can access the value as `input.value` or `input.checked` for checkboxes. We can access their value as `input.value` (string) or `input.checked` (boolean) for checkboxes.
Like this: Like this:
@ -166,7 +166,7 @@ input.checked = true; // for a checkbox or radio button
``` ```
```warn header="Use `textarea.value`, not `textarea.innerHTML`" ```warn header="Use `textarea.value`, not `textarea.innerHTML`"
Please note that we should never use `textarea.innerHTML`: it stores only the HTML that was initially on the page, not the current value. Please note that even though `<textarea>...</textarea>` holds its value as nested HTML, we should never use `textarea.innerHTML`. It stores only the HTML that was initially on the page, not the current value.
``` ```
### select and option ### select and option
@ -174,8 +174,8 @@ Please note that we should never use `textarea.innerHTML`: it stores only the HT
A `<select>` element has 3 important properties: A `<select>` element has 3 important properties:
1. `select.options` -- the collection of `<option>` elements, 1. `select.options` -- the collection of `<option>` elements,
2. `select.value` -- the value of the chosen option, 2. `select.value` -- the value of the currently selected option,
3. `select.selectedIndex` -- the number of the selected option. 3. `select.selectedIndex` -- the number of the currently selected option.
So we have three ways to set the value of a `<select>`: So we have three ways to set the value of a `<select>`:
@ -223,10 +223,12 @@ Like this:
</script> </script>
``` ```
The full specification of the `<select>` element is available at <https://html.spec.whatwg.org/multipage/forms.html#the-select-element>. The full specification of the `<select>` element is available in the specification <https://html.spec.whatwg.org/multipage/forms.html#the-select-element>.
### new Option ### new Option
This is rarely used on its own. But there's still an interesting thing.
In the specification of [the option element](https://html.spec.whatwg.org/multipage/forms.html#the-option-element) there's a nice short syntax to create `<option>` elements: In the specification of [the option element](https://html.spec.whatwg.org/multipage/forms.html#the-option-element) there's a nice short syntax to create `<option>` elements:
```js ```js
@ -237,7 +239,7 @@ Parameters:
- `text` -- the text inside the option, - `text` -- the text inside the option,
- `value` -- the option value, - `value` -- the option value,
- `defaultSelected` -- if `true`, then `selected` attribute is created, - `defaultSelected` -- if `true`, then `selected` HTML-attribute is created,
- `selected` -- if `true`, then the option is selected. - `selected` -- if `true`, then the option is selected.
For instance: For instance:
@ -281,6 +283,6 @@ Form navigation:
Value is available as `input.value`, `textarea.value`, `select.value` etc, or `input.checked` for checkboxes and radio buttons. Value is available as `input.value`, `textarea.value`, `select.value` etc, or `input.checked` for checkboxes and radio buttons.
For `<select>` we can also get the value by the index `select.selectedIndex` or through the options collection `select.options`. The full specification of this and other elements is at <https://html.spec.whatwg.org/multipage/forms.html>. For `<select>` we can also get the value by the index `select.selectedIndex` or through the options collection `select.options`. The full specification of this and other elements is in the specification <https://html.spec.whatwg.org/multipage/forms.html>.
These are the basics to start working with forms. In the next chapter we'll cover `focus` and `blur` events that may occur on any element, but are mostly handled on forms. These are the basics to start working with forms. We'll meet many examples further in the tutorial. In the next chapter we'll cover `focus` and `blur` events that may occur on any element, but are mostly handled on forms.