Статья в разработке!

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

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

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

В качестве примера рассмотрим объект реальной жизни «Фонарик». Фонарик, как и любой другой объект, имеет свойства. Свойства объекта – это его характеристики, например, материал корпуса, источник питания, длина и др. Т.е. это всё что можно описать с помощью существительных и прилагательных. Кроме свойств у объектов есть ещё действия (методы). Например, его можно включить и выключить. Некоторые методы, как например эти, предназначены для изменения состояния объекта. В общем, к действиям (методам) объекта относят обычно всё, что можно обозначить посредством глаголов.

JavaScript - Понятие объекта

Прототипы и наследование

В JavaScript каждый объект кроме свойств и методов имеет ещё внутреннюю ссылку (__proto__). Данная ссылка определяет связанный с данным объектом прототип. Прототип – это некоторый объект (отличный от данного) или же null.

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

В результате того, что в JavaScript каждый объект имеет прототип, между ними (объектами) образовываются соответствующие связи. Например, если взять некоторый объект, то от него посредством этой связи можно перейти к его прототипу, а от него к его прототипу и так далее до конца цепочки. Цепочка заканчивается тогда, когда прототипом является null. Данную цепочку ещё называют цепочкой прототипов.

JavaScript - Цепочка прототипов

Прототипы используются в JavaScript для организации наследования.

Например, когда необходимо получить доступ к некоторому свойству объекта интерпретатор JavaScript сначала ищет его в этом объекте. Если данного свойства в нём нет, то он переходит к прототипу и пытается найти его там. Если его там нет, то он пытается найти его в прототипе этого прототипа и так далее пока это свойство не найдётся или не завершится цепочка прототипов этого объекта. Если свойство не будет найдено, то будет возвращено значение undefined.

Кстати, наследование, основанное на прототипах - это единственный тип наследования, который есть в JavaScript.

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

Как организовано наследование стандартных объектов

В JavaScript всё (функции, массивы, регулярные выражения и т.д.) является объектами за исключением шести примитивных типов данных (string, number, boolean, null, undefined, symbol). Все объекты в JavaScript имеют в самой верхней точке прототипной цепи наследования Object.prototype. Объект Object.prototype не имеет прототипа.

// попробуем получить прототип объекта Object.prototype с помощью метода getPrototypeOf
Object.getPrototypeOf(Object.prototype); // null
// попробуем получить прототип объекта Object.prototype с помощью свойства __proto__
Object.prototype.__proto__; // null

Object.prototype имеет в качестве конструктора функцию Object.

// получим конструктор объекта Object.prototype
Object.prototype.constructor; // ƒ Object() { [native code] }

Конструктор (функция-конструктор) – это функция, посредством которой в JavaScript можно создавать объекты. Функция-конструктор вызывается с использованием ключевого слова new. Чтобы данную функцию можно было отличить от обычной функции, ей назначают имя, начинающееся с большой буквы.

При создании объектов с помощью функции-конструктора JavaScript добавляет к функции свойство prototype. Свойство prototype функции-конструктора – это объект, который будет являться прототипом, для каждого объекта, создаваемого с помощью этой функции-конструктора.

В тоже время объект (свойство prototype функции-конструктора) имеет свойство constructor по умолчанию. Свойство constructor указывает на функцию-конструктор, для которой объект является свойством prototype.

JavaScript - Object.prototype

Теперь рассмотрим, как в JavaScript организован некоторый тип данных (стандартный объект), например дата.

Создание даты (объект типа Date) осуществляется с помощью функции-конструктора Date.

// присвоенние переменной nowDate текущей даты (ссылки на объект типа Date)  
var nowDate = new Date(); 

Дата, хранящаяся в переменной nowDate, имеет в качестве прототипа объект Date.prototype. А объект Date.prototype имеет в качестве прототипа Object.prototype.

JavaScript - Date.prototype

В результате созданный объект типа Date, ссылка на который присвоена переменной nowDate, имеет доступ к методам getDate, getHours, isPrototypeOf и др. Всех этих методов нет в текущем объекте, но они доступны в нём из-за наследования.

Методы getDate и getHours находятся в прототипе Date.prototype, а метод isPrototypeOf – в Object.prototype.

Создание объектов в JavaScript можно осуществить синтаксически разными способами, с помощью таких как:

  • литерала объекта;
  • Object.create;
  • функции-конструктора;
  • ключевого слова class.

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

Литерал объекта – это один из самых простых способов создания объектов в JavaScript. Обычно он используется в том случае, когда необходимо создать только один объект. Выполняется создание объекта этим способом посредством заключения свойств, разделённых между собой с помощью запятой, в фигурные скобки:

{
  имя1: значение1,
  имя2: значение2,
  ...
}

Имя свойства отделяется от значения посредством двоеточия.

Пример объявления объекта, состоящего из двух свойств и одного метода:

// point – переменная, содержащая ссылку на объект
var point = {
  x: 40,
  y: 60,
  toString: function() {
    return 'x = ' + x + '; y = ' + y;
  }
}

В этом примере объявление метода осуществляется посредством указания в качестве значения свойства функции.

Кроме этого способа в JavaScript есть ещё один способ объявление метода. Он синтаксически выполняется без использования ключевого слова function.

// point – переменная, содержащая ссылку на объект
var point = {
  x: 40,
  y: 60,
  toString() {
    return 'x = ' + x + '; y = ' + y;
  }
}

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

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

var obj = {
  '': 1, // ТАКОЕ ИМЯ СВОЙСТВА ОБЯЗАТЕЛЬНО ДОЛЖНО БЫТЬ ЗАКЛЮЧЕНО В КАВЫЧКИ
  'name author': 'Алексей', // ТАКОЕ ИМЯ СВОЙСТВА ОБЯЗАТЕЛЬНО ДОЛЖНО БЫТЬ ЗАКЛЮЧЕНО В КАВЫЧКИ
  date: '11.08.2018',
  text: 'Некоторый текст...'
}

Доступ к свойствам объектов может осуществляться 2 способами:

  • через точку;
  • посредством квадратных скобок.
point.x; // получить значение свойства x объекта point через точку
point['x']; // получить значение свойства x объекта point посредством квадратных скобок
point.toString; // получить ссылку на метод (свойство, содержащее функцию) без его выполнения
point.toString(); // выполнить метод toString объекта point
point['toString']; // получить ссылку на метод toString объекта point без его выполнения
point['toString'](); // выполнить метод toString объекта point

При обращении к свойству через квадратные скобки имя свойство необходимо указывать в формате строки.

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

var propX = 'x';
point[propX]; // 40

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

obj['']; // 1

Чтобы изменить значение свойства необходимо просто присвоить ему новое значение.

point.x = 50; // установим свойству x объекта point в качестве значения число 50

Добавление свойства к объекту:

point.z = 35; // добавления свойства z к объекту point и присвоения ему в качестве значения числа 35

В качестве значений свойств объектов можно использовать любой тип данных, в том числе и объекты (ссылочный тип данных).

Удаление свойства у объекта осуществляется с помощью оператора delete:

delete point.z

Проверить есть ли свойство у объекта можно с помощью оператора in:

'z' in point; // проверить наличие свойства 'z' в объекте point

Создание объекта с использованием функции-конструктора

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

В JavaScript принято имя функции-конструктора начинать с прописной буквы. Это рекомендуемая условность позволяет отличить функцию-конструктора от обычной функции.

Вызов функции-конструктора осуществляется через оператор new.

// функция-конструктор Point
function Point(x,y) {
  this.x = x;
  this.y = y;
}
// создание объекта point1 через функцию-конструктор Point
var point1 = new Point(10,40);
// создание объекта point2 через функцию-конструктор Point
var point2 = new Point(30, 30);

В функции-конструкторе ключевое слово this указывает на создаваемый новый объект.

В JavaScript имеется встроенная функция-конструктор Object. Данная функция позволяет создать пустой объект, который будет иметь в качестве прототипа стандартный прототип объекта Object.prototype.

К сведению, благодаря этому стандартному прототипу, у пустого объекта будут доступны такие стандартные методы как toString, valueOf и др.

// создадим новый пустой объект flashLight
var flashLight = new Object();
// добавим к нему 3 свойства
flashLight.material = 'Алюминий';
flashLight.sourcePower = '2 батарейки AA';
flashLight.length = 13.5;
// добавим к нему 2 метода
flashLight.turnOn = function(){}
flashLight.turnOff = function(){}

При вызове функции-конструктора без аргументов скобки можно не указывать. Это разрешение стандартом, но делать так не рекомендуется.

// НЕ РЕКОМЕНДУЕТСЯ
var flashLight = new Object;
...

Ещё пример создания объектов через функцию-конструктор:

// функция-конструктор Circle
function Circle(selector, x, y, r, color) {
  this.selector = selector;
  this.x = x;
  this.y = y;
  this.r = r;
  this.color = color;
  this.setStyles = function(){
    var element = document.querySelector(this.selector);
    element.style.position = 'fixed';        
    element.style.left = (this.x - this.r) + 'px';
    element.style.top = (this.y - this.r) + 'px';        
    element.style.width = this.r + 'px';
    element.style.height = this.r + 'px';
    element.style.borderRadius = this.r + 'px';
    element.style.backgroundColor = this.color;
  }
}

