Пошук уроків, статей та іншого контенту
Дізнайтеся, як оператор delete видаляє властивості об'єктів і які обмеження він має. Розберіть, чому delete не варто використовувати як універсальний спосіб видалення змінних або елементів масиву.
deleteОператор delete видаляє властивість об’єкта:
const user = {
name: "Олена",
age: 28
};
delete user.age;
console.log(user); // { name: "Олена" }
console.log(user.age); // undefinedПісля видалення властивість більше не належить об’єкту. Це відрізняється від присвоєння undefined:
const first = {
value: undefined
};
const second = {};
console.log(first.value); // undefined
console.log(second.value); // undefined
console.log("value" in first); // true
console.log("value" in second); // falseУ першому об’єкті властивість value існує, але її значення дорівнює undefined. У другому об’єкті властивості value немає.
delete object.property;
delete object["property"];Для обчислюваної назви властивості використовується квадратна нотація:
const settings = {
theme: "dark",
language: "uk"
};
const propertyName = "theme";
delete settings[propertyName];
console.log(settings); // { language: "uk" }Результатом оператора delete є логічне значення:
true, якщо властивість успішно видалено або її не існує;
false, якщо видалення заборонене в нестрогому режимі;
виняток TypeError у строгому режимі, якщо властивість не можна видалити.
const product = {
name: "Keyboard"
};
console.log(delete product.name); // true
console.log(delete product.name); // trueПовторне видалення відсутньої властивості також повертає true.
Можливість видалення визначається дескриптором властивості configurable.
Звичайні властивості, створені через об’єктний літерал або присвоєння, зазвичай є конфігурованими:
const object = {
title: "JavaScript"
};
console.log(Object.getOwnPropertyDescriptor(object, "title"));
// {
// value: "JavaScript",
// writable: true,
// enumerable: true,
// configurable: true
// }
delete object.title;
console.log(object.title); // undefinedВластивість можна зробити такою, що не видаляється, за допомогою Object.defineProperty():
const config = {
version: "1.0"
};
Object.defineProperty(config, "version", {
configurable: false
});
console.log(delete config.version); // false у нестрогому режимі
console.log(config.version); // "1.0"У строгому режимі спроба видалити таку властивість спричинить TypeError:
"use strict";
const config = {};
Object.defineProperty(config, "version", {
value: "1.0",
configurable: false
});
delete config.version; // TypeErrorЯкщо не вказати інші параметри дескриптора в Object.defineProperty(), вони матимуть значення false. Тому для властивості вище writable та enumerable також дорівнюють false.
delete і змінніdelete не призначений для видалення змінних.
let count = 10;
// delete count; У строгому режимі delete count є синтаксичною помилкою. У нестрогому режимі оператор не видаляє локальну змінну.
Змінні, оголошені через let, const і var, належать до лексичного або змінного оточення, а не є звичайними властивостями об’єкта.
let userName = "Олена";
const userAge = 28;
var userCity = "Львів";
// delete userName; // не можна видалити зміннуОкремий випадок — властивість глобального об’єкта. У браузері глобальна змінна, оголошена через var, зазвичай створює властивість window, а let і const — ні:
var browserName = "Chrome";
let language = "uk";
console.log(window.browserName); // "Chrome"
console.log(window.language); // undefined
delete window.browserName;
console.log(window.browserName); // undefinedНа практиці не варто покладатися на такі відмінності між середовищами. Для даних, які потрібно динамічно додавати або видаляти, краще використовувати явний об’єкт:
const session = {
token: "abc123",
userId: 42
};
delete session.token;
console.log(session); // { userId: 42 }delete видаляє лише власну властивість об’єкта. Якщо властивість успадкована з прототипу, оператор не видалить її з прототипу:
const parent = {
role: "admin"
};
const child = Object.create(parent);
console.log(child.role); // "admin"
delete child.role;
console.log(child.role); // "admin"
console.log(Object.hasOwn(child, "role")); // falseУ цьому прикладі child.role доступна через прототип parent. У самого child такої властивості немає, тому delete child.role нічого не змінює.
Щоб прибрати властивість для всіх об’єктів, які її успадковують, потрібно видаляти її з прототипу:
delete parent.role;
console.log(child.role); // undefinedТакі зміни прототипів слід робити обережно, оскільки вони впливають на всі пов’язані об’єкти.
Технічно delete може видалити елемент масиву:
const colors = ["red", "green", "blue"];
delete colors[1];
console.log(colors); // [ "red", <1 empty item>, "blue" ]
console.log(colors.length); // 3
console.log(colors[1]); // undefined
console.log(1 in colors); // falseОднак масив не стає коротшим. На місці видаленого елемента утворюється «дірка» — порожній слот.
Це відрізняється від елемента зі значенням undefined:
const withUndefined = ["red", undefined, "blue"];
const withHole = ["red", "green", "blue"];
delete withHole[1];
console.log(1 in withUndefined); // true
console.log(1 in withHole); // falseБагато методів масивів пропускають порожні слоти:
const items = ["a", "b", "c"];
delete items[1];
items.forEach((item, index) => {
console.log(index, item);
});
// 0 "a"
// 2 "c"Тому delete майже ніколи не є правильним способом видалення елемента масиву.
splice()Якщо потрібно видалити елементи та зменшити довжину масиву, використовуйте splice():
const colors = ["red", "green", "blue"];
colors.splice(1, 1);
console.log(colors); // [ "red", "blue" ]
console.log(colors.length); // 2Метод splice(start, deleteCount) змінює початковий масив:
start — індекс, з якого починається операція;
deleteCount — кількість елементів для видалення.
Для видалення всіх елементів, що відповідають умові, часто зручніше створити новий масив через filter():
const numbers = [1, 2, 3, 4, 5, 6];
const evenNumbers = numbers.filter((number) => number % 2 === 0);
console.log(evenNumbers); // [2, 4, 6]
console.log(numbers); // [1, 2, 3, 4, 5, 6]filter() не змінює початковий масив, а повертає новий.
delete не видаляє значення з пам’яті безпосередньоОператор видаляє посилання на властивість, а не «примусово очищує» об’єкт із пам’яті.
Якщо на об’єкт залишилися інші посилання, він продовжує існувати:
const address = {
city: "Київ"
};
const user = {
name: "Олена",
address
};
delete user.address;
console.log(user.address); // undefined
console.log(address.city); // "Київ"Об’єкт, на який посилається address, не зник, оскільки змінна address усе ще містить посилання на нього.
JavaScript використовує автоматичне збирання сміття. Коли об’єкт стає недоступним з коренів програми, рушій може звільнити пам’ять. Коли саме це відбудеться, код напряму не контролює.
delete і прототипи вбудованих об’єктівdelete може видалити властивість із прототипу, але змінювати вбудовані прототипи без необхідності не рекомендується:
const customObject = {
value: 10
};
Object.prototype.extraValue = 20;
console.log(customObject.extraValue); // 20
delete Object.prototype.extraValue;
console.log(customObject.extraValue); // undefinedЗміна Object.prototype впливає на велику кількість об’єктів у програмі та може призвести до важких для пошуку помилок.
Object.freeze()Object.freeze() робить властивості об’єкта неконфігурованими. Після цього їх не можна видалити:
"use strict";
const settings = {
theme: "dark"
};
Object.freeze(settings);
delete settings.theme; // TypeErrorБез строгого режиму спроба може повернути false, але властивість залишиться:
const settings = {
theme: "dark"
};
Object.freeze(settings);
console.log(delete settings.theme); // false
console.log(settings.theme); // "dark"У наступному прикладі властивості об’єкта видаляються за умовою, а елементи масиву — за допомогою filter():
const account = {
id: 42,
name: "Олена",
email: "olena@example.com",
temporaryToken: "secret-token"
};
// Тимчасовий токен більше не потрібен після авторизації.
delete account.temporaryToken;
console.log(account);
// { id: 42, name: "Олена", email: "olena@example.com" }
const tasks = [
{ id: 1, title: "Прочитати документацію", completed: true },
{ id: 2, title: "Написати код", completed: false },
{ id: 3, title: "Запустити тести", completed: true }
];
const activeTasks = tasks.filter((task) => !task.completed);
console.log(activeTasks);
// [ { id: 2, title: "Написати код", completed: false } ]
console.log(tasks.length); // 3У цьому коді delete доречний для видалення непотрібної властивості об’єкта, а filter() — для створення списку без завершених завдань.
delete для масивівconst values = [10, 20, 30];
delete values[1];
console.log(values.length); // 3Такий код залишає порожній слот. Для видалення елемента зі зміщенням наступних елементів використовуйте splice().
undefined і відсутньою властивістюconst object = {
value: undefined
};
console.log(object.value); // undefined
console.log("value" in object); // true
delete object.value;
console.log("value" in object); // falseПеревірка object.property === undefined не дозволяє надійно відрізнити відсутню властивість від властивості зі значенням undefined.
const або letconst token = "abc";
// delete token; // помилкаЗмінну не можна видалити оператором delete. Якщо потрібно прибрати дані, зберігайте їх у властивості об’єкта й видаляйте саме цю властивість.
У нестрогому та строгому режимах поведінка під час видалення неконфігурованої властивості відрізняється:
const object = {};
Object.defineProperty(object, "id", {
value: 1,
configurable: false
});
// У нестрогому режимі: false.
// У строгому режимі: TypeError.
delete object.id;Для передбачуваної поведінки використовуйте строгий режим і враховуйте дескриптори властивостей.
Якщо властивість успадкована, delete object.property не видалить її з прототипу. Перевіряйте, де саме визначена властивість:
console.log(Object.hasOwn(object, "property"));delete видаляє властивість об’єкта.
Видалення можливе лише для конфігурованих властивостей.
Успішне видалення повертає true.
delete не призначений для видалення змінних let, const або var.
Для неконфігурованих властивостей у строгому режимі виникає TypeError.
Видалення елемента масиву створює порожній слот і не зменшує length.
Для масивів використовуйте splice() або filter() залежно від потрібної поведінки.
delete видаляє лише власну властивість, а не властивість із прототипу.
Видалення властивості не гарантує негайного звільнення пам’яті.