JavaScript | Как удалить свойство объекта?

JavaScript | Как удалить свойство объекта?

Оглавление

  1. Вступление к публикации
  2. Как удалить собственное свойство объекта с строковым ключом JavaScript?
  3. Как удалить собственное свойство объекта с символьным ключом JavaScript?
  4. Как удалить наследованное свойство объекта JavaScript?
  5. Какое собственное свойство объекта JavaScript нельзя удалить?
  6. Код в строгом режиме и удаление собственного свойства объекта JavaScript
  7. Как использовать логические ответы оператора delete в функции в JavaScript?
  8. Как удалить свойство глобального объекта в JavaScript?
  9. Как удалить свойство конструктора класса в JavaScript?
  10. Как удалить свойство прототипа класса в 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 - JavaScript
Удалили свойство объекта оператором delete — JavaScript

Мы успешно удалили собственное свойство у объекта.

Обратите внимание, что выполнение оператора delete вернуло нам логическое значение true. Чтобы понять почему мы получаем ИСТИНУ, нужно смотреть в алгоритм работы самого оператора. Сделать это можно на странице стандарта ECMAScript.

Логика работы оператора delete по стандарту ECMAScript от 05 марта 2023 года
Логика работы оператора delete по стандарту ECMAScript от 05 марта 2023 года

 

Как удалить собственное свойство объекта с символьным ключом JavaScript?

let sy = Symbol('sy_desc');
let obj = {a:1};
obj[sy] = 2;

Мы создаём примитивное значение (тип Symbol) и складываем его в переменную «sy«. Также мы создаём объект и добавляем в него свойство с символьным ключом.

Теперь пробуем удалить свойство с символьным ключом.

delete obj[sy]

Результат удаления — true. Свойства больше нет.

Удалили свойство с символьным ключом - JavaScript
Удалили свойство с символьным ключом — JavaScript

 

Как удалить наследованное свойство объекта JavaScript?

Если мы попытаемся удалить наследованное свойство у потомка (у нужного нам объекта), то оно не будет удалено:

let vasya = {name: 'Вася', type: 'Человек'};
let petya = Object.create(vasya);
petya.name = 'Петя';
console.log(petya);

delete petya.type;
console.log(petya);

Представим, что у нас есть родительский объект Вася и дочерний объект Петя. То есть Петя был создан на основании Васи. Для имитации такого наследования свойств мы будем использовать конструктор класса Object и его метод create().

Выглядеть это будет так:

Неудачная попытка удаления наследованного свойства объекта - JavaScript
Неудачная попытка удаления наследованного свойства объекта — JavaScript

 

В этом случае оператор delete не выполнит поставленную перед ним задачу. Свойство «type» будет по-прежнему доступно Пете через прототип Васи. Иными словами Петя по-прежнему знает как дотянуться до свойства, которое не удалилось.

Не удалили унаследованное свойство у объекта - JavaScript
Не удалили унаследованное свойство у объекта — JavaScript

То есть при попытке удалить свойство у ребёнка, мы не удалили его у родителя. Правильно это или нет? Чтобы ответить на этот вопрос нужно владеть гораздо большей информацией по самому языку JavaScript.

В итоге, нам нужно будет удалять свойство у самого Васи:

delete vasya.type;

petya.type
undefined

По факту, мы уже будем работать с другим объектом.

Удалили свойство объекта у предка. Теперь оно недоступно для потомка - JavaScript
Удалили свойство объекта у предка. Теперь оно недоступно для потомка — JavaScript

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

Установили атрибут [[Configurable]] свойств name и type в значение false - JavaScript
Установили атрибут [[Configurable]] свойств name и type в значение false — JavaScript
Теперь пытаемся осуществить удаление обоих собственных свойств объекта:

delete dima.name;
delete dima.type;

В результате мы получаем логическое значение false. Это означает неудачу.

Удаление собственных свойств объекта завершилось неудачей - JavaScript
Удаление собственных свойств объекта завершилось неудачей — JavaScript

Причём интересен тот факт, что никаких ошибок (исключений) нет и фактически можно не понять в чём дело, если не знаешь о таком понятии как «дескрипторы свойств» у объектов.

 

Код в строгом режиме и удаление собственного свойства объекта 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«.

Ошибка TypeError при попытке удаления собственного свойства у объекта в строгом режиме в JavaScript
Ошибка TypeError при попытке удаления собственного свойства у объекта в строгом режиме в JavaScript

 

Как использовать логические ответы оператора 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

    }

}

Данная функция пытается удалить любое первое свойство у объекта. Функция использует несколько ветвлений, но каждое из них при любом раскладе возвращает нам переданный объект. То есть свойство может удалиться, а может и нет.

Пример работы:

Функция использующая оператор delete в уловном операторе if в JavaScript
Функция использующая оператор delete в уловном операторе if в JavaScript

Мы вызвали функцию с оригинальной Машей, у которой заблокировано удаление свойств. Затем вызвали её с каким-то Петей и свойство удалилось.

 

 

