Для свойств, имена которых состоят из нескольких слов, доступ к значению «через точку» не работает:
// это вызовет синтаксическую ошибку
user.likes birds = true
JavaScript видит, что мы обращаемся к свойству user.likes
, а затем идёт непонятное слово birds
. В итоге синтаксическая ошибка.
Точка требует, чтобы ключ был именован по правилам именования переменных. То есть не имел пробелов, не начинался с цифры и не содержал специальные символы, кроме $
и _
.
Квадратные скобки
Для таких случаев существует альтернативный способ доступа к свойствам через квадратные скобки. Такой способ сработает с любым именем свойства:
let user = {};
// присваивание значения свойству
user["likes birds"] = true;
// получение значения свойства
alert(user["likes birds"]); // true
// удаление свойства
delete user["likes birds"];
Сейчас всё в порядке. Обратите внимание, что строка в квадратных скобках заключена в кавычки (подойдёт любой тип кавычек).
Квадратные скобки также позволяют обратиться к свойству, имя которого может быть результатом выражения. Например, имя свойства может храниться в переменной:
let key = "likes birds";
// то же самое, что и user["likes birds"] = true;
user[key] = true;
Здесь переменная key
может быть вычислена во время выполнения кода или зависеть от пользовательского ввода. После этого мы используем её для доступа к свойству. Это даёт нам большую гибкость.
Пример:
let user = {
name: "John",
age: 30
};
let key = prompt("Что вы хотите узнать о пользователе?", "name");
// доступ к свойству через переменную
alert( user[key] ); // John (если ввели "name")
Запись «через точку» такого не позволяет:
let user = {
name: "John",
age: 30
};
let key = "name";
alert( user.key ); // undefined
Вычисляемые свойства
Мы можем использовать квадратные скобки в литеральной нотации для создания вычисляемого свойства.
Пример:
let fruit = prompt("Какой фрукт купить?", "apple");
let bag = {
[fruit]: 5, // имя свойства будет взято из переменной fruit
};
alert( bag.apple ); // 5, если fruit="apple"
Смысл вычисляемого свойства прост: запись [fruit]
означает, что имя свойства необходимо взять из переменной fruit
.
И если посетитель введёт слово "apple"
, то в объекте bag
теперь будет лежать свойство {apple: 5}
.
По сути, пример выше работает так же, как и следующий пример:
let fruit = prompt("Какой фрукт купить?", "apple");
let bag = {};
// имя свойства будет взято из переменной fruit
bag[fruit] = 5;
…Но первый пример выглядит лаконичнее.
Мы можем использовать и более сложные выражения в квадратных скобках:
let fruit = 'apple';
let bag = {
[fruit + 'Computers']: 5 // bag.appleComputers = 5
};
Квадратные скобки дают намного больше возможностей, чем запись через точку. Они позволяют использовать любые имена свойств и переменные, хотя и требуют более громоздких конструкций кода.
Подведём итог: в большинстве случаев, когда имена свойств известны и просты, используется запись через точку. Если же нам нужно что-то более сложное, то мы используем квадратные скобки.
Свойство из переменной
В реальном коде часто нам необходимо использовать существующие переменные как значения для свойств с тем же именем.
Например:
function makeUser(name, age) {
return {
name: name,
age: age
// ...другие свойства
};
}
let user = makeUser("John", 30);
alert(user.name); // John
В примере выше название свойств name
и age
совпадают с названиями переменных, которые мы подставляем в качестве значений этих свойств. Такой подход настолько распространён, что существуют специальные короткие свойства для упрощения этой записи.
Вместо name:name
мы можем написать просто name
:
function makeUser(name, age) {
return {
name, // то же самое, что и name: name
age // то же самое, что и age: age
// ...
};
}
Мы можем использовать как обычные свойства, так и короткие в одном и том же объекте:
let user = {
name, // тоже самое, что и name:name
age: 30
};
Ограничения на имена свойств
Как мы уже знаем, имя переменной не может совпадать с зарезервированными словами, такими как «for», «let», «return» и т.д.
Но для свойств объекта такого ограничения нет:
// эти имена свойств допустимы
let obj = {
for: 1,
let: 2,
return: 3
};
alert( obj.for + obj.let + obj.return ); // 6
Иными словами, нет никаких ограничений к именам свойств. Они могут быть в виде строк или символов (специальный тип для идентификаторов, который будет рассмотрен позже).
Все другие типы данных будут автоматически преобразованы к строке.
Например, если использовать число 0
в качестве ключа, то оно превратится в строку "0"
:
let obj = {
0: "Тест" // то же самое что и "0": "Тест"
};
// обе функции alert выведут одно и то же свойство (число 0 преобразуется в строку "0")
alert( obj["0"] ); // Тест
alert( obj[0] ); // Тест (то же свойство)
Есть небольшой подводный камень, связанный со специальным свойством __proto__
. Мы не можем установить его в необъектное значение:
let obj = {};
obj.__proto__ = 5; // присвоим число
alert(obj.__proto__); // [object Object], значение - это объект, т.е. не то, что мы ожидали
Как мы видим, присвоение примитивного значения 5
игнорируется.
Мы более подробно исследуем особенности свойства __proto__
в следующих главах Прототипное наследование, а также предложим способы исправления такого поведения.