Reputation:
function foobar() {}
console.log(typeof window.foobar); // "function"
console.log(typeof window.alert); // "function"
delete window.foobar;
delete window.alert;
console.log(typeof window.foobar); // "function"
console.log(typeof window.alert); // "undefined"
console.log(window.hasOwnProperty('foobar')); // true
console.log(window.hasOwnProperty('alert')); // false
Can somebody please explain, how this is possible?
Why can't I simply delete the foobar
property of the window object?
Why is a custom global function like foobar
protected against delete
operator, but a built-in global function like alert
not?
Upvotes: 3
Views: 209
Reputation: 288480
Global variables are not configurable:
Object.getOwnPropertyDescriptor(window, 'foobar').configurable; // false
That's because according to Static Semantics: TopLevelVarDeclaredNames, function declarations are like var
declarations:
At the top level of a function or script, inner function declarations are treated like var declarations.
And Runtime Semantics: GlobalDeclarationInstantiation declares them as non-configurable:
- For each production f in functionsToInitialize, do
- Let status be envRec.CreateGlobalFunctionBinding(fn, fo, false).
CreateGlobalFunctionBinding (N, V, D) uses the argument false as the configurability of the property:
- Let desc be the PropertyDescriptor{[[Value]]:V, [[Writable]]: true, [[Enumerable]]: true , [[Configurable]]: D}.
Therefore, the [[Delete]] internal method, used by the delete
operator, won't succeed:
If desc.[[Configurable]] is true, then
- Remove the own property with name P from O.
- Return true.
Return false.
That's why you should use strict mode. Otherwise some problems are silently ignored.
delete window.foobar; // false (in sloppy mode)
delete window.foobar; // TypeError (in strict mode)
You can delete the native alert
because it's configurable.
That method is defined in the HTML spec as an IDL method:
[Global] /*sealed*/ interface Window : EventTarget { // ... void alert(optional DOMString message = ""); };
According to WebIDL, exposed operations should be configurable if they don't are unforgeable:
The property has attributes { [[Writable]]: B, [[Enumerable]]: true, [[Configurable]]: B }, where B is false if the operation is unforgeable on the interface, and true otherwise.
Object.getOwnPropertyDescriptor(window, 'alert').configurable; // true
If you want to be able to delete the function, assign it as a property instead of using a function declaration:
window.foobar = function() {};
Object.getOwnPropertyDescriptor(window, 'foobar').configurable; // true
delete window.foobar; // true
That's because when you create a property via a property assignment, it's configurable. From CreateDataProperty, used by the [[Set]] internal method,
- Let newDesc be the PropertyDescriptor{[[Value]]: V, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}.
Upvotes: 2