Довжина об’єкта в JavaScript

9 Липня 2019

наступна стаття
Микола Гоцалюк

Frontend TeamLead

Микола Гоцалюк
Довжина об’єкта в JavaScript

Можливо дехто і буде здивований, але  визначити довжину Object простим викликом length на об’єкті — неможливо! Переконайтеся самі:

var object = { first: 1, second: 2 };
object.length // undefined

Як би ми не старалися нічого не вийде, оскільки в Object немає параметру length. Він присутній лише у таких типів даних як array та string:

var object = { first: 1, second: 2 };
var string = 'string';
var array = [1,2,3];

object.hasOwnProperty('length'); // false
string.hasOwnProperty('length'); // true
array.hasOwnProperty('length'); // true

Шлях до визначення довжини

На відміну від масивів, отримати довжину об'єкта завжди було складно. Object.keys() повертає enumerated-масив всіх ключів властивостей об'єкта, а після цього можна просто використати length та отримати його довжину.

var object = { first: 1, second: 2 };
Object.keys(object).length; // 2

Але на практиці не все так просто, як із першого погляду. Тому для більш детального пояснення було б добре розібратись в походженні цього enumerated масиву.

Як правило, коли ми хочемо додати властивість до об'єкта, ми можемо це зробити за допомогою крапки:

var object = { first: 1};
object.second = 2;
console.log(object); // { first: 1, second: 2 }

Альтернативним шляхом може бути використати Object.defineProperty() який приймає три параметри: obj, prop, descriptor. Enumerated-атрибут можна вказати якраз у descriptor:

const object = {};
Object.defineProperty(
 object,
 'first', {
   value: '1',
   enumerable: true 
 }
);
console.log(object); // { first: '1' }

Автоматичне визначення

Давайте повернемося до нашого прикладу властивостей об'єкта, що ми встановили за допомогою крапки. Чому він відображався автоматично? Це відбувається тому, що коли ми вказуємо  властивість, атрибут enumerable автоматично встановлюється як значення true.

var object = {};
object.first = 1;
object.propertyIsEnumerable(first); // true

У більшості випадків ми б не використовували enumerable-атрибут для визначення length. Це просто надійний спосіб контролювати, чи буде створена властивість видимою, чи прихованою, коли ми перебираємо об'єкт за допомогою Object.keys.

Таким чином, атрибут enumerable використовується для приховування властивостей, що не слід повторювати. Це стало причиною введення перелічуваності в ECMAScript 1.

const object = {first: '1'};
Object.defineProperty(
 object,
 'second', {
   value: '2',
   enumerable: false
 }
);
Object.keys(object); // [ 'first' ]
Object.getOwnPropertyNames(object); // [ 'first', 'second' ]

Як можна зрозуміти з прикладу вище, Object.getOwnPropertyNames поверне масив з іменами усіх ключів, в той час як  Object.keys поверне масив імен тільки enumerable-ключів. Здавалося б, що краще використовувати метод  Object.getOwnPropertyNames для знаходження length. Але швидше всього, ці параметри об’єкту не є enumerable та мають бути приховані. Тому використовувати в даному контексті Object.getOwnPropertyNames — не найкраща ідея.

Додаткові можливості

Перед початком використання Object.keys за замовчуванням для знаходження length об’єкта, необхідно зробити невелику ремарку. В стандарті ECMAScript 6, ES6, представлений новий тип даних —  symbol. Його використання можливе у якості імені ключа властивості об’єкта.

const obj = {
 [Symbol('first')]: 1,
 second: 2
};

Але за таких умов як Object.keys так і Object.getOwnPropertyNames не будуть працювати так, як від них вимагається.    

Object.keys(obj)
// ["second"]
Object.getOwnPropertyNames(obj)
// ["second"]

Як бачимо, символьний ключ відсутній в обох масивах. Рішеням цієї проблеми буде використання Object.getOwnPropertySymbols:

Object.getOwnPropertySymbols(obj)
// [Symbol(first)]

Таким чином ми отримали масив тільки з імен ключів властивостей типу symbol.  І тепер для отримання length  нам необхідно просто скомбінувати обидва методи: 

const symbolsLength = Object.getOwnPropertySymbols(obj);
const withoutSymbolLength = Object.keys(obj);
const length = symbolsLength + withoutSymbolLength;

Схожі статті
Записатись на консультацію

Ми зв'яжемось з Вами протягом 10 хвилин