Создание объектов в JavaScript. Прототипы и наследование

Александр Мальцев
Александр Мальцев
24K
9
Содержание:
  1. Объекты и способы их создания
  2. Литеральный синтаксис
  3. Прототипы
  4. Создание объекта с помощью функции-конструктора
  5. Наследование встроенных объектов
  6. Object.create() – создание объекта с указанием прототипа
  7. Массив объектов и приёмы работы с ним
  8. Как проверить является ли объект пустым
  9. Комментарии

Статья, в которой познакомимся с понятием объекта и прототипа. Рассмотрим, как осуществляется наследование в JavaScript и создание собственных объектов. Разберём массив объектов и приёмы работы с ним.

Объекты и способы их создания

Объект – это один из типов данных в JavaScript, который предназначен для хранения коллекции различных значений и более сложных сущностей.

Всего в JavaScript существует 8 типов данных: number, bigint, string, boolean, null, undefined, symbol и object. Но все они в отличие от объекта являются примитивными. При присвоении переменной значения примитивного типа, оно непосредственно сохраняется в переменную.

// объявление переменной mark с помощью ключевого слова let и присвоение переменной числа 4
let mark = 4;
// присвоение переменной mark нового значения
mark = 'Good!';

Копирование примитивных типов выполняется по значению (по английски – copy by value):

const mark = 4;
// создание переменной newMark и присвоение ей значения, находящегося в mark
let newMark = mark;
// присвоение newMark нового значения
newMark = 5;

console.log(mark); // 4
console.log(newMark); // 5

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

Объекты – это ссылочный тип. Таким образом, когда присваиваете объект переменной, вы на самом деле присваиваете переменной ссылку на объект, которая на его указывает.

Создавать объекты в JavaScript можно разными способами:

  • с использованием литерального синтаксиса;
  • с помощью ключевого слова new и указания типа создаваемого объекта;
  • на основе прототипов (Object.create())

Литеральный синтаксис

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

Литерал объекта записывается с помощью фигурных скобок {...}, внутрь которых помещают свойства, отделенные друг от друга посредством запятой:

const person = {
  firstName: 'Александр',
  lastName: 'Мальцев',
  age: 28,
  getFullName: function () {
    return `${this.firstName} ${this.lastName}`
  }
}

В этом примере объект содержит четыре свойства: firstName, lastName, age и getFullName. При этом свойство getFullName является методом, т.к. его значение является функцией.

Сокращённый формат записи методов выполняется без использования ключевого слова function и двоеточия:

const person = {
  // ...
  getFullName() {
    return `${this.firstName} ${this.lastName}`
  }
}

Свойства

Свойства состоят из ключа и значения. Отделяется ключ от значения посредством двоеточия. Свойства подобны переменным, но в составе объекта.

Обращение к свойствам выполняется через точку или квадратные скобки:

// через точку
const firstName = person.firstName;
const lastName = person.lastName;
// через квадратные скобки (ключ в этом случае нужно указывать в формате строки)
const age = person['age'];
const getFullName = person['getFullName'];

Значения, связанные с соответствующими ключами можно не только получить, но и изменить:

// изменим значения свойств firstName и lastName
person.firstName = 'Иван';
person.lastName = 'Михайлов';

А также добавить новые свойства к объекту:

// добавления к объекту person свойства middleName со значением 'Сергеевич'
person.middleName = 'Сергеевич';

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

Например, установим в качестве значения свойства children массив объектов:

person.children = [
  {
    name: 'Аня',
    age: 8
  },
  {
    name: 'Ваня',
    age: 14
  }
];

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

// удалим свойство middleName из объекта person
delete person.middleName;

Проверить наличия ключа в объекте можно посредством оператора in:

console.log( 'firstName' in person ); // true
console.log( 'middleName' in person ); // false

Методы

Методы, как мы уже отмечали выше – это свойства, значение которого является функцией.

Обращение к ним осуществляется также как к свойствам (через точку или с использованием квадратных скобок):

