Объекты в JavaScript

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

Структура объектов и их объявление

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

  • var obj = {// свойства и методы} — объявление без конструктора, классом наследником выступает Object.prototype;
  • var obj = new Object({}) — то же, что и предыдущий способ, только через new;
  • var obj = new Func_constructor() — создание через функцию конструктор;
  • var obj = new Class_name() — создание через класс.

Рассмотрим эти объявления на примерах.

Пример создание объектов разными способами:

// Объявление объекта посредством квадратных скобок без объявления класса или функции-конструктора
var car = {
color: «red»,
start: function(){alert(«car is started»)}
};

//обратимся к свойству
alert(car.color); // red
car.start(); // car is started

//Объявление объекта через конструктор new
var car = new Object({calor: ‘red’, start:function(){alert(«car is started»)}});

// функция конструктор
function Car(color){
this.color = color;
this.start = function(){alert(‘car is started’);}
}
//создание объекта
var obj = new Car(«red»); // объект получил и свойство из параметра в конструкторе и метод — все объекты этого конструктора будут получать разные цвета но один и тот же метод

// Создание через конструктор класса
сlass Car{
// свойства и методы
}
var obj = new Car();

Свойства объектов

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

Пример:

var Volvo = {
model: «Volvo», // свойство, описывающее модель
type: «Sedan», // свойство, описывающее тип кузова
width: 5, // свойство, описывающее длину
height: 2 // свойство, описывающее высоту
};

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

<button id = «Volvo» value = «Volvo»> // RКнопка для события
<p id = «car_info»></p> // Место отображения информации

function gerCarParameters(e){ // функция вывода информации на экран
if(e.target.value == Volvo.model) //если модель объекта соответствует модели, указанной на кнопке, то выводится информация
document.getElementById(«car_info»).innerHTML = Volvo.model + «<br>» + Volvo.type + «<br>» + Volvo.width + «<br>» + Volvo.height;
else throw «Car of this model isn’t in database» // Если объекта нет то выводится сообщение
}

document.getElementById(«Volvo»).onclick = «getCarParameters(event)» // Присваиваем кнопке атрибут события и функцию-обработчик

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

Также доступ к свойствам может осуществляется по примеру ассоциативного массива.

Пример:

alert(Volvo[‘type’]); // Sedan
alert(Volvo[«width»]); // 5

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

Свойства могут быть объектами, массивами и всеми распространенными типами данных в JavaScript

Пример: Присвоим объекту разные типы данных

var car = {
model: «Volvo», // String
type: «Sedan», // String
width: 5, // Int
height: 2 //Int
onSale: true // Bool
popular_in_counries: [«England», «France», «USA»], // Array
engine: { // Object
type: «Caterpillar»,
power: 250,
celinder_number: 8
}
};

alert(car.engine.type); // Caterpillar
alert(car.popular_in_contries); // England, France, USA
car.popular_in_contries.push(«Russia»);
alert(car.popular_in_contries); // Russia, England, France, USA

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

Добавление свойств в объект, созданный конструктором

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

Пример:

function Car(){}
var obj = new Car(); // Создали пустой объект

obj.color = «red»; // добавили свойства текущему объекту
obj[«year»] = 1990; // как ассоциативный массив, то же, что и предыдущий пример
alert(obj.year); // 1990

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

Методы объектов представляют собой функцию, которая проводит некие манипуляции со свойствами объектов или некие действия, не касаясь свойств.

Пример:

var human = {
height: 180,
weight: 75,
go: function(){alert(«go»);}, // метод
get_parameters: function(){alert(this.height + » » + this.weight)}
}

human.go() // go
human.get_parameters(); // 180 75
// или так
human[«go»](); // go

Как и свойства, методы могут присваиваться и динамически после создания объекта. В коде видно конструкцию «this» — о ней поговорим позже. Аналогично методы объявляются в классах и конструкторах.

Что представляет собой объект в рамках JavaScript и ООП в целом?

Объекты в ООП — набор данных и функций, доступ к которым осуществляется по ссылке. Ссылкой является переменная, в которую сохраняется созданный объект. Объект представляет собой ссылочный тип данных, когда примитивы (Integer, String и т.п) хранятся в стеке. Примитивам нельзя присвоить свойства и методы, если они не объявлены через оператор new.

Пример:

var x = 5; // примитив, значение которого хранится в стеке
var y = new Number(5); // Объект, данные которого хранятся в куче
x.a = 5; // ошибка присвоения свойства примитиву
y.a = 6; // добавлено свойство
typeof x; // Number
typeof y; // Object

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

Пример:

new Car(); // Объект создается и тут же уничтожается интерпретатором
var x = new Car(); // сохраняем объект в переменную и теперь он нам доступен.

Переменная объекта это ссылка на блок свойств и методов в куче. В предыдущем примере такой ссылкой является переменная x. Рассмотрим простой пример.

Пример:

var x = {a: 5, b: 4}
var y = x // присвоили переменной объект x

alert(x.a); // 5
alert(y.a); // 5
y.a = 6; изменили свойство объекта y
alert(y.a); // 6
alert(x.a); // 6 — кажется тут что то не так

Почему изменив объект y, изменился и объект х? На самом деле В переменные x и y сохранен один и тот же объект. Просто теперь у него две ссылки x и y. То есть: x и y = {a: 5, b: 4}, присвоить переменной y новый объект, его нужно объявить заново. А такое присвоение «y=x» попросту копирует ссылку на один и тот-же объект. Чтобы ставить одну ссылку, допустим x, то ссылке y нужно присвоить null: y = null. Таким образом мы не уничтожаем объект, но ссылку на него.

Строковое представление объектов

Что будет, если вывести имя ссылки на экран?

Пример:

var obj = {a:»Hello», b:»World»};
alert(obj); // [object Object]

Что это значит? Почему выводится такое значение. Ведь когда мы выводим массив, то выводятся все его значения, а объект таким образом.

Все объекты наследуют специальные методы и свойства, хранящиеся в Object — класс, находящийся на вершине иерархии объектов JavaScript, от которого наследуют функционал объекты, массивы, строки и остальные объекты. Object.prototype хранит в себе методы toString() b valueOf(), которые и отвечают за отображение значения [object Object] на экране.

У Array.prototype, String.prototype и других есть свои такие методы. Однако пользовательские объекты, не важно созданы они конструктором или простым присваиванием берут эти методы у Object.prototype. На экран выводится тип ссылки, указывающей, что это object, который наследуется от Object.

Если таким же способом вывести массив, число и другой встроенный объект, то отобразится его значение, а не тип. Такое отображение действует только на пользовательские объекты и объекты DOM.

Сравнение примитивов и объектов

Ранее упоминалось, чт примитивы это не объекты. Однако при создании примитивов посредством new, мы получаем объект. Сравните следующие отличия с помощью оператора typeof:

typeof «John» // «string»
typeof 3.14 // «number»
typeof true // «boolean»
typeof false // «boolean»
typeof x // «undefined» (if x has no value)
typeof {name:’John’, age:34} // «object»
typeof [1,2,3,4] // «object» не «array»
typeof null // «object» (null — тип данных)
typeof function myFunc(){} // «function»

Отдельно стоит рассмотреть функцию. Почему-то оператор typeof выводит function. Хотя это объект и наследуется он от Function.prototype. Не стоит вдаваться в подробности так как это особенность оператора. Следует знать, что функции — это объекты!

Отображение свойств объекта через цикл for in

Цикл for in прекрасно подходит для перебора объекта как массива.

Пример:

var obj = {a:»Hello», b:»World»};

for (x in obj) {
alert(obj[x] + » «); // Hello World
};

Добавление свойств и методов объекту через специальную функцию Object.defineProperty()

Данная функция является статической и находится в хранилище класса Object.prototype. Функция позволяет добавить в объект свойство и настроить его. В опции настроек входит: имя, значение, разрешение на перебор циклом for in

Пример:

var obj = {};
Object.defineOwnProperty(obj, «name», «john», true);

Пояснение:

  1. Первый параметр функции указывает какому объекту присваивается свойство.
  2. Второй параметр определяет имя свойства.
  3. Третий параметр определяет значение свойства.
  4. Четвертый параметр разрешает итерацию в цикле, если false, то нет.

Операции с объектами

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

Пример: Объекты могут быть свойствами других объектов

var obj = {
n:9,
u: 10,
v: {a:5, b:7} // объект в объекте
};

Пример: Объект может быть параметром функции

function showObj(obj, x, y){
alert(obj.x + » «+ obj.y);
}

var human = {weight: 80, height: 180}

showObj(human, weight, height); // 80 180

Пример: Методы объектов можно использовать для других объектов

var obj_1 = {a: 8, show: function(){alert(this.a)}};
var obj_2 = {a: 3};

obj_1.show(); // 8
obj_2.show(); // ошибка — нет такой функции у данного объекта

obj_1.show.call(obj_2); // 3

Последний вызов метода вывел результат для второго объекта. Функция call позволяет применять метод к контексту других объектов.

Пример: Новые статичные методы в ES 2015 для Object

// Добавляет или изменяет свойство объекта
Object.defineProperty(object, property, descriptor)

// Добавляет или изменяет несколько свойств объекта
Object.defineProperties(object, descriptors)

// Доступ к значению свойства
Object.getOwnPropertyDescriptor(object, property)

// Возвращает все имена свойств массивом
Object.getOwnPropertyNames(object)

// Возвращает свойства, доступные для цикла
Object.keys(object)

// Показывает прототип объекта
Object.getPrototypeOf(object)

// Запрещает добавлять свойства объекту
Object.preventExtensions(object)

// Возвращает true, если разрешено добавление свойств в объект
Object.isExtensible(object)

// Запрещает изменять имена свойств
Object.seal(object)

// Возвращает true, если объект защищен от смены имен свойств
Object.isSealed(object)

// Запрещает какие либо изменения в объекте
Object.freeze(object)

// Возвращает true, если объект полностью защищен от изменений
Object.isFrozen(object)

Оператор this

Оператор this является ссылкой на текущий объект. Рассмотрим на примере конструктора:

function createObj(a, b){
this.width = a; // создает свойство именно для конкретного экземпляра
this.height = b;
}

var obj_1 = new CreateObj(12, 14);
var obj_2 = new CreateObj(56, 20);

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

Пример: Без конструктора

var human = {
name: «John»,
age: 18,
info: = function(){alert(this.name + » » + this.age)}
};

human.info(); // John 18
// Если убрать из метода this, то будет ошибка — в таком объявлении переменные не станут глобальными

Также this используется в атрибуте HTML

Пример:

<button onclick=»this.style.display=’none'»> // Здесь this означает текущий объект DOM button.

Объекты DOM

Любой HTML элемент рассматривается JavaScript как объект. Не важно — строчный или блочный элемент, форма или фрейм.

Пример:

alert(document.getElementById(«p»)); //[object HTMLPElement]
alert(document.getElementById(«h1»)); //[object HTMLH1Element]
alert(document.getElementById(«span»)); //[object HTMLSpanElement]
alert(document.getElementById(«li»)); //[object HTMLLiElement]
alert(document.getElementById(«div»)); //[object HTMLDivElement]
alert(document.getElementById(«header»)); //[object HTMLHeaderElement]
alert(document.getElementById(«button»)); //[object HTMLButtonElement]
alert(document.getElementById(«input»)); //[object HTMLInputElement]
alert(document.body); //[object HTMLBodyElement]
alert(document.images[0]); //[object HTMLImageElement]

var div = document.getElementById(«div»); // сохраняем объект div
div.innerHTML = «Hello»; // Теперь в div будет текст

Объекты BOM

JavaScript может манипулировать объектами браузера:

  1. Location — объект геолокации.
  2. Screen — объект, содержащий информацию об экране.
  3. History — объект, содержащий информации об истории просматривания страниц.
  4. Navigator — информация о браузере.
  5. Window — главный объект окна браузера, который является вершиной иерархии объектов DOM

Пример:

alert(Screen.height); // выведет ширину экрана
window.open(); // откроет новое окно браузера

JSON для объектов

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

Пример:

var myObj = {name: «John», age: 31, city: «New York»};
var myJSON = JSON.stringify(myObj); // Получили строку «John 31 New York»

// Чтобы конвертировать строку обратно в объект нужно сделать следующее
var myJSON = ‘{«name»:»John», «age»:31, «city»:»New York»}’;
var myObj = JSON.parse(myJSON); // Получили объект из строки

Наследование объектов

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

Пример:

//конструктор человека
function Human (surname, age) {
this.surname = surname;
this.age = age;
this.go = function(){document.write(this.name + » идет <br/>»);}
this.humanInfo = function(){
document.write(«Name: » + this.surname + «; age: » + this.age);
};
}
Human.prototype.maximumAge = 100; // добавляем в конструктор свойство, определяющее максимальный возраст человека

// конструктор сотрудника компании, который будет наследовать функционал человека
function Worker(surname, age, company_name){
Human.call(this, surname, age); // передаем все свойства от человека к работнику, вызовом конструктора, создающего человека
this.company_name = company_name;
this.workerInfo = function(){
document.write(«Name: » + this.surname + «; age: » + this.age + «; company: » + this.company_name);
};
}
Worker.prototype = Object.create(Human.prototype);

var John = new Human(«John», 23);
var Edward = new Worker(«Edward», 32, «Yandex»);
John.go();
Edward.go();
John.humanInfo();
Edward.workerInfo();
console.log(Edward.maximumAge);

// программа выведет:
Name: John; age: 23;
Name: Edward; age: 32; company: Yandex

Сначала был определен конструктор объектов Human. Затем, чтобы добавить конструктору новое свойство в ходе выполнения программы следует обратиться к его прототипу. В нашем случае это конструкция Human.prototype. Здесь мы добавили ему свойство maximumAge. Сам процесс наследования происходит при создании объекта.

В конструкторе Worker есть такая инструкция, как Human.call(this, surname, age). Она вызывает конструктор объекта Human прямо в конструкторе Worker. Это копирует имена свойств от объекта Human в объект Worker. При этом, метод call() вызывает конструктор в контексте Worker. Данная конструкция попросту сокращает код, не требуя записывать одни и те же свойства несколько раз. При этом, Worker получает и методы, хранящиеся в конструкторе Human.

Также достойна внимания конструкция Worker.prototype = Object.create(Human.prototype). Здесь создается прототип Human и присваивается прототипу Worker. Данная конструкция является гарантией того, что созданные объекты Worker всегда будут наследовать функционал от Human. При этом достаточно добавить свойство или метод через Worker.prototype и оно появится у тех и других создаваемых объектов. То есть, не нужно присваивать прототипам конструкторов свойства по отдельности.

Расширяем объекты посредством prototype

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

Пример:

function Proto_human(protoName, protoAge) {
this.name = protoName;
this.age = protoAge;
this.show_proto_info = function(){
document.write(«Имя: » + this.name + «; возраст: » + this.age + «<br/>»);
};
};

Proto_human.prototype.greetings = function(){ // добавляем в конструктор новый метод, который будет присвоен всем создаваемым объектам
document.write(this.name + » say: ‘Hello!'<br/>»);
};
Proto_human.prototype.someNumber = 250; // добавление в конструктор свойства

var human1 = new Proto_human(«Ben», 22);
human1.greetings(); // Ben say: Hello!
var human2 = new Proto_human(«Zak», 28);
human2.greetings(); // Zak say: Hello!
console.log(human1.someNumber); // 250
console.log(human2.someNumber); // 250

Стоит отметить, что объекты, которые были созданы до выполнения присвоения свойства или методы прототипу, останутся не изменены. То есть, они не получат нового метода и свойства. Их получат только те объекты, которые будут создаваться после конструкции «Proto_human.prototype.some = value».

Вообще prototype является резервным хранилищем свойств и методов. Когда объект обращается к методу или свойству, добавленного в прототип, то интерпретатор сначала ищет его в самом объекте. Если не находит, то уже обращается к prototype. Если уже и тут его нет, то генерируется ошибка.

Проверка наличия свойства в объекте через оператор in

Оператор in возвращает значение типа boolean, если в объекте есть запрашиваемый метод или свойство. Синтаксис оператора следующий: «имя свойства» in объект. Обратите внимание, что имя свойства заключается в кавычках, а имя объекта без них.

Пример:

var user = {name: «Max», display: function(){alert(this.name);}};

var user_has_name_prop = «name» in user; // проверяем наличие свойства с именем «name»
alert(user_has_name_prop); // true — свойство name есть в user
var user_has_surname_prop = «surname» in user; // проверяем наличие свойства с именем surname
alert(user_has_surname_prop); // false — в user нет свойства или метода под названием surname

Альтернативой данному оператору является метод Obj.hasOwnProperty().

Пример:

var user = {name: «Max», display: function(){alert(this.name);}};
alert(user.hasOwnProperty(name)); // true
alert(user.hasOwnProperty(display)); // true
alert(user.hasOwnProperty(width)); // false

Итог

  1. Объекты в JavaScript являются структурным типом данных, хранящим свойства и методы.
  2. Доступ к свойствам осуществляется через имя объекта, оператор «.» имя свойства или метода.
  3. Свойства и методы не индексируются, как в массиве.
  4. Объекты можно уничтожить, присвоив переменной значение null — если ссылки на объект две и более, то таким образом уничтожается ссылка, а не объект.
  5. Объект можно перебирать в цикле.
  6. Объекты могут быть свойствами других объектов.
  7. У объектов есть прототип.
  8. Свойствами объекта могут быть массивы.
  9. Все объекты получают свойства и методы прототипа — пользовательские объекты наследуют прототип конструктора и Object.prototype.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *