user6576367
user6576367

Reputation:

Weird behaviour with window object when removing property from it

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

Answers (1)

Oriol
Oriol

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:

  1. For each production f in functionsToInitialize, do
    1. Let status be envRec.CreateGlobalFunctionBinding(fn, fo, false).

CreateGlobalFunctionBinding (N, V, D) uses the argument false as the configurability of the property:

    1. 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:

  1. If desc.[[Configurable]] is true, then

    1. Remove the own property with name P from O.
    2. Return true.
  2. 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,

  1. Let newDesc be the PropertyDescriptor{[[Value]]: V, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}.

Upvotes: 2

Related Questions