const person = {
  firstName: 'Александр',
  lastName: 'Мальцев',
  age: 28,
  getFullName() {
    console.log(`${this.firstName} ${this.lastName}`);
  }
}

// создание переменной getFullName и присвоение ей ссылки на метод getFullName объекта person
const getFullName = person.getFullName;
// тоже самое только через квадратные скобки
// const getFullName = person['getFullName'];

Но, так как методы – это функции, то их соответственно можно вызвать. Вызов метода выполняется также как функции, т.е. с использованием круглых скобок:

const getFullName = person.getFullName;
// вызвать метод
getFullName();
// или сразу
person.getFullName();
person['getFullName']();

Кроме выполнения действий методы всегда возвращают значения. В данном примере вызов getFullName() возвращает значение undefined, т.к. явно мы его не задали с помощью оператора return:

console.log(getFullName()); // undefined

Краткая запись свойств

Пример, в котором значения свойствам устанавливаются из переменных, имеющих точно такие же имена:

const createRect = (width, height) => {
  // возвращаем объект
  return {
    width: width,
    height: height,
    calcArea() {
      return this.width * this.height;
    }
  }
}
const rect = createRect(10, 15);
console.log( rect.calcArea() ); // 150

Когда имя свойства совпадает с названием переменной эту запись можно сделать краткой:

{
  width, // вместо width: width
  height, // вместо height: height
  //...
}

Именование ключей в объекте

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

const someObj = {
  '': 1, // ключом является пустая строка
  'author of post': 'Алексей', // в ключе используются пробелы
}

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

const key = 'author of post';
const value = someObj[key];

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

// получим значения свойства, имя которой является пустой строкой
//const value = someObj[''];

Сравнение объектов JavaScript с объектами реальной жизни

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

Например, взять фонарик. Фонарик – это объект со свойствами. У него есть цвет, яркость, длина, диаметр и т.д. Точно также объекты JavaScript могут иметь свойства, определяющие его характеристики. Кроме этого, у него имеется ещё функционал. Его можно включить и выключить. В JavaScript – это методы.

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

// фонарик
const flashlight = {
  color: 'black',
  brightness: 300,
  long: 13.5,
  diameter: 2.6,
  isOn: false,
  turnOn() {
    this.isOn = true;
  },
  turnOff() {
    this.isOn = false;
  }
}

Вычисляемые свойства

В JavaScript, начиная с версии ES6 (ES2015), появилась возможность использовать выражения в квадратных скобках [].

const key = 'url';
const apps = {
    name: 'Facebook',
    [key]: 'facebook.com', // имя свойства будет взято из переменной key
};
console.log(apps.url); // "facebook.com"

Пример с использованием более сложных выражений:

const key = 'url';
const apps = {
  name: 'Facebook',
  [key]: 'facebook.com',
  ['get' + key.toUpperCase()]: function() {
    return this[key];
  }
};

console.log( apps.getURL() ); // "facebook.com"

Копирование объектов, ссылок

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

// присвоим переменной student1 объект (а точнее ссылку на него)
let student1 = { name: 'Игорь' };
// скопируем объект, содержащийся в переменной student1 в student2 (а точнее ссылку на него)
let student2 = student1;

Теперь student1 и student2 содержат ссылки, указывающие на один и тот же объект.

Изменим значения свойства name, используя student2:

student2.name = 'Вася';

Получим значение свойства name через student1:

console.log( student1.name ); // Вася

А что если нам необходимо скопировать не саму ссылку, а создать новый объект с такими же свойствами?

let student3 = {};
for (const key in student1) {
  student3[key] = student1[key];
}
// student3 содержит клон объекта student1
student3.name = 'Александр';
// в student1 значение name осталось прежним
console.log( student1.name ); // Вася

Другой способ скопировать свойства – это воспользоваться методом Object.assign():

// копирует все свойства из student1 в {}, а затем возвращает его
const student4 = Object.assign({}, student1);

