This commit is contained in:
Ilya Kantor 2019-06-12 15:18:51 +03:00
parent f6e2c899c2
commit 5498450646
4 changed files with 124 additions and 22 deletions

View file

@ -58,7 +58,24 @@ alert( visitsCountMap.get(john) ); // 123
Using objects as keys is one of most notable and important `Map` features. For string keys, `Object` can be fine, but it would be difficult to replace the `Map` with a regular `Object` in the example above.
In the old times, before `Map` existed, people added unique identifiers to objects for that:
Let's try:
```js run
let john = { name: "John" };
let visitsCountObj = {}; // try to use an object
visitsCountObj[john] = 123; // try to use john object as the key
*!*
// That's what got written!
alert( visitsCountObj["[object Object]"] ); // 123
*/!*
```
As `john` is an object, it got converted to the key string `"[object Object]"`. All objects without a special conversion handling are converted to such string, so they'll all mess up.
In the old times, before `Map` existed, people used to add unique identifiers to objects for that:
```js run
// we add the id field
@ -159,7 +176,7 @@ The iteration goes in the same order as the values were inserted. `Map` preserve
Besides that, `Map` has a built-in `forEach` method, similar to `Array`:
```js
// runs the function for each (key, value) pair
// runs the function for each (key, value) pair
recipeMap.forEach( (value, key, map) => {
alert(`${key}: ${value}`); // cucumber: 500 etc
});

View file

@ -1,11 +1,11 @@
# Object.keys, values, entries
Let's step away from the individual data structures and talk about the iterations over them.
Let's step away from the individual data structures and talk about the iterations over them.
In the previous chapter we saw methods `map.keys()`, `map.values()`, `map.entries()`.
These methods are generic, there is a common agreement to use them for data structures. If we ever create a data structure of our own, we should implement them too.
These methods are generic, there is a common agreement to use them for data structures. If we ever create a data structure of our own, we should implement them too.
They are supported for:
@ -63,8 +63,93 @@ for (let value of Object.values(user)) {
}
```
## Object.keys/values/entries ignore symbolic properties
```warn header="Object.keys/values/entries ignore symbolic properties"
Just like a `for..in` loop, these methods ignore properties that use `Symbol(...)` as keys.
Usually that's convenient. But if we want symbolic keys too, then there's a separate method [Object.getOwnPropertySymbols](mdn:js/Object/getOwnPropertySymbols) that returns an array of only symbolic keys. Also, the method [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) returns *all* keys.
Usually that's convenient. But if we want symbolic keys too, then there's a separate method [Object.getOwnPropertySymbols](mdn:js/Object/getOwnPropertySymbols) that returns an array of only symbolic keys. Also, there exist a method [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) that returns *all* keys.
```
## Object.fromEntries to transform objects
Sometimes we need to perform a transformation of an object to `Map` and back.
We already have `new Map(Object.entries(obj))` to make a `Map` from `obj`.
The syntax of `Object.fromEntries` does the reverse. Given an array of `[key, value]` pairs, it creates an object:
```js run
let prices = Object.fromEntries([
['banana', 1],
['orange', 2],
['meat', 4]
]);
// now prices = { banana: 1, orange: 2, meat: 4 }
alert(prices.orange); // 2
```
Let's see practical applications.
For example, we'd like to create a new object with double prices from the existing one.
For arrays, we have `.map` method that allows to transform an array, but nothing like that for objects.
So we can use a loop:
```js run
let prices = {
banana: 1,
orange: 2,
meat: 4,
};
let doublePrices = {};
for(let [product, price] of Object.entries(prices)) {
doublePrices[product] = price * 2;
}
alert(doublePrices.meat); // 8
```
...Or we can represent the object as an `Array` using `Object.entries`, then perform the operations with `map` (and potentially other array methods), and then go back using `Object.fromEntries`.
Let's do it for our object:
```js run
let prices = {
banana: 1,
orange: 2,
meat: 4,
};
*!*
let doublePrices = Object.fromEntries(
// convert to array, map, and then fromEntries gives back the object
Object.entries(prices).map(([key, value]) => [key, value * 2])
);
*/!*
alert(doublePrices.meat); // 8
```
It may look difficult from the first sight, but becomes easy to understand after you use it once or twice.
We also can use `fromEntries` to get an object from `Map`.
E.g. we have a `Map` of prices, but we need to pass it to a 3rd-party code that expects an object.
Here we go:
```js run
let map = new Map();
map.set('banana', 1);
map.set('orange', 2);
map.set('meat', 4);
let obj = Object.fromEntries(map);
// now obj = { banana: 1, orange: 2, meat: 4 }
alert(obj.orange); // 2
```