Объекты в JavaScript

В этой главе:

  • Что такое объект

  • Создание объектов

  • Литерал объекта

  • Проверка, перечисление и удаление свойств

  • Доступ к свойству через квадратные скобки []

  • Передача по ссылке

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

  • Функция конструктор и оператор new

Что такое объект

Объект - это составной тип данных, он объединяет множество значений в единый модуль и позволяет сохранять и извлекать значения по их именам. Говоря другими словами, объекты - это неупорядоченные коллекции свойств, каждое из которых имеет свое имя и значение. В качестве свойств могут быть обычные переменные, содержащие значения, или объекты.

Создание объектов

В JavaScript существует два способа создания объектов - с помощью оператора new за которым следует функция конструктор или с помощью литерала объекта:

1
2
var empty = new Object();  //пустой объект создается с помощью оператора new
var empty = {};            //пустой объект создается с помощью литерала объекта

Литерал объекта

Литерал объекта - это заключённый в фигурные скобки список из нуля или более свойств (пар имя: значение), разделённых запятыми. Именем свойства может быть идентификатор или строковой литерал. Значением свойства может любое значение примитивного или ссылочного типа, а также любое выражение, допустимое в JavaScript, полученное значение выражения станет значением свойства.

1
2
3
4
5
6
7
var empty = {};         // пустой объект (без свойств)
var point = {x:0, y:0}; // объект с двумя свойствами x и y со значениями 0
var homer = {           // объект с несколькими свойствами
  "name": "Гомер Симпсон",
  age: 34,
  married: true
};

Обратите внимание, что после фигурной скобки должна стоять точка с запятой.

Обычно для доступа к значениям свойств объекта используется оператор точка . (точка). Значение в левой части оператора должно быть ссылкой на объект, к свойствам которого требуется получить доступ. Значение в правой части оператора должно быть именем свойства. Свойства объекта работают как переменные: в них можно сохранять значения и считывать их:

1
2
3
4
5
6
7
8
9
10
11
var homer = {
  name: "Гомер Симпсон",
  age: 34,
  married: true
};
 
homer.age = 35;  //присваиваем свойству новое значение
document.write(homer.age + "<br>");  //вывод значения свойства age
 
homer.male = "мужчина"//добавляем в объект новое свойство со значением
document.write(homer.male); //вывод значения нового свойства объекта

В этом примере важно обратить внимание на два момента - новое свойство объекта, можно добавить в любом месте, просто присвоив этому свойству значение, так же и значения свойств уже созданных, можно изменять в любой момент, например простым присваиванием нового значения.

Как вы могли уже заметить - значения свойств указанных внутри литерала объекта указываются после двоеточия, если добавляется новое свойство или присваивается новое значение уже существующему за пределами литерала объекта, то вместо двоеточия используется операция присваивания.

Как упоминалось ранее, значением свойства может быть объект:

1
2
3
4
5
6
7
8
9
10
var obj = {
  name: "Гомер",
  colors: {
    first: "yellow",
    second: "blue"
  }
};
 
//для доступа к значениям свойств используется стандартный синтаксис
document.write(obj.colors.first);

Значением свойства colors является объект {first: "yellow", second: blue }. Здесь следует обратить внимание на то, что у объекта, который выступает в качестве значения, в конце отсутствует точка с запятой. Это объясняется тем что в литерале объекта все свойства указываются через запятую и никаких точек с запятой там не должно быть использовано.

Проверка, перечисление и удаление свойств

Для удаления свойств объекта используется оператор delete.

1
2
3
4
5
6
7
var homer = {
  name: "Гомер Симпсон",
  age: 34,
  married: true
};
 
delete homer.age;

Обратите внимание, что при удалении свойства его значение не просто устанавливается в значение undefined, оператор delete действительно удаляет свойство из объекта. Цикл for in демонстрирует это отличие: он перечисляет свойства, которым присвоено значение undefined, но не перечисляет удаленные свойства.