Object.assign() позволяет скопировать свойства из множества объектов. Объект, в который нужно скопировать задаётся в первом аргументе, а те из которых – начиная со второго.

const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };

Object.assign(target, source1, source2);
console.log(target); // {a: 1, b: 2, c: 3}

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

Сравнение объектов выполняется по ссылкам.

let objA = {};
let objB = objA;
let objC = {};

console.log( objA === objB ); // true, т.к. переменные содержат одну и ту же ссылку
console.log( objA === objC ); // false, т.к. переменные содержат разные ссылки (оба объекта пусты, но это разные объекты)

Прототипы

Каждый объект в JavaScript имеет специальное внутреннее свойство, которое указывает на его прототип. В спецификации оно называется [[prototype]].

Задать его можно с помощью __proto__. Это свойство доступно во всех браузерах несмотря на то, что оно не является стандартным.

Например, создадим 2 объекта и для второго укажем в качестве прототипа первый:

const point2 = {
  coords: [5, 7],
  getCoords() {
    return this.coords;
  }
}
const point3 = {
  coords: [3, 19, 7]
}
// укажем в качестве прототипа point3 объект point2
point3.__proto__ = point2;

Прототип сам по себе является просто объектом. А это значит, что он в свою очередь тоже может иметь свой собственный прототип и так далее. Эту последовательность в JavaScript часто называют цепочкой прототипов. Цепочка заканчивается, когда мы достигаем прототипа, который в качестве __proto__ имеет значение null.

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

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

// getCoords() взят из прототипа
console.log( point3.getCoords() ); // [3, 19, 7]

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

// hasOwnProperty взят из прототипа point3.__proto__.__proto__
console.log( point3.hasOwnProperty('coords') );  // true
// z – нет такого ключа в прототипах
console.log( point3.z); // undefined

Свойства и методы объекта, которые берутся из прототипа называются «унаследованными».

Добавим к point3 метод getCoords():

point3.getCoords = function() {
  return `Coords: [${this.coords.join('; ')}]`;
}

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

point3.getCoords(); // 'Coords: [3; 19; 7]'

Кроме __proto__ для получения и установки прототипа можно также воспользоваться методами Object.getPrototypeOf() и Object.setPrototypeOf():

const objA = {
  keyA: 'apple'
}
const objB = {
  keyB: 'bow'
}
const objC = {
  keyC: 'chair'
}
// установим в качестве прототипа ObjC объект ObjB
Object.setPrototypeOf(objC, objB); // objC.__proto__ = objB
// установим в качестве прототипа ObjB объект ObjA
Object.setPrototypeOf(objB, objA); // objB.__proto__ = objA

Object.getPrototypeOf(objC); // {keyB: 'bow'}
// или
objC.__proto__ // {keyB: 'bow'}

Object.getPrototypeOf(Object.getPrototypeOf(objC)); // {keyA: 'apple'}
// или
objC.__proto__.__proto__ // {keyA: 'apple'}

Мы не можем указать в качестве прототипа объект, который уже имеется в цепочке (т.е. замкнуть её).

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

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

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

Функция-конструктор – это обычная функция. Поэтому чтобы было хоть какое-то отличие её имя должно начинаться с прописной буквы.

Вызов функции-конструктора осуществляется с использованием оператора 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 указывает на создаваемый (новый) объект.

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

Когда мы создаём новый объект посредством оператора new, то ему в качестве прототипа задаётся объект, содержащийся в свойстве prototype функции-конструктора.

// функция-конструктор
function Point(x, y) { ... }
// новый объект типа Point, его прототип будет задан объектом, содержащимся в Point.prototype
const point1 = new Point(2, 6);

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

function Point(x, y) { ... }
console.log( Point.prototype ); // { constructor: f } 

То есть:

console.log( Point.prototype.constructor === Point ); // true

Таким образом, при создании нового объекта типа Point, его прототип будет равен Point.prototype:

const point1 = new Point(10, 40);
console.log( point1.__proto__ === Point.prototype ); // true

