Оглавление
- Вступление к публикации
- Как удалить собственное свойство объекта с строковым ключом JavaScript?
- Как удалить собственное свойство объекта с символьным ключом JavaScript?
- Как удалить наследованное свойство объекта JavaScript?
- Какое собственное свойство объекта JavaScript нельзя удалить?
- Код в строгом режиме и удаление собственного свойства объекта JavaScript
- Как использовать логические ответы оператора delete в функции в JavaScript?
- Как удалить свойство глобального объекта в JavaScript?
- Как удалить свойство конструктора класса в JavaScript?
- Как удалить свойство прототипа класса в JavaScript?
Вступление к публикации
Оператор delete и виды свойств объектов в JavaScript
Прежде чем удалять свойство у объекта нужно знать, что свойства объектов могут быть собственными и наследованными:
- Собственные свойства объекта легко удаляются унарным оператором delete. Унарный он потому, что умеет работать только с одним (UNO) операндом. То есть с тем, что находится справа от него.
- Наследованные свойства можно удалить только у объекта-прототипа, в котором они присутствуют, также при помощи оператора delete.
В общем если объекту не присваивалось значение для свойства, то удалить его напрямую через delete не получится.
Свойства глобального объекта
Важно знать, что в JavaScript всё наследование объектов по цепочке прототипов всегда приведёт нас к глобальному объекту. Это значит, что у любых объектов созданных вами есть один общий предок — глобальный объект с именем «window» на клиенте или глобальный объект с именем «global» на сервере.
Если в файле скрипта не писать операторы объявления переменных, а сразу писать имя идентификатора привязки и присваивать ему значение, то мы фактически создадим у глобального объекта новое свойство с этим именем. Это знание приводит нас к новому вопросу: «Как удалить свойство глобального объекта?».
Что лично вы называете объектом?
У начинающих разработчиков от избытка информации может начаться помутнение сознания в голове. Информация может перемешаться в «кашу». Поэтому сейчас очень важно вам самим ответить себе на вопрос: «У какого объекта я хочу удалить свойство?». Большинство людей под объектом понимают то, что оформляется в фигурные скобки в коде. Но это лишь часть правды.
От себя добавлю то, что в JavaScript всё является объектами. Функции — это объекты. Массивы — это объекты. И Объекты — это тоже объекты (как бы парадоксально это не звучало). Этого достаточно, чтобы поменять отношение к написанию кода.
Как удалить собственное свойство объекта с строковым ключом JavaScript?
У нас есть объект с тремя свойствами, который мы создали литерально, через фигурные скобки:
let obj = { a:1, b:2, c:3 };
Каждый ключ свойства представляет из себя строковый тип. Мы хотим удалить одно из свойств у этого объекта. Как это сделать?
Для удаления свойства нам нужно воспользоваться оператором delete. Выражение удаления свойства «a» для объекта «obj» будет выглядеть таким образом:
delete obj.a
Как оформляется запись удаления свойства объекта? Сначала мы пишем название оператора, затем ставим пробел и только потом указываем ссылку на нужное свойство объекта.
После этого свойство с ключом «a» и значением «1» будет удалено из объекта «obj«.
Мы успешно удалили собственное свойство у объекта.
Обратите внимание, что выполнение оператора delete вернуло нам логическое значение true. Чтобы понять почему мы получаем ИСТИНУ, нужно смотреть в алгоритм работы самого оператора. Сделать это можно на странице стандарта ECMAScript.
Как удалить собственное свойство объекта с символьным ключом JavaScript?
let sy = Symbol('sy_desc'); let obj = {a:1}; obj[sy] = 2;
Мы создаём примитивное значение (тип Symbol) и складываем его в переменную «sy«. Также мы создаём объект и добавляем в него свойство с символьным ключом.
Теперь пробуем удалить свойство с символьным ключом.
delete obj[sy]
Результат удаления — true
. Свойства больше нет.
Как удалить наследованное свойство объекта JavaScript?
Если мы попытаемся удалить наследованное свойство у потомка (у нужного нам объекта), то оно не будет удалено:
let vasya = {name: 'Вася', type: 'Человек'}; let petya = Object.create(vasya); petya.name = 'Петя'; console.log(petya); delete petya.type; console.log(petya);
Представим, что у нас есть родительский объект Вася и дочерний объект Петя. То есть Петя был создан на основании Васи. Для имитации такого наследования свойств мы будем использовать конструктор класса Object и его метод create().
Выглядеть это будет так:
В этом случае оператор delete не выполнит поставленную перед ним задачу. Свойство «type» будет по-прежнему доступно Пете через прототип Васи. Иными словами Петя по-прежнему знает как дотянуться до свойства, которое не удалилось.
То есть при попытке удалить свойство у ребёнка, мы не удалили его у родителя. Правильно это или нет? Чтобы ответить на этот вопрос нужно владеть гораздо большей информацией по самому языку JavaScript.
В итоге, нам нужно будет удалять свойство у самого Васи:
delete vasya.type; petya.type undefined
По факту, мы уже будем работать с другим объектом.
Теперь наследник не сможет дотянуться до свойства «type«, так как собственного свойства у него нет, а у предков оно было удалено. Не к чему обращаться.
Какое собственное свойство объекта JavaScript нельзя удалить?
В процессе углубленного изучения языка JavaScript начнёт возникать множество профессиональных вопросов. Пытливый ум разработчика рано или поздно задастся вопросом: «Можно ли заблокировать свойство объекта от удаления?» или «Любое ли свойство объекта можно так легко удалить?» или «Почему не удаляется свойство объекта?«.
Давайте разберём этот вопрос на примере Димы:
let dima = {name: 'Дима', type: 'Человек'};
После объявления объекта Димы мы теперь можем приступить к блокировке его собственных свойств от удаления. Как это сделать?
Нам нужно воспользоваться конструктором класса Object и его методом defineProperty(). Этот метод позволяет установить настройки для внутренних дескрипторов свойств (атрибутов) данного объекта. Со всеми возможными дескрипторами свойств можно ознакомиться в таблице «Table 3: Attributes of an Object property«.
Нас будет интересовать дескриптор (атрибут), который называется [[Configurable]]. Данный атрибут может быть как «свойством средства доступа«, а также «свойством данных«.
Объект в JavaScript логически представляет собой набор свойств. Каждое свойство является либо свойством данных, либо свойством доступа:
- Свойство данных связывает значение ключа со значением языка ECMAScript и набором логических атрибутов.
- Свойство средства доступа связывает значение ключа с одной или двумя функциями средства доступа и набором логических атрибутов. Функции доступа используются для хранения или извлечения значения языка ECMAScript, связанного со свойством.
Если мы установим для нужного свойства объекта, его значение дескриптора (атрибута) [[Configurable]] в логическое false, то тогда такое свойство объекта невозможно будет удалить. Устанавливаем значения для двух свойств у нашего объекта Дима.
Object.defineProperty(dima, 'name', {configurable: false}); Object.defineProperty(dima, 'type', {configurable: false});
Вызов метода defineProperty() всегда возвращает объект на который был передан в качестве первого параметра.
Теперь пытаемся осуществить удаление обоих собственных свойств объекта:
delete dima.name; delete dima.type;
В результате мы получаем логическое значение false. Это означает неудачу.
Причём интересен тот факт, что никаких ошибок (исключений) нет и фактически можно не понять в чём дело, если не знаешь о таком понятии как «дескрипторы свойств» у объектов.
Код в строгом режиме и удаление собственного свойства объекта JavaScript
Строгий режим можно объявить через строку «use strict» в основном файле скрипта.
Поведение удаления свойства при «коде в строгом режиме» с атрибутом свойства — {configurable: false}
, приведёт к вызову исключения TypeError (к ошибке).
На этот раз посмотрим на Машу:
"use strict" let masha = {name: 'Маша', type: 'Человек'}; Object.defineProperty(masha, 'name', {configurable: false}); Object.defineProperty(masha, 'type', {configurable: false}); delete masha.name;
Для перехода в строгий режим в консоли браузера нужно использовать директиву «use strict» на первой линии одной строки. Чтобы писать команды ниже директивы, нужно использовать сочетание клавиш «SHIFT + ENTER«.
Как использовать логические ответы оператора delete в функции в JavaScript?
Мы выяснили, что оператор delete может возвращать логическое значение и даже выбрасывать исключение. Это значит, что мы можем писать более информативные функции и логировать некоторые результаты — писать сообщения в журнал.
Наша собственная функция может иметь вид:
// Функция удаляет одно первое свойство объекта
function delprop(obj){
try {
if(delete obj[Object.getOwnPropertyNames(obj)[0]]){
console.log(`Одно свойство удалено`, obj)
return obj
}
else{
console.log(
`Удаление свойства отклонено. Атрибут [[Configurable]] имеет значение: `,
Object.getOwnPropertyDescriptor(obj, Object.getOwnPropertyNames(obj)[0]).configurable
)
return obj
}
} catch (error) {
console.error(`Ошибка удаления свойства объекта`, error)
return obj
}
}
Данная функция пытается удалить любое первое свойство у объекта. Функция использует несколько ветвлений, но каждое из них при любом раскладе возвращает нам переданный объект. То есть свойство может удалиться, а может и нет.
Пример работы:
Мы вызвали функцию с оригинальной Машей, у которой заблокировано удаление свойств. Затем вызвали её с каким-то Петей и свойство удалилось.
Как удалить свойство глобального объекта в JavaScript?
Прежде всего нужно знать, каким образом можно создать свойство у глобального объекта:
- Его можно создать через присвоение значения для идентификатора привязки на самом верхнем уровне видимости в глобальном блоке .
- Его можно создать через объявление функции при помощи ключевого слова
function
- Его можно создать при помощи оператора создания идентификатора привязки — через
var
.
Давайте рассмотрим примеры.
Пример № 1 — только идентификатор привязки
window.aaaa
undefined
aaaa = `10`
'10'
window.aaaa
'10'
Скриншот операций:
Теперь у глобального объекта window появилось свойство с ключом «aaaa«.
Пример № 2 — именованная функция через слово function
window.bbbb undefined function bbbb(b){return b} undefined window.bbbb ƒ bbbb(b){return b}
Скриншот операций:
Пример № 3 — идентификатор привязки через слово var
window.abab undefined var abab = `555` undefined window.abab '555'
Скриншот операций:
Удаление свойства у глобального объекта
Теперь, когда у нас имеются новые три свойства у глобального объекта, мы можем попытаться их удалить.
delete window.aaaa; delete window.bbbb; delete window.abab;
Что из этого получится?
По итогу мы смогли удалить только одно свойство, которое было написано в виде идентификатора привязки без какого либо из ключевых слов языка ECMAScript.
Слова function
и var
имеют большую силу. Созданные с их помощью ключи глобального объекта нельзя удалить оператором delete
. Объявленные имена ключей на верхнем уровне навсегда помещаются в отдельные свойства глобального объекта на весь период жизни среды выполнения кода.
Давайте посмотрим на атрибуты свойств глобального объекта, которые мы не смогли удалить.
Object.getOwnPropertyDescriptor(window, 'bbbb'); Object.getOwnPropertyDescriptor(window, 'abab'); Object.getOwnPropertyDescriptor(window, 'aaaa');
Скриншот операций:
Причина невозможности удаления этих свойств та же, что мы рассматривали ранее. Атрибут «configurable» имеет значение false. Это значит, что изменить свойство теперь невозможно.
Как удалить свойство конструктора класса в JavaScript?
В JavaScript наследование свойств (в том числе методов) осуществляется от объекта к объекту. При объявлении класса, мы по сути создаём новый вид объекта. Так вот у этого класса могут быть собственные свойства конструктора, а могут быть собственные свойства прототипа (для будущих экземпляров). Я называю это «свойствами конструктора», потому что они не наследуются экземплярами — так проще понять идею. Эта терминология используется самим стандартом ECMAScript. По сути это просто статичные свойства самого класса, которые не наследуются экземплярами.
Так вот идея заключается в том, что любое такое свойство можно также удалить, как и у обычного объекта.
class Tap{ constructor(){ this.a = 10; this.b = 2; } static mult(o){return o?.a * o?.b} }
Давайте создадим новый экземпляр класса Tap и передадим его в статичный метод конструктора класса.
Tap.mult(new Tap)
В ответ мы успешно получаем число 20. Умножение прошло успешно и метод mult()
работает в конструкторе класса.
Теперь смотрим на атрибуты свойств самого конструктора класса:
Object.getOwnPropertyDescriptors(Tap)
И мы видим, что у свойства «mult
» стоит атрибут «configurable
» в значении «true
«.
Атрибут configurable в значении true у статичного свойства конструктора класса — JavaScript. Это значит, что такое свойство можно удалить оператором delete
.
delete Tap.mult; true
С этого момента свойство конструктора более не доступно в классе. Можно сказать, что мы разрушили работу приложения. С этим нужно быть осторожнее.
Вы можете удалить свойство конструктора не только у своего класса, но и у стандартных классов языка JavaScript.
delete Array.from
После этого свойство from
не будет существовать у конструктора Array.
Как удалить свойство прототипа класса в JavaScript?
По аналогии со свойством конструктора делаем удаление свойства прототипа класса.
class Lap{ constructor(){ this.a = 10; this.b = 2; } sum(){return this.a + this.b} }
Проверяем, что наследованный метод доступен экземпляру
(new Lap).sum() 12
Метод работает для экземпляра. Теперь производим удаление:
delete Lap.prototype.sum true
В ответ нам возвращается true
— значит свойство удалено.
Информационные ссылки
Стандарт ECMAScript — https://tc39.es/ecma262/multipage/
Стандарт ECMAScript — Раздел «13.5 Unary Operators» — https://tc39.es/ecma262/#sec-unary-operators
Стандарт ECMAScript — Раздел «13.5.1 The delete Operator» — https://tc39.es/ecma262/#sec-delete-operator