Symbol и перечисление ключей #
Ключи объекта в JavaScript почти всегда строки; Symbol даёт гарантированно уникальный идентификатор. Методы Object.keys, values и entries перечисляют собственные перечисляемые свойства — это основа сериализации, валидации форм и обхода payload без захвата унаследованных полей из прототипа (подробнее — см. раздел ООП).
Object.keys, values, entries #
const cart = {
id: 'cart-7a2',
currency: 'RUB',
itemCount: 2,
}
Object.keys(cart)
// ['id', 'currency', 'itemCount']
Object.values(cart)
// ['cart-7a2', 'RUB', 2]
Object.entries(cart)
// [['id', 'cart-7a2'], ['currency', 'RUB'], ['itemCount', 2]]
entries удобен для преобразования объекта в Map или для итерации пар ключ–значение:
for (const [key, value] of Object.entries(cart)) {
console.log(`${key}: ${value}`)
}
const cartMap = new Map(Object.entries(cart))
Порядок ключей для строковых свойств, похожих на целые индексы, и остальных строк — по спецификации ES2015+ (сначала целочисленные ключи по возрастанию, затем остальные строки в порядке создания, затем Symbol).
Что не попадает в перечисление #
Object.keys не видит:
- свойства из прототипа (унаследованные);
- свойства с
enumerable: false; - ключи типа
Symbol(для них —Object.getOwnPropertySymbols).
const proto = { sharedMethod() {} }
const playlist = Object.create(proto)
playlist.title = 'Focus Tracks'
playlist.trackCount = 5
Object.keys(playlist) // ['title', 'trackCount'] — без sharedMethod
Проверка одного собственного ключа:
Object.hasOwn(playlist, 'title') // true
Object.hasOwn(playlist, 'sharedMethod') // false
Object.hasOwn предпочтительнее устаревшего obj.hasOwnProperty, если объект мог переопределить последний.
Symbol как ключ #
Symbol создаёт уникальное значение; два вызова Symbol('desc') не равны:
const internalId = Symbol('playlist.internalId')
const playlist = {
title: 'Evening Mix',
[internalId]: 'pl-9f2c',
}
playlist[internalId] // "pl-9f2c"
playlist.internalId // undefined — Symbol не строковый ключ с таким именем
Описание в Symbol('...') только для отладки; на уникальность не влияет.
Зачем Symbol в прикладном коде #
- Скрытые служебные поля — не конфликтуют со строковыми ключами пользователя и не попадают в
Object.keysбез явного обхода. - Well-known symbols —
Symbol.iterator,Symbol.toStringTagи др. настраивают поведение встроенных протоколов (итерация, строковое представление). - Глобальный реестр —
Symbol.for('app.cart')возвращает один и тот же символ в рамках программы:
const CART_TAG = Symbol.for('app.cart')
const payload = { [CART_TAG]: { version: 1 } }
Symbol.keyFor(CART_TAG) // "app.cart"
Для публичных JSON API Symbol обычно не сериализуется — JSON.stringify его пропускает.
Обход всех собственных ключей #
Полный список собственных свойств (включая неперечисляемые) — Object.getOwnPropertyNames; символы — Object.getOwnPropertySymbols:
const profile = {
userId: 'u-104',
[Symbol('session')]: 'sess-9f2',
}
Object.getOwnPropertyNames(profile) // ['userId']
Object.getOwnPropertySymbols(profile) // [Symbol(session)]
В типичном UI-коде достаточно Object.keys / entries.
Практика: валидация и patch #
Проверка обязательных полей в теле запроса:
const required = ['event', 'data', 'meta']
const apiPayload = {
event: 'cart.updated',
data: { cartId: 'cart-7a2' },
meta: { sentAt: '2026-07-14T12:00:00Z' },
}
const missing = required.filter((key) => !Object.hasOwn(apiPayload, key))
// []
Иммутабельное обновление по белому списку ключей:
const allowed = ['displayName', 'avatarUrl']
const patch = { displayName: 'Мария К.', role: 'admin', avatarUrl: null }
const safePatch = Object.fromEntries(
Object.entries(patch).filter(([key]) => allowed.includes(key))
)
// { displayName: 'Мария К.', avatarUrl: null }
Связь с копированием объектов: fromEntries(entries) — обратная операция к разбору объекта.
for…in #
Цикл for...in обходит перечисляемые ключи по цепочке прототипов, если не ограничить hasOwn:
for (const key in playlist) {
if (Object.hasOwn(playlist, key)) {
console.log(key, playlist[key])
}
}
Для собственных ключей данных предпочтительнее Object.keys или for...of по entries — меньше сюрпризов от унаследованных полей.
Итог #
Object.keys,values,entries— собственные перечисляемые строковые ключи.Symbol— уникальный ключ или метка; не виден вkeysбез отдельного API.Object.hasOwnпроверяет собственное свойство без обращения к прототипу.- Унаследованные и неперечисляемые поля требуют других методов или раздела ООП.
- Для API и форм комбинируйте перечисление с белыми списками и валидацией.