Свойство prototype доступно для записи. Например, установим в качестве прототипа другой объект:

function Point(x, y) { ... }
// установим в качестве прототипа объект со свойствами firstName и lastName
Point.prototype = {
  firstName: 'Александр',
  lastName: ' Мальцев',
}
const point1 = new Point(10, 40);
console.log( point1.__proto__ ); // {firstName: 'Александр', lastName: 'Мальцев'}

Объект, который мы установили в качестве прототипа не содержит свойство constructor.

Чтобы его сохранить можно добавить это свойство в объект:

// prototype функции-конструктора Point
Point.prototype = {
  firstName: 'Александр',
  lastName: ' Мальцев',
  constructor: Point
}

Или не присваивать Point.prototype другой объект, а просто изменить его:

// изменим прототип
Point.prototype.firstName = 'Александр';
Point.prototype.lastName = 'Мальцев';

Пример

Пример, в котором рассмотрим, как использовать прототипы для реализации наследования:

// функция-конструктор для создания объектов типа Rectangle
function Rectangle(x1, y1, x2, y2, bgColor) {
  this.left = Math.min(x1, x2);
  this.top = Math.min(y1, y2);
  this.width = Math.max(x1, x2) - this.left;
  this.height = Math.max(y1, y2) - this.top;
  this.bgColor = bgColor;
}
// определим метод draw() в прототипе Rectangle
Rectangle.prototype.draw = function() {
  const el = document.createElement('div');
  el.style.position = 'absolute';
  el.style.left = `${this.left}px`;
  el.style.top = `${this.top}px`;
  el.style.width = `${this.width}px`;
  el.style.height = `${this.height}px`;
  el.style.backgroundColor = this.bgColor;
  document.body.append(el);
}
// функция-конструктор для создания объектов типа Square
function Square(x, y, side, bgColor) {
  // вызываем функцию в текущем контексте
  Rectangle.call(this, x, y, x + side, y + side, bgColor);
}
// установим в качестве прототипа Square прототип Rectangle
Square.prototype.__proto__ = Rectangle.prototype;
// функция-конструктор для создания объектов типа Circle
function Circle(x, y, r, bgColor) {
  Square.call(this, x, y, r, bgColor);
  this.radius = r;
}
// установим в качестве прототипа Circle прототип Square
Circle.prototype.__proto__ = Square.prototype;
// определим новый метод draw() в прототипе Circle
Circle.prototype.draw = function () {
  const el = document.createElement('div');
  el.style.position = 'absolute';
  el.style.left = `${this.left}px`;
  el.style.top = `${this.top}px`;
  el.style.width = `${this.width}px`;
  el.style.height = `${this.height}px`;
  el.style.borderRadius = `${this.radius}px`;
  el.style.backgroundColor = this.bgColor;
  document.body.append(el);
}

// создадим новый объект типа Rectangle
const rectangle = new Rectangle(70, 80, 200, 300, '#673ab7');
rectangle.draw();

// создадим новый объект типа Square
const square = new Square(250, 50, 150, '#ff9800');
square.draw();

// создадим новый объект типа Circle
const circle = new Circle(450, 140, 90, '#4caf50');
circle.draw();

Создание объекта с помощью конструктора Object()

Ещё один способ создать объект в JavaScript – это использовать конструктор Object().

new Object() создаёт пустой объект, который будет иметь в качестве прототипа Object.prototype.

// создание пустого объекта
const emptyObj = new Object();
// прототипом emptyObj является Object.prototype
console.log( emptyObj.__proto__ === Object.prototype );

// создадим новый пустой объект flashLight
const flashlight = new Object();
// добавим свойства
flashlight.color = 'black';
flashlight.brightness = 300;
flashlight.long = 13.5;
flashlight.diameter = 2.6;
flashlight.isOn: false,
// добавим методы
flashlight.turnOn = function() {
  this.isOn = true;
}
flashlight.turnOff = function() {
  this.isOn = false;
}

Переменные внутри объекта

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

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;
}

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

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

