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`.
- `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
let user = { name: "John", years: 30 };

View file

@ -2,9 +2,11 @@
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
@ -16,6 +18,8 @@ let arr = ["Ilya", "Kantor"]
*!*
// destructuring assignment
// sets firstName = arr[0]
// and surname = arr[1]
let [firstName, surname] = arr;
*/!*
@ -54,7 +58,7 @@ let [firstName, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic
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"
@ -111,7 +115,7 @@ user.set("name", "John");
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
}
@ -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:
```js
// changed the order of properties in let {...}
// changed the order in let {...}
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?
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:
@ -305,6 +309,8 @@ let options = {
};
*!*
// title = property named title
// rest = object with the rest of properties
let {title, ...rest} = options;
*/!*
@ -315,8 +321,8 @@ alert(rest.width); // 100
````smart header="Gotcha without `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.
````smart header="Gotcha if there's no `let`"
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:
```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
let title, width, height;
// okay now
*!*(*/!*{title, width, height} = {title: "Menu", width: 200, height: 100}*!*)*/!*;
*!*(*/!*{title, width, height}*!*)*/!* = {title: "Menu", width: 200, height: 100};
alert( title ); // Menu
```
@ -366,7 +372,7 @@ let options = {
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 {
size: { // put size here
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.
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
// take size as a whole into a variable, ignore the rest
let { size } = options;
@ -401,7 +406,7 @@ let { size } = options;
## 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:
@ -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.
- The object syntax:
```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.
Object properties that have no mapping are copied to the `rest` object.
- The array syntax:
```js

View file

@ -3,7 +3,7 @@
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.
@ -82,7 +82,7 @@ alert(user.name); // Alice
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"
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
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
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?
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
function User(name, birthday) {