Object.keys, values, entries
Давайте отойдём от отдельных структур данных и поговорим об их переборе вообще.
В предыдущей главе мы видели методы map.keys() , map.values() , map.entries() .
Это универсальные методы, и существует общее соглашение использовать их для структур данных. Если бы мы делали собственную структуру данных, нам также следовало бы их реализовать.
Методы поддерживаются для структур:
Простые объекты также можно перебирать похожими методами, но синтаксис немного отличается.
Object.keys, values, entries
Для простых объектов доступны следующие методы:
- Object.keys(obj) – возвращает массив ключей.
- Object.values(obj) – возвращает массив значений.
- Object.entries(obj) – возвращает массив пар [ключ, значение] .
Обратите внимание на различия (по сравнению с map , например):
| Map | Object | |
|---|---|---|
| Синтаксис вызова | map.keys() | Object.keys(obj) , не obj.keys() |
| Возвращает | перебираемый объект | «реальный» массив |
Первое отличие в том, что мы должны вызвать Object.keys(obj) , а не obj.keys() .
Почему так? Основная причина – гибкость. Помните, что объекты являются основой всех сложных структур в JavaScript. У нас может быть объект data , который реализует свой собственный метод data.values() . И мы всё ещё можем применять к нему стандартный метод Object.values(data) .
Второе отличие в том, что методы вида Object.* возвращают «реальные» массивы, а не просто итерируемые объекты. Это в основном по историческим причинам.
let user = < name: "John", age: 30 >;
- Object.keys(user) = [«name», «age»]
- Object.values(user) = [«John», 30]
- Object.entries(user) = [ [«name»,»John»], [«age»,30] ]
Вот пример использования Object.values для перебора значений свойств в цикле:
let user = < name: "John", age: 30 >; // перебор значений for (let value of Object.values(user)) < alert(value); // John, затем 30 >
Object.keys/values/entries игнорируют символьные свойства
Так же, как и цикл for..in , эти методы игнорируют свойства, использующие Symbol(. ) в качестве ключей.
Обычно это удобно. Но если требуется учитывать и символьные ключи, то для этого существует отдельный метод Object.getOwnPropertySymbols, возвращающий массив только символьных ключей. Также, существует метод Reflect.ownKeys(obj), который возвращает все ключи.
Трансформации объекта
У объектов нет множества методов, которые есть в массивах, например map , filter и других.
Если мы хотели бы их применить, то можно использовать Object.entries с последующим вызовом Object.fromEntries :
- Вызов Object.entries(obj) возвращает массив пар ключ/значение для obj .
- На нём вызываем методы массива, например, map .
- Используем Object.fromEntries(array) на результате, чтобы преобразовать его обратно в объект.
Например, у нас есть объект с ценами, и мы хотели бы их удвоить:
let prices = < banana: 1, orange: 2, meat: 4, >; let doublePrices = Object.fromEntries( // преобразовать в массив, затем map, затем fromEntries обратно объект Object.entries(prices).map(([key, value]) => [key, value * 2]) ); alert(doublePrices.meat); // 8
Это может выглядеть сложным на первый взгляд, но становится лёгким для понимания после нескольких раз использования.
Можно делать и более сложные «однострочные» преобразования таким путём. Важно только сохранять баланс, чтобы код при этом был достаточно простым для понимания.
Задачи
Сумма свойств объекта
важность: 5
Есть объект salaries с произвольным количеством свойств, содержащих заработные платы.
Напишите функцию sumSalaries(salaries) , которая возвращает сумму всех зарплат с помощью метода Object.values и цикла for..of .
Если объект salaries пуст, то результат должен быть 0 .
let salaries = < "John": 100, "Pete": 300, "Mary": 250 >; alert( sumSalaries(salaries) ); // 650
function sumSalaries(salaries) < let sum = 0; for (let salary of Object.values(salaries)) < sum += salary; >return sum; // 650 > let salaries = < "John": 100, "Pete": 300, "Mary": 250 >; alert( sumSalaries(salaries) ); // 650
Или, как вариант, мы можем получить сумму, используя методы Object.values и reduce :
// reduce перебирает массив значений salaries, // складывает их // и возвращает результат function sumSalaries(salaries) < return Object.values(salaries).reduce((a, b) =>a + b, 0) // 650 >
Object.keys()
Метод Object.keys() возвращает массив из собственных перечисляемых свойств переданного объекта, в том же порядке, в котором они бы обходились циклом for. in (разница между циклом и методом в том, что цикл перечисляет свойства и из цепочки прототипов).
Синтаксис
Object.keys(obj)
Параметры
Объект, чьи собственные перечисляемые свойства будут возвращены.
Описание
Метод Object.keys возвращает массив строковых элементов, соответствующих именам перечисляемых свойств, найденных непосредственно в самом объекте. Порядок свойств такой же, как и при ручном перечислении свойств в объекте через цикл.
Примеры
var arr = ["a", "b", "c"]; console.log(Object.keys(arr)); // консоль: ['0', '1', '2'] // Массивоподобный объект var obj = 0: "a", 1: "b", 2: "c" >; console.log(Object.keys(obj)); // консоль: ['0', '1', '2'] // Массивоподобный объект со случайным порядком ключей var an_obj = 100: "a", 2: "b", 7: "c" >; console.log(Object.keys(an_obj)); // консоль: ['2', '7', '100'] // Свойство getFoo является не перечисляемым свойством var my_obj = Object.create( >, getFoo: value: function () return this.foo; >, >, >, ); my_obj.foo = 1; console.log(Object.keys(my_obj)); // консоль: ['foo']
Если вы хотите увидеть все свойства, а не только перечисляемые, смотрите метод Object.getOwnPropertyNames() .
Примечания
В ES5, если аргумент метода не является объектом (является примитивным значением), будет выброшено исключение TypeError . В ES2015 такой аргумент будет приведён к объекту.
> Object.keys('foo') TypeError: 'foo' is not an object // код ES5 > Object.keys('foo') ['0', '1', '2'] // код ES2015
Полифил
Для добавления поддержки совместимого метода Object.keys в старых окружениях, которые его ещё не реализуют, скопируйте следующий кусок кода:
// From https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/keys if (!Object.keys) Object.keys = (function () "use strict"; var hasOwnProperty = Object.prototype.hasOwnProperty, hasDontEnumBug = ! toString: null >.propertyIsEnumerable("toString"), dontEnums = [ "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "constructor", ], dontEnumsLength = dontEnums.length; return function (obj) if ( typeof obj !== "object" && (typeof obj !== "function" || obj === null) ) throw new TypeError("Object.keys called on non-object"); > var result = [], prop, i; for (prop in obj) if (hasOwnProperty.call(obj, prop)) result.push(prop); > > if (hasDontEnumBug) for (i = 0; i dontEnumsLength; i++) if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]); > > > return result; >; >)(); >
Пожалуйста, обратите внимание, что вышеприведённый код в IE7 (и, может быть, в IE8) включает и не перечисляемые ключи, если объект передаётся из другого окна.
Более простой полифил может быть найден в статье Javascript — Object.keys Browser Compatibility (англ.).
Спецификации
| Specification |
|---|
| ECMAScript Language Specification # sec-object.keys |
Совместимость с браузерами
BCD tables only load in the browser
Смотрите также
- Перечисляемость и собственность свойств (en-US)
- Object.prototype.propertyIsEnumerable()
- Object.create()
- Object.getOwnPropertyNames()
Как получить значение из объекта js
Для получения значения из объекта нужно обратиться к ключу, под которым находится значение. Существует несколько способов обращения к ключу объекта:
Через точку. В этом варианте нужно указать имя ключа после точки:
const user = name: 'Ivan Ivanov', age: 34, >; console.log(user.name); // => 'Ivan Ivanov'
С помощью квадратных скобок. Такой способ подходит для указания динамического ключа(ключ содержится в переменной):
const user = name: 'Ivan Ivanov', age: 34, >; const property = 'name'; console.log(user[property]); // => 'Ivan Ivanov'
Обращение по ключу к свойству объекта (JS)
Функция getPrice, должна возвращать стоимость в выбранной валюте. Необходимо применить динамические свойства объекта, конкретно метод Object.keys().
import prices from "./prices.js" export const getPrice = (currency) =>
Вопрос: как обратиться по ключу к свойству объекта, чтобы для выбранной валюты он выводил конкретную стоимость. prices импортируются из данного скрипта:
const prices = < ethereum: < usd: 3382, eur: 2916, rub: 246392 >>
export default prices Попробовал вариант с:
export const getPrice = (currency) => < console.log(prices) console.log(currency) const key = Object.keys(prices) return `$` >
Однако в консоль выводит значение только «ethereum»