В JavaScript практически всё (функции, массивы, регулярные выражения и т.д.) является объектами за исключением семи примитивных типов данных (String, Number, Boolean, Null, Undefined, Symbol и Bigint).

Например, при создании даты используется конструктор Date.

const now = new Date();
// конструктор
console.log( now.constructor === Date ); // true
Методы прототипа конструктора Date

Прототипом даты является объект Date.prototype:

console.log( now.__proto__ === Date.prototype ); // true

Он предоставляет методы для работы с датой:

JavaScript - Date.prototype

Т.е. getDate(), getHours() и т.д. находятся в Date.prototype. Их нет в now, но они доступны нам в нём из-за наследования.

В свою очередь Date.prototype имеет в качестве прототипа Object.prototype.

console.log( Date.prototype.__proto__ === Object.prototype );
// или
console.log( now.__proto__.__proto__ === Object.prototype ); // true

А следовательно нам также будут доступны методы Object.prototype, которые нет Date.prototype. Например, hasOwnProperty:

console.log( now.hasOwnProperty('getYear') ); // false

Корнем иерархии встроенных прототипов в JavaScript является 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

Object.create() – создание объекта с указанием прототипа

Метод Object.create() позволяет создать новый объект с указанным прототипом.

// создадим новый объект point2d;
const point2d = {
  x: 5,
  y: 7
}
// создадим новый объект, прототипом которого будет point2d
const point3d = Object.create(point2d);
point3d.z = 8;

// получим прототип объекта point3d
console.log( Object.getPrototypeOf(point3d) ); // {x: 5, y: 7}

Создание объекта с прототипом Object.prototype:

const obj = Object.create(Object.prototype);
// эквивалентно этому:
// const obj = {};

Создание объекта без прототипа:

const obj = Object.create(null);

Пример использования Object.create() для реализация наследования.

// функция-конструктор Product
function Product(name, price, discount) {
  this.name = name;
  this.price = price;
  this.discount = discount;
}

Product.prototype.calcDiscountedPrice = function () {
  return (this.price * (1 - this.discount / 100)).toFixed(2);
}

// функция-конструктор Product
function Book(name, price, discount, isbn, author, totalPages) {
  // вызываем конструктор ProductS
  Product.call(this, name, price, discount);
  this.isbn = isbn;
  this.author = author;
  this.totalPages = totalPages;
}

//
Book.prototype = Object.create(Product.prototype);
Book.prototype.constructor = Book;

const book = new Book('Краткая история времени', 611.00, 5, 9785171022846, 'Стивен Хокинг', 232);
// цена книги со скидкой
console.log(book.calcDiscountedPrice()); // 580.45

Массив объектов и приёмы работы с ним

Массив объектов - это массив, элементами которого являются объекты.

Пример создания массива, имеющего в качестве элементов объекты:

var arrHeaders = [
  {
    tag: "H2",
    id: "page-1",
    text: "Заголовок 1"
  },
  {
    tag: "H2",
    id: "page-2",
    text: "Заголовок 2"
  }
]

Добавление к массиву, приведённому выше ещё одного объекта:

arrHeaders.push(
  {
    tag: "H2",
    id: "page-3",
    text: "Заголовок 3"
  }
);

Пример динамического создания массива объектов:

// переменная в которую поместим массив объектов
var arrHeaders = [];
// переберём заголовки h1, h2, h3 и h4 на странице и сформируем из них массив объектов
document.querySelectorAll('h1, h2, h3, h4').forEach(function(item) {
  arrHeaders.push({
    tag: item.tagName,
    id: item.id,
    text: item.textContent
  })
});
// выведем массив, содержащий объекты в консоль
console.log(arrHeaders);

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

// array - массив содержащий объекты
// property - свойство массива
// value - искомое значение
function findObjectInArray(array, property, value) {
  var result;
  array.forEach(function(item, index){
    if (item[property] === value) {
      result = item;
      return;
    }
  });
  return result; // в качестве результата возвращает первый найденный объект или значение undefined
}

