Урок 04

Объекты: основы

Объект — коллекция пар «ключ-значение». Ключи — строки или символы.

Создание

const user = {
    name: 'Алиса',
    age: 25,
    email: 'alice@example.com',
};

Через конструктор:

const empty = new Object();
const fromNull = Object.create(null); // без прототипа

Доступ

user.name;        // 'Алиса'
user['name'];     // 'Алиса'

Через переменную:

const key = 'name';
user[key]; // 'Алиса'

Добавление и изменение

user.age = 26;
user['email'] = 'new@example.com';
user.city = 'Москва';

Удаление

const { email, ...rest } = user; // без email, user не меняется
delete user.email;               // мутирует

Современный подход — деструктуризация со rest.

Проверка свойства

'name' in user;               // true
Object.hasOwn(user, 'name');  // ES2022, только собственное
user.hasOwnProperty('name');  // старый способ

in проверяет и унаследованные, Object.hasOwn — только собственные.

Ключи, значения, записи

Object.keys(user);    // ['name', 'age', 'email']
Object.values(user);  // ['Алиса', 25, '...']
Object.entries(user); // [['name', 'Алиса'], ...]

Порядок:

  1. Числовые ключи по возрастанию
  2. Строковые в порядке добавления
  3. Символы в порядке добавления

Перебор

for (const [key, value] of Object.entries(user)) {
    console.log(key, value);
}

Методы объекта

const calculator = {
    value: 0,
    add(n) {
        this.value += n;
        return this;
    },
    sub(n) {
        this.value -= n;
        return this;
    },
};

calculator.add(5).sub(2);

Методы — функции как свойства.

Сокращённые свойства

const name = 'Алиса';
const age = 25;

const user = { name, age };
// { name: 'Алиса', age: 25 }

Вычисляемые ключи

const key = 'name';
const user = { [key]: 'Алиса' };
// { name: 'Алиса' }

const prefix = 'user_';
const data = {
    [`${prefix}name`]: 'Алиса',
};
// { user_name: 'Алиса' }

Вложенные

const data = {
    user: {
        profile: {
            name: 'Алиса',
        },
    },
};

data.user.profile.name;
data.user?.profile?.name; // безопасный доступ

Опциональная цепочка

user?.address?.city;      // undefined, если нет
user?.getName?.();        // вызов, если функция есть
user?.['dynamic-key'];    // доступ по ключу

Слияние

Object.assign({}, a, b);
{ ...a, ...b };

Конфликт ключей — последний выигрывает.

Глубокое слияние:

function deepMerge(target, source) {
    const result = { ...target };
    for (const [key, value] of Object.entries(source)) {
        if (value && typeof value === 'object' && !Array.isArray(value)) {
            result[key] = deepMerge(result[key] ?? {}, value);
        } else {
            result[key] = value;
        }
    }
    return result;
}

Заморозка

Object.freeze(user);
user.name = 'Боб'; // не сработает в strict

Только верхний уровень. Для глубокой:

function deepFreeze(obj) {
    Object.freeze(obj);
    Object.values(obj).forEach((v) => {
        if (v && typeof v === 'object') deepFreeze(v);
    });
    return obj;
}

Проверка на пустоту

Object.keys(user).length === 0;

Итоги

  • Ключи — строки или символы
  • Доступ через точку или скобки
  • in и Object.hasOwn для проверки
  • Object.keys, values, entries
  • Spread для слияния
  • Object.freeze для иммутабельности