Объекты
Если в нашей программе нам надо описать сущность человека, у которого есть имя, возраст, пол и так далее, то естественно мы не сможем представить сущность человека в виде числа или строки. Нам потребуется несколько строк или чисел, чтобы должным образом описать человека. В этом плане человек будет выступать как сложная комплексная структура, у которого будут отдельные свойства - возраст, рост, имя, фамилия и т.д. Для работы с подобными структурами в JavaScript используются объекты. Каждый объект может хранить свойства, которые описывают его состояние, и методы, которые описывают его поведение.
Что такое объекты
В качестве примера рассмотрим объект реальной жизни «Фонарик». Фонарик, как и любой другой объект, имеет свойства. Свойства объекта – это его характеристики, например, материал корпуса, источник питания, длина и др. Т.е. это всё что можно описать с помощью существительных и прилагательных. Кроме свойств у объектов есть ещё действия (методы). Например, его можно включить и выключить. Некоторые методы, как например эти, предназначены для изменения состояния объекта. В общем, к действиям (методам) объекта относят обычно всё, что можно обозначить посредством глаголов.
Методы JavaScript
это действия, которые можно выполнить с объектамиимяОбъекта.имяМетода()
Свойства JavaScript
это значения, ассоциированные с объектомимяОбъекта.свойство
Фонарик представляет собой объект который содержит свойства и методы.
Свойства объекта фонарик:
- Материал корпуса - алюминий
- Источник питания - батарейки
Методы объекта фонарик:
- Включение фонарика
- Выключение фонарика
Создание объекта
Первый способ заключается в использовании конструктора Object
:
let user = new Object();
В данном случае объект называется user
. Выражение new Object()
представляет вызов конструктора - функции, создающей новый объект. Для вызова конструктора применяется оператор new
. Вызов конструктора фактически напоминает вызов обычной функции.
Второй способ создания объекта, который на сегодняшний день более распространен, представляет использование фигурных скобок:
let user = {};
Свойства объекта
После создания объекта мы можем определить в нем свойства. Чтобы определить свойство, надо после названия объекта через точку указать имя свойства и присвоить ему значение:
let user = {};
user.name = "Tom";
user.age = 26;
В данном случае объявляются два свойства name
и age
, которым присваиваются соответствующие значения. После этого мы можем использовать эти свойства, например, вывести их значения в консоли:
console.log(user.name);
console.log(user.age);
Также можно определить свойства при определении объекта:
let user = {
name: "Tom",
age: 26
};
В этом случае для присвоения значения свойству используется символ двоеточия, а после определения свойства ставится запятая (а не точка с запятой).
Кроме того, доступен сокращенный способ определения свойств:
let name = "Tom";
let age = 34;
let user = {name, age};
// Tom
console.log(user.name);
// 34
console.log(user.age);
В данном случае названия переменных также являются и названиями свойств объекта. И таким образом можно создавать более сложные конструкции:
let name = "Tom";
let age = 34;
let user = {name, age};
let teacher = {user, course: "JavaScript"};
// {name: "Tom", age: 34}
console.log(teacher.user);
// JavaScript
console.log(teacher.course);
Методы объекта
Методы объекта определяют его поведение или действия, которые он производит. Методы представляют собой функции. Например, определим метод, который бы выводил имя и возраст человека:
let user = {};
user.name = "Tom";
user.age = 26;
user.display = function(){
console.log(user.name);
console.log(user.age);
};
// вызов метода
user.display();
Как и в случае с функциями методы сначала определяются, а потом уже вызываются. Также методы могут определяться непосредственно при определении объекта:
let user = {
name: "Tom",
age: 26,
display: function(){
console.log(this.name);
console.log(this.age);
}
};
Как и в случае со свойствами, методу присваивается ссылка на функцию с помощью знака двоеточия
. Чтобы обратиться к свойствам или методам объекта внутри этого объекта, используется ключевое слово this
. Оно означает ссылку на текущий объект.
Также можно использовать сокращенный способ определения методов, когда двоеточие
и слово function
опускаются:
let user = {
name: "Tom",
age: 26,
display(){
console.log(this.name, this.age);
},
move(place){
console.log(this.name, "goes to", place);
}
};
// Tom 26
user.display();
// Tom goes to the shop
user.move("the shop");
Синтаксис массивов
Существует также альтернативный способ определения свойств и методов с помощью синтаксиса массивов:
let user = {};
user["name"] = "Tom";
user["age"] = 26;
user["display"] = function(){
console.log(user.name);
console.log(user.age);
};
// вызов метода
user["display"]();
Название каждого свойства или метода заключается в кавычки и в квадратные скобки, затем им также присваивается значение, например: user["age"] = 26
.
При обращении к этим свойствам и методам можно использовать либо нотацию точки user.name
, либо обращаться так: user["name"]
.
Также можно определить свойства и методы через синтаксис массивов напрямую при создании объекта:
let user = {
["name"]: "Tom",
["age"]: 26,
["display"]: function(){
console.log(user.name);
console.log(user.age);
}
};
user["display"]();
Строки в качестве свойств и методов
Также следует отметить, что названия свойств и методов объекта всегда представляют строки. То есть мы могли предыдущее определение объекта переписать так:
let user = {
"name": "Tom",
"age": 26,
"display": function(){
console.log(user.name);
console.log(user.age);
}
};
// вызов метода
user.display();
С одной стороны, разницы никакой нет между двумя определениями. С другой стороны, бывают случаи, где заключение названия в строку могут помочь. Например, если название свойства состоит из двух слов, разделенных пробелом:
let user = {
name: "Tom",
age: 26,
"full name": "Tom Johns",
"display info": function(){
console.log(user.name);
console.log(user.age);
}
};
console.log(user["full name"]);
user["display info"]();
Только в этом случае для обращении к подобным свойствам и методам мы должны использовать синтаксис массивов.
Динамическое определение имен свойств и методов
Синтаксис массивов открывает нам другую возможность - определение имени свойства вне объекта:
const prop1 = "name";
const prop2 = "age";
let tom = {
[prop1]: "Tom",
[prop2]: 37
};
// {name: "Tom", age: 37}
console.log(tom);
// Tom
console.log(tom.name);
// 37
console.log(tom["age"]);
Благодая этому, например, можно динамически создавать объекты с произвольными названиями свойств:
function createObject(propName, propValue){
return {
[propName]: propValue,
print(){
console.log(`${propName}: ${propValue}`);
}
};
}
let person = createObject("name", "Tom");
// name: Tom
person.print();
let book = createObject("title", "JavaScript Reference");
// title: JavaScript Reference
book.print();
Удаление свойств
Выше мы посмотрели, как можно динамически добавлять новые свойства к объекту. Однако также мы можем удалять свойства и методы с помощью оператора delete
. И как и в случае с добавлением мы можем удалять свойства двумя способами. Первый способ - использование нотации точки:
delete объект.свойство
Либо использовать синтаксис массивов:
delete объект["свойство"]
Например, удалим свойство:
let user = {};
user.name = "Tom";
user.age = 26;
user.display = function(){
console.log(user.name);
console.log(user.age);
};
// Tom
console.log(user.name);
// удаляем свойство
delete user.name;
// альтернативный вариант delete user["name"];
// undefined
console.log(user.name);
После удаления свойство будет не определено, поэтому при попытке обращения к нему, программа вернет значение undefined
.
Константные объекты
Возможно, нам поребуется, чтобы объект нельзя было изменить, то есть сделать константным. Однако просто определить его как обычную константу с помощью оператора const
недостаточно, например:
const person = {name: "Tom", age: 37};
person.name= "Bob";
// Bob
console.log(person.name);
Здесь мы видим, что свойство объекта изменило свое значение, хотя объект определен как константа. Оператор const
лишь влияет на то, что мы не можем присвоить константе новое значение, например как в следующем случае:
const person = {name: "Tom", age: 37};
// ошибка - нельзя константе присвоить значение второй раз
person = {name: "Sam", age: 56};
Тем не менее значения свойств объекта мы можем изменять. Чтобы сделать объект действительно константным, необходимо применить специальный метод Object.freeze()
. В этот метод в качестве параметра передается объект, который надо сделать константным:
const person = {name: "Tom", age: 37};
Object.freeze(person);
person.name= "Bob";
// Tom - значение свойства не изменилось
console.log(person.name);
Создание объекта из переменных и констант
При создании объекта его свойствам могут передаваться значения переменных, констант или динамически вычисляемые результаты функций:
function getSalary(status){
if(status==="senior") return 1500;
else return 500;
}
const name = "Tom";
const age = 37;
const person = { name: name, age: age, salary: getSalary()};
// {name: "Tom", age: 37, salary: 500}
console.log(person);
Но если названия констант/переменных совпадает с названиями свойств, то можно сократить передачу значений:
const name = "Tom";
const age = 37;
const salary = 500;
const person = { name, age, salary};
// {name: "Tom", age: 37, salary: 500}
console.log(person);
В данном случае объект person автомтически получит свойства, названия которых будут соответствовать названиям констант, а в качестве значений иметь значения этих констант. То же самое относится к передаче функций методам объекта:
function display(){
console.log(this.name, this.age);
}
const move = function(place){ console.log(this.name, "goes to", place)};
const name = "Tom";
const age = 37;
const salary = 500;
const person = { name, age, salary, display, move};
// Tom 37
person.display();
// Tom goes to cinema
person.move("cinema");
В данном случае объект person имеет два метода, которые соответствуют переданным в объект функциям - display()
и move()
. Стоит отметить, что при такой передаче функций методам объекта, мы по прежнему можем использовать в этих функциях ключевое слово this
для обращения к функциональности объекта. Однако стоит быть осторожным при передаче лямбд-выражений, поскольку для глобальных лямбд-выражений this
будет представлять объект окна браузера:
const move = (place)=>{ console.log(this.name, "goes to", place); console.log(this);};
const name = "Tom";
const person = { name, move};
// goes to cinema
person.move("cinema");
Фукция Object.fromEntries()
С помощью функции Object.fromEntries()
можно создать объект из набора пар ключ-значение, где ключ потом будет представляет название свойства. Например, создадим объект из массивов:
const personData = [ ["name", "Tom"], ["age", 37]];
const person = Object.fromEntries(personData);
// {name: "Tom", age: 37}
console.log(person);
// Tom
console.log(person.name);
Здесь объект создается из массива personData
, который содержит два подмассива. Каждый подмассив содержит два элемента и фактически представляет пару ключ-значение. Первый элемент представляет ключ, а второй - значение.