// например, найдём объект в массиве по свойству text, значения которого равно "Заголовок 2"
var findObject = findObjectInArray(arrHeaders, 'text', 'Заголовок 2'); // найденный индекс

if (findObject) {
  console.log(findObject);
} else {
  console.log('Объект не найден!');
}

Ещё один вариант выполнения поиска в массиве объектов (с использованием метода find):

// value - значение элемента
// index - индекс элемента
// array - массив
function checkHeaderText(value, index, array) {
  if (value.id === "page-3") {
    return true; // прекращает выполнение и возвращает указанный элемент
  }
}

// например, найдём объект в массиве по свойству id, значения которого равно "page-3"
var findObj = arrHeaders.find(checkHeaderText);

if (findObj) {
  console.log(findObj);
} else {
  console.log('Объект не найден!');
}

Пример кода, в котором показано как можно выполнить сортировку массива объектов (в данном случае arrArticles по полю title).

var arrArticles = [
  {
    href: "/article7",
    title: "Статья 7",
    likes: 15,
    comments: 5
  },
  {
    href: "/article1",
    title: "Статья 1",
    likes: 15,
    comments: 17
  },
  {
    href: "/article5",
    title: "Статья 5",
    likes: 3,
    comments: 10
  },
  {
    href: "/article3",
    title: "Статья 3",
    likes: 20,
    comments: 2
  }
]

function compareTitle(articleA, articleB) {
  if (articleA.title < articleB.title)
    return -1;
  if (articleA.title > articleB.title)
    return 1;
  return 0;
}

arrArticles.sort(compareTitle);

console.log(arrArticles);

Этот способ заключается в создании собственной функции сравнения и указания её в качестве параметра методу sort.

Пример кода, в котором показано как можно создать функцию сравнения для сортировки массива объектов по нескольким полям:

// функция сравнения для сортировки массива объектов сначала по свойству likes, а затем по comments
function compareLikesComments(articleA, articleB) {
  if ((articleA.likes > articleB.likes) || (articleA.likes === articleB.likes && articleA.comments > articleB.comments)) {
    return -1;
  } else if ((articleA.likes < articleB.title) || (articleA.likes === articleB.likes && articleA.comments < articleB.comments)) {
    return 1;
  }
  return 0;
}

arrArticles.sort(compareLikesComments);

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

// массив объектов
var points = [
  {x: 5, y: 7},
  {x: -2, y: 9},
  {x: 0, y: 8},
  {x: -1, y: -3}
];

// поиск объекта в массиве по x и y
var findIndex =  function(x, y) {
  return points.findIndex(function(value, index, array){
    if (value.x === x && value.y === y) {
      return true;
    }
  })
};

// получения индекса (если объект не будет найден, то будет возвращено значение -1)
var result = findIndex(-2, 9);
if (result >= 0) {
  points.splice(result, 1); // удаляем объект из массива по его индексу
}
// выводим полученный массив объектов в консоль
console.log(points);

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

var points = [
  {x: 5, y: 7},
  {x: -2, y: 9},
  {x: 0, y: 8},
  {x: -1, y: -3}
];

// Задача: удалить из массива все объекты, у которых хотя бы одно из значений x или y меньше нуля

// 1 способ - посредством перебора (с использованием метода splice)
var i = points.length - 1;

while (i >= 0) {
  if (points[i].x < 0 || points[i].y > 0) {
    points.splice(i, 1);
  }
  i--;
}
console.log(points);

// 2 способ - с использованием метода filter
var filtered = points.filter(function(value, index, array){
  return value.x >= 0 && value.y >= 0;
});
console.log(filtered);

Как преобразовать объект в массив

Пример, в котором рассмотрим как в JavaScript можно преобразовать объект в массив.

// объект
var obj = {
  'key1': 'value1',
  'key2': 'value2',
  'key3': 'value3'
};
/* задача. преобразовать данный объект в массив:
[
  ['key1', 'value1'],
  ['key2', 'value2'],
  ['key3', 'value3']
};
*/