// создание объекта circle1 через функцию-конструктор Circle
var circle1 = new Circle('#circle-1', 200, 200, 100, 'darkblue');
// вызов метода setStyles объекта circle1
circle1.setStyles();

// создание объекта circle1 через функцию-конструктор Circle
var circle2 = new Circle('#circle-2', 300, 300, 50, 'gray');
// вызов метода setStyles объекта circle2
circle2.setStyles();

При создании объектов через функцию-конструктор можно использовать локальные переменные и функции. Эти переменные и функции будут видны только внутри объекта, и не будут доступны вне его.

function Point(x, y) {
  // локальные переменные x и y
  var
    _x = x,
    _y = y;
  // методы объекта
  this.setX = function (x) {
    _x = x;
  }
  this.getX = function () {
    return _x;
  }
  this.setY = function (y) {
    _y = y;
  }
  this.getY = function () {
    return _y;
  }
}
// создание объекта point1
var point1 = new Point(11, 18);
// создание объекта point2
var point2 = new Point(24, 36);

// к переменной _x нет доступа из вне
console.log(point1._x); //undefined
// получить значение переменной _x можно с помощью метода getX
console.log(point1.getX()); //11
// установить значение переменной _x можно с помощью метода setX
point1.setX(12);

Обычно в функции-конструкторе не используется return. Функция-конструктор в качестве результата автоматически возвращает this. Но если в качестве результата функции-конструктора вернуть некоторый объект (с помощью return), то в этом случае он станет результатом, а не this.

// функция-конструктор Point
function Point(x,y) {
  this.x = x;
  this.y = y;
  return {
    r: 5
  }
}
// создание объекта point1 через функцию-конструктор Point
var point1 = new Point(10,40); // {r:5}
// у объекта point1 нет свойства x
console.log(point1.x); // undefined
// у объекта point1 нет свойства y
console.log(point1.y); // undefined
// у объекта point1 есть только свойство r
console.log(point1.r); // 5

Создать объект с использованием функции-конструктора можно сразу.

// создание объекта point с использованием функции-конструктора
var point = new function() {
  this.x = 20;
  this.y = 25;
}

Этот способ позволяет создать только один объект. Но он также применяется когда внутри функции необходимо использовать локальные переменные и функции.

Создание объекта с использованием Object.create

Object.create - это ещё один способ создания нового объекта в JavaScript. Данный способ отличается от других тем, что он позволяет указать прототип для создаваемого объекта.

В качестве прототипа можно указывать не только объект, но и специальное значение null.

Если указать null, то это будет означать, что объект не будет иметь прототипа.

// создание объекта point через Object.create
var point = Object.create(null);
// добавление свойств объекту point
point.x = 10;
point.y = 20;
// добавление метода объекту point
point.info = function(){
  return "Точка имеет координаты: x = " + this.x + "; y = " + this.y; 
}

// получение значения свойтсва x объекта point
point.x; // 10
// установление свойтсву y объекта point значения 15
point.y = 15;
// вызов метода info объекта point
point.info(); // "Точка имеет координаты: x = 10; y = 15"
// получим прототип объекта
Object.getPrototypeOf(point); // null
// создание объекта product через литерал объекта
var product = {
  id: '045332236',
  name: 'Danesi Doppio кофе в зернах, 2 кг',
  description: 'Элитный итальянский эспрессо, появившийся более ста лет назад. Секрет его популярности кроется в использовании самого отборного сырья, стабильном качестве, деликатной обжарке кофейных зерен.',
  price: 7943.00,
  discount: 5,
  currency: 'руб.',
  discountPrice: function () {
    return (this.price * (1 - this.discount / 100)).toFixed(2);
  }
}

// создание объекта book через Object.create (прототипом создаваемого объекта является объект product)
var book = Object.create(product);
// установление свойств
book.id = '141805815';
book.name = 'Краткая история времени';
book.description = 'В книге рассказывается о появлении Вселенной, о природе пространства и времени, чёрных дырах, теории суперструн и о некоторых математических проблемах.';
book.price = 611.00;
book.isbn = 9785171022846;
book.author = 'Стивен Хокинг';
book.totalPages = 232;
// получение свойства discount
book.discount; // 5 (величина скидки в процентах)
// вызов метода discountPrice объекта book
book.discountPrice(); // "580.45" (цена с учётом скидки)   
// new Object - создаём новый пустой объект
var flashLight = Object.create(null);
// осталось заполнить его свойствами
flashLight.material = 'Алюминий';
flashLight.sourcePower = '2 батарейки AA';
flashLight.length = 13.5;
flashLight.turnOn = function(){}
flashLight.turnOff = function(){}