What is the purpose of the delete operator in Javascript?
The behaviour of the delete operator seems very complicated and there are many misunderstandings about what it actually does. To me, it seems that reassigning something to undefined will more reliably do what you would expect. I’ve never seen the delete keyword in Javascript actually used in non-example code and I am wondering if it is particularly useful for anything. Does delete have any purpose that cannot be acheived by reassignment to undefined ? Is it used at all in any of the famous libraries (e.g. jQuery, dojo, backbone, etc)?
The behavior of delete isn’t complicated at all. But it really shouldn’t have been called delete . JavaScript being syntactically similar to C++, using an operator C++ has but doing something completely different with it was a bit of an oops and has caused all of this confusion. (If it were called remove , I bet people wouldn’t be nearly so confused.)
6 Answers 6
Does delete have any purpose that cannot be acheived by reassignment to undefined?
Yes. If you want to unmask a property from a prototype or cause in , hasOwnProperty , and for (. in. ) to not record the property as existing then delete is appropriate.
let set = <>; set._x = true; alert('_x' in set); // true set._x = undefined; alert('_x' in set); // true delete set._x; alert('_x' in set); // false
EDIT: As T.J. Crowder explains:
The purpose of the delete operator is to completely remove a property from an object, whereas setting a property to undefined just sets the property to undefined .
This matters in its own right, but it also matters when you’re using inheritance, because if O derives from P
let P = < prop: 42 >; let O = Object.create(P); // P is O's prototype.
when you retrieve O.prop , you get the value of prop from O if O has a property with that name (even if its value is undefined), but if O doesn’t have the property at all, then the value will be retrieved from P.prop instead.
console.log(O.prop); // "42" since O doesn't have its own prop, but P does. O.prop = undefined; console.log(O.prop); // "undefined" since O has its own prop. delete O.prop; console.log(O.prop); // "42" since the delete "unmasked" P.prop.
As Mike Samuel points out in his answer, one of the most common usages of delete is when you are treating an object as a «property bag» that associates names with values. There is logically a difference between «this name is now mapped to some bogus value» and «this name is not mapped at all». «delete» achieves the latter.
That’s all reasonably well understood. I thought I might add an interesting historical note regarding the JScript 1.0 through 5.0 engines.
In those original Microsoft implementations of JScript we used OLE Automation-style IDispatch objects to implement expando objects. IDispatch of course works by associating a name with a «dispatch id», which is simply an integer. To invoke dynamically, first you ask the dispatch object to give you the dispatch ID associated with a name, and then you say «now invoke the method associated with this ID, given these arguments».
That’s all well and good. But one of the requirements of the IDispatch contract is that the mapping from name to dispatch ID be stable over the entire lifetime of the object. So if someone says «add property Foo to this object», then we might decide that property Foo is associated with dispatch identifier 0x1234 in that object. From that moment on, every time the object is asked for the dispatch identifier of «Foo», it must give back 0x1234, even if Foo is deleted and subsequently added again. This permits a caller to maintain their own fast cache of name/dispid pairs rather than always having to ask the object on every invocation.
The practical upshot of that is that «delete» does not in any way lessen the memory burden on the object in that implementation! When you delete a property (in the original implementation) we must add a bit to the object marking that dispatch identifier as deleted, but we must retain all the information about the name/id pairing in case that name ever comes back. Adding a huge number of properties to an object and then deleting all of them does not shrink the object in memory.
The JScript engine has of course been completely rewritten since my time (except for, I believe, the parser and lexer) so I have no idea if the engine still has this unusual quirk. It would be interesting to find out.
Стоит ли удалять событие с элемента, перед его удалением? [дубликат]
В одном видео слышал, что удаляя элемент в котором есть событие мы не удаляем сам обработчик. Другими словами обработчик события продолжает работать, не смотря, что элемента нет. Хотел бы получить подтверждение или опровержение этим словам. Спасибо!
1 ответ 1
удаляя элемент в котором есть событие мы не удаляем сам обработчик
Да, при удалении элемента из dom-дерева все обработчики на нём остаются:
document.querySelector('button').addEventListener('click', function (e) < e.target.remove(); setTimeout(function () < document.body.appendChild(e.target) >, 500); >);
Ну как я понимаю событие может находиться в памяти, но не выполняться
document.querySelector('button').addEventListener('click', function(e) < if (e.target.parentElement) < e.target.remove(); setTimeout(function() < e.target.click() >, 500); > else < document.body.appendChild(e.target); >>);
Стоит ли удалять событие с элемента, перед его удалением?
В большинстве случаев нет. Если на элемент нет других ссылок, то он всё равно будет собран сборщиком мусора вместе с обработчиком:
~function add() < var btn = document.createElement('button'); btn.textContent = "Click me"; btn.addEventListener('click', function (e) < btn.remove(); setTimeout(add, 500); >); document.body.appendChild(btn); >();
Как видно в профайлере, выживших объектов от кликов кроме последнего нет:
Впрочем, в IE8 действительно была проблема с утечками в некоторых подобных случаях.
Однако, если обработчик или элемент каким-то образом удерживается внешним кодом, то они будут сохранены до тех пор, пока это удерживание не исчезнет. Если есть какие-либо подписки на более долгоживущие объекты или события, то отписываться надо.
Поэтому при использовании фреймвёрка, имеющего жизненный цикл компонента, рекомендуется при уничтожении компонента отписаться от всего, на что подписался руками.
Как правильно реализовать модальное подтверждением удаления элементов?
Задача с подтверждением удаления в модалке. Однако, проблема, если по кликать по всем элементам и нажать на кнопку «отмену», а потом на каком-то одном элементе нажать кнопку «удалить» то удаляются все элементы.
Не пойму в чем дело, разъясните пожалуйста.
Действительно, что-то тут не так.
Для начала поставьте console.log в определенном месте своего кода:
document.querySelector('.list').addEventListener('click', (event) => < const target = event.target if (target.classList.contains('delete')) < const task = document.querySelector(`[data-id="$"]`) // Посмотрим что будет выводиться в консоль? console.log(target.dataset.id) deleteTask(task) > >)
И попробуйте проделать все описанные в вопросе действия, после чего посмотрите сколько идентификаторов текущего «таска» — выводятся в консоль. Что-то тут не так. Разобраться конечно в этом можно, но нужно разбираться и тратить время.
Ну, а вообще, если как-то по простому решить проблему + немного подчистить код, то можно сделать например вот так:
const modal = document.querySelector(".modal"); const listbox = document.querySelector(".list"); const modalCancelButton = modal.querySelector(".cancel"); const modalConfirmButton = modal.querySelector(".confirm"); let currentTaskID = null; listbox.addEventListener("click", (< target: t >) => < if (t.classList.contains("delete")) < currentTaskID = t.dataset.delete; modal.classList.remove("hidden"); >>); modalCancelButton.addEventListener("click", () => < modal.classList.add("hidden"); currentTaskID = null; >); modalConfirmButton.addEventListener("click", () => < modal.classList.add("hidden"); deleteTask(currentTaskID); >); const deleteTask = id && listbox.querySelector(`[data-id="$"]`).remove();