Как удалить свойство глобального объекта в JavaScript?

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

  1. Его можно создать через присвоение значения для идентификатора привязки на самом верхнем уровне видимости в глобальном блоке .
  2. Его можно создать через объявление функции при помощи ключевого слова function
  3. Его можно создать при помощи оператора создания идентификатора привязки — через var.

Давайте рассмотрим примеры.

 

Пример № 1 — только идентификатор привязки

window.aaaa
undefined

aaaa = `10`
'10'

window.aaaa
'10'

Скриншот операций:

Создали свойство для глобального объекта через присвоение значения для несуществующего идентификатора привязки - JavaScript
Создали свойство для глобального объекта через присвоение значения для несуществующего идентификатора привязки — JavaScript

Теперь у глобального объекта window появилось свойство с ключом «aaaa«.

 

Пример № 2 — именованная функция через слово function

window.bbbb
undefined

function bbbb(b){return b}
undefined

window.bbbb
ƒ bbbb(b){return b}

Скриншот операций:

Создали свойство для глобального объекта через создание именованной функции ключевым словом function - JavaScript
Создали свойство для глобального объекта через создание именованной функции ключевым словом function — JavaScript

 

Пример № 3 — идентификатор привязки через слово var

window.abab
undefined

var abab = `555`
undefined

window.abab
'555'

Скриншот операций:

Создали свойство для глобального объекта через ключевое слово var и идентификатор привязки - JavaScript
Создали свойство для глобального объекта через ключевое слово var и идентификатор привязки — JavaScript

 

Удаление свойства у глобального объекта

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

delete window.aaaa;
delete window.bbbb;
delete window.abab;

Что из этого получится?

Частично удалили свойства у глобального объекта в JavaScript
Частично удалили свойства у глобального объекта в JavaScript

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

Слова function и var имеют большую силу. Созданные с их помощью ключи глобального объекта нельзя удалить оператором delete. Объявленные имена ключей на верхнем уровне навсегда помещаются в отдельные свойства глобального объекта на весь период жизни среды выполнения кода.

Давайте посмотрим на атрибуты свойств глобального объекта, которые мы не смогли удалить.

Object.getOwnPropertyDescriptor(window, 'bbbb');
Object.getOwnPropertyDescriptor(window, 'abab');
Object.getOwnPropertyDescriptor(window, 'aaaa');

Скриншот операций:

Значения в атрибутах неудаляемых свойств глобального объекта - объявленных через function и var - JavaScript
Значения в атрибутах неудаляемых свойств глобального объекта — объявленных через function и var — JavaScript

Причина невозможности удаления этих свойств та же, что мы рассматривали ранее. Атрибут «configurable» имеет значение false. Это значит, что изменить свойство теперь невозможно.

 

Как удалить свойство конструктора класса в JavaScript?

В JavaScript наследование свойств (в том числе методов) осуществляется от объекта к объекту. При объявлении класса, мы по сути создаём новый вид объекта. Так вот у этого класса могут быть собственные свойства конструктора, а могут быть собственные свойства прототипа (для будущих экземпляров). Я называю это «свойствами конструктора», потому что они не наследуются экземплярами — так проще понять идею. Эта терминология используется самим стандартом ECMAScript. По сути это просто статичные свойства самого класса, которые не наследуются экземплярами.

Так вот идея заключается в том, что любое такое свойство можно также удалить, как и у обычного объекта.

class Tap{
   constructor(){
      this.a = 10;
      this.b = 2;
   }
   static mult(o){return o?.a * o?.b}
}
prototype ссылается на сам объект класса - метод mult принадлежит constructor - JavaScript
prototype ссылается на сам объект класса — метод mult принадлежит constructor — JavaScript

Давайте создадим новый экземпляр класса Tap и передадим его в статичный метод конструктора класса.

Tap.mult(new Tap)

В ответ мы успешно получаем число 20. Умножение прошло успешно и метод mult() работает в конструкторе класса.

Статичное свойство класса доступно для выполнения в JavaScript
Статичное свойство класса доступно для выполнения в JavaScript

Теперь смотрим на атрибуты свойств самого конструктора класса:

Object.getOwnPropertyDescriptors(Tap)

И мы видим, что у свойства «mult» стоит атрибут «configurable» в значении «true«. Атрибут configurable в значении true у статичного свойства конструктора класса - JavaScript

Атрибут configurable в значении true у статичного свойства конструктора класса — JavaScript. Это значит, что такое свойство можно удалить оператором delete.

delete Tap.mult;
true
Удалили свойство конструктора класса в JavaScript - теперь ошибка при вызове
Удалили свойство конструктора класса в JavaScript — теперь ошибка при вызове

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

Вы можете удалить свойство конструктора не только у своего класса, но и у стандартных классов языка JavaScript.

delete Array.from

После этого свойство from не будет существовать у конструктора Array.

Удалили свойство from из конструктора класса Array - JavaScript
Удалили свойство from из конструктора класса Array — JavaScript

 

Как удалить свойство прототипа класса в 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 — значит свойство удалено.

Удалили свойство прототипа класса в JavaScript - теперь ошибка при вызове
Удалили свойство прототипа класса в JavaScript — теперь ошибка при вызове

 

Информационные ссылки

Стандарт ECMAScripthttps://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