var arr = Object.entries(obj);

Как проверить является ли объект пустым

Несколько решений как можно проверить объект на пустоту:

// 1 способ
var isEmptyObject = function (obj) {
  var prop;
  for (prop in obj) {
    if(obj.hasOwnProperty(prop))
      return false;
    }
  return true;
}
// 2 способ (ECMAScript 5+)
var isEmptyObject2 = function (obj) {
  return Object.keys(obj).length === 0 && obj.constructor === Object;
}

var obj1 = {x: 5, y: 7};
var obj2 = {};

isEmptyObject(obj1); //false
isEmptyObject2(obj1); //false

isEmptyObject(obj2); //true
isEmptyObject2(obj2); //true

Инструкция с использованием функции isEmptyObject "если пришел пустой объект javascript" будет выглядеть так:

var obj = {};

// если пришёл пустой объект
if (isEmptyObject(obj)) {
  // инструкции которые будут выполнены если объект пустой
} else {
  // инструкции которые будут выполнены если объект не пустой
}

Комментарии:

  1. Toivo
    Toivo
    03.10.2021, 07:11
    В JavaScript содержится 8 различных типов данных. Семь из которых являются «примитивными»ю.
    Замените «ю» на.
    1. Александр Мальцев
      Александр Мальцев
      04.10.2021, 13:26
      Спасибо, поправил.
    2. Toivo
      Toivo
      08.09.2021, 00:16
      // выаодим в консоль значение статического свойства
      1. Александр Мальцев
        Александр Мальцев
        09.09.2021, 15:28
        Спасибо, поправил.
      2. Александр
        Александр
        11.11.2019, 23:30
        Алекандр, как всегда отличная статья. Два вопроса:

        1) Можно ли на объекте использовать те же методы, что и на массивах, map,filter,reduce или надо преобразовывать объект в массив?
        2) Можно ли удалить объект в объекте. Т.е. если условно стоит задача, находить внутри объекта a у какого из его объектов имеется свойство aaa равное 5 и удалять, но не свойство aaa, а сразу весь подобъект aa?

        const a = {
        aa = {
        aaa: 5,
        aab: 3,
        },

        bb = {
        aaa:8,
        aab: 9,
        }
        }

        1. Александр Мальцев
          Александр Мальцев
          12.11.2019, 01:31
          Благодарю за отзыв.
          1. Если у объекта и в его цепочки прототипов нет этих методов, то их конечно вызвать нельзя. Чтобы эти методы использовать этот объект конечно нужно привести к массиву.
          2. Удаление свойства осуществляется как обычно даже если оно является объектом:
          delete a.aa
          В примере свойства должны отделяться от значений с помощью двоеточия:
          const a = {
            aa: {
              aaa: 5,
              aab: 3,
            },
            bb: {
              aaa: 8,
              aab: 9,
            }
          }
        2. Дмитрий
          Дмитрий
          13.06.2016, 22:10
          А как удалить все теги из строки, по аналогии с функцией в php — strip_tags
          1. Александр Мальцев
            Александр Мальцев
            14.06.2016, 12:17
            Попробуйте для этого использовать методы textContent и innerText.
            Можно например для этого создать функцию, которая будет возвращать переданную ей строку, но уже без тегов.
            <script>
            //функция для убирания из строки html тегов
            function strip_tags(html) {
              var tmp = document.createElement("DIV");
              tmp.innerHTML = html;
              return tmp.textContent || tmp.innerText || "";
            }
            // некоторая строка содержащая html код
            var html ='<h2 class="page-header">Понятие объекта</h2>';
            // убрать из строки html-теги
            var output = strip_tags(html);
            // вывести содержимое строки в консоль
            console.log(output);
            </script>
            
          2. Иван
            Иван
            21.04.2016, 07:58
            Очень просто и доходчиво, спасибо автору!
            Войдите, пожалуйста, в аккаунт, чтобы оставить комментарий.