Цикл по свойствам for in, который упоминался в главе "циклы" позволяет осуществлять последовательный перебор всех свойств объекта. Его можно использовать например при отладке сценариев, при работе с объектами, которые могут иметь произвольные свойства с заранее неизвестными именами, для вывода имен свойств на экран или для работы с их значениями. Синтаксис данного цикла выглядит следующим образом:

1
2
3
for (var имя_переменной in объект) {
  ...   //операторы
}

Перед исполнением цикла имя одного из свойств присваивается переменной в виде строки. В теле цикла эту переменную можно использовать как для получения имени свойства так и для получения значения свойства с помощью оператора [].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var homer = {
  name: "Гомер Симпсон",
  age: 34,
  married: true
};
 
document.write("до удаления свойства: <br>")
for (var name in homer) {
  document.write(name + "<br>");  //выводит имена свойств
}
 
delete homer.age;
 
document.write("<br> после удаления свойства: <br>")
for (var name in homer) {
  document.write(name + " = " + homer[name] + "<br>");  //выводит имена и значения свойств
}

На заметку: цикл for in не перечисляет свойства в каком-либо заданном порядке, и хотя он перечисляет все свойства, определенные пользователем, некоторые предопределенные свойства и методы JavaScript он не перечисляет.

Для проверки факта существования того или иного свойства используется оператор in. С левой стороны от оператора помещается имя свойства в виде строки, с правой стороны - проверяемый объект на наличие указанного свойства.

1
2
3
4
5
6
7
var obj = {};
if ("a" in obj) {
  obj.a = 1;
}
else {
  document.write("Такого свойства не существует");
}

При обращении к несуществующему свойству возвращается значение undefined. Поэтому, для проверки так же достаточно часто используется другой способ - сравнение значения с undefined.

1
if (obj.x !== undefined) obj.x = 1;

Разница между этими двумя способами проверки следующая: проверка с помощью сравнения "=== undefined" не работает, если значение свойства равно undefined:

1
2
3
var obj = {};
boj.x = undefined;
if (obj.x !== undefined) //false, хотя такое свойство существует

Оператор in в этом случае гарантирует точный результат

1
2
3
var obj = {};
boj.x = undefined;
if ("x" in obj) //true, так как такое свойство существует

В реальных программах значение undefined не присваивают, этот пример был приведен, чтобы показать разницу при проверки на существования свойства, если значение свойство undefined.

Доступ к свойству через квадратные скобки []

Как мы знаем, доступ к свойствам объекта осуществляется посредством оператора "точка". Доступ к свойствам объекта возможен также при помощи оператора [], который обычно используется при работе с массивами. Таким образом, следующие два выражения имеют одинаковое значение и на первый взгляд ничем не отличаются:

1
2
obj.property = 10;
obj['property'] = 10;

Важное различие между этими двумя синтаксисами, на которое следует обратить внимание, состоит в том, что в первом варианте имя свойства представляет собой идентификатор, а во втором - строку.

Бывают случаи, когда имя свойства хранится в переменной, поэтому в квадратные скобки можно так же передать переменную, которой присвоено имя свойства в виде сроки:

1
2
3
4
5
6
var obj = { name: "Гомер" };
 
var str = "name"//присваиваем переменной в виде строки имя свойства
 
//запись obj[str] эквивалентна obj["name"]
document.write(str + ": " + obj[str]);

Если имя свойства хранится в качестве значения в переменной как в примере (var str = "name";), то единственным способом обратиться к нему - это через квадратные скобки (obj[str]), это будет тоже самое, что и (obj["name"]).

Примечание: еще одна разница между доступом к свойству объекта через точку и [] состоит в том, что на имя свойства при доступе через оператор "точка" наложены синтаксические ограничения - это те же правила именования, что и для обычной переменной, в то время как при обращении к свойству объекта с помощью оператора [], имя свойства задается в виде строки и может содержать любые символы.

1
obj["Мое имя"] = "Гомер";

Какой же способ лучше использовать при написании программы? Обычно обращение к свойству через точку используется, если вы на этапе написания программы уже знаете какие будут названия свойств. А если свойства будут определяться по ходу выполнения, например, будут вводиться посетителем и записываться в переменную, то единственный выбор — квадратные скобки.

Передача по ссылке

В JavaScript простые типы (например, числа, строки и тд.) передаются по значению, объекты наоборот, присваиваются и передаются по ссылке - это значит, что в переменной в качестве значения хранится не сам объект, а ссылка на место в памяти, где храниться сам объект.
Чтобы это лучше понять - сравним обычные переменные и объекты:

1
2
3
//обычные переменные имеющие простые типы значений
var msg = "hello world!"//значение хранится в переменной
var msg2 = msg;  //msg2 получает копию значения переменной msg

Рассмотрим этот пример подробнее - во второй строке переменная, находящаяся в левой части оператора присваивания, получает копию значения переменной, находящейся в правой части этого оператора, т.е. теперь две переменные имеют каждая свое значение и изменив значение например в первой переменной, значение второй переменной останется неизменным.
Теперь посмотрим на объекты:

1
2
var user1 = { name: "Вася"};  //переменная содержит ссылку на объект
var user2 = user1;  //скопировали ссылку на объект другой переменной

Здесь ситуация становится немного сложнее. При копировании переменной - копируется только ссылка, а объект по-прежнему остается в единственном экземпляре. Получается, что теперь две переменные ссылаются на один и тот же объект. Следовательно, этим объектом можно оперировать с помощью переменной user1 или user2. Так как объект всего один, то в какой бы переменной его не изменяли — это отразится сразу на двух переменных.

1
2
3
4
5
var user1 = { name: "Вася"}; 
var user2 = user1;
 
user2.name = "Иван"//изменили значение через user2
document.write(user1.name);  //изменения видны в первой переменной 

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

Метод - это функция, которая хранится в качестве значения в свойстве объекта и может вызываться посредством этого объекта.

1
2
3
4
5
6
7
8
9
var obj = {
  name: "Гомер",
   
  write_hello: function() {
    document.write("Привет");
  }
};
 
obj.write_hello();  //вызов метода

Метод должен иметь доступ к данным объекта для полноценной работы. Для доступа к объекту из метода используется ключевое слово this. Оно ссылается на объект, в контексте которого вызван метод и позволяет обращаться к другим его методам и свойствам:

1
2
3
4
5
6
7
8
9
10
var calc = {
  num1: 5,
  num2: 5,
  compute: function( ) {
    this.result = this.num1 * this.num2;
  }
};
 
calc.compute(); //Вычисляем сколько будет 5*5?
document.write(calc.result); // Выводим результат

Такую запись this.result = this.num1 * this.num2, в принципе можно читать как calc.result = calc.num1 * calc.num2, так как слово this в качестве значения содержит ссылку на объект.

Функция конструктор и оператор new

Помимо литерального синтаксиса создания объекта, объект можно создавать при помощи функции - конструктора и оператора new.

Конструктор - это функция, которая выполняет инициализацию свойств объекта и предназначена для использования совместно с оператором new:

1
2
3
4
5
6
7
//определяем конструктор
function Car(seats) {
  this.seats = seats;
  this.canDrive = true;
}
//вызываем конструктор для создания нового объекта
var myCar = new Car("leather");

Давайте разберем как это все работает. Оператор new создает новый пустой объект без каких-либо свойств, а затем вызывает функцию-конструктор (можно называть просто конструктор), передавая ей только что созданный объект. Главная задача конструктора заключается в инициализации вновь созданного объекта - установке всех его свойств, которые необходимо инициализировать до того, как объект сможет использоваться программой. После того как объект создан и инициализирован, переменной myCar присваивается ссылка на объект.
Результатом выполнения кода из примера выше является создание нового экземпляра объекта:

1
2
3
4
myCar = {
  seats: "leather",
  canDrive: true
};

Создаваемые объекты таким образом обычно называют экземпляром объекта (или класса), в нашем случае myCar является экземпляром объекта Car.

Примечание: при вызове конструктора без аргументов, скобки можно не ставить.

1

2

3

var myCar = new Car;
//тоже самое, что и
var myCar = new Car();