[whatwg] Overriding functions in DOM Storage

Cameron McCormack cam at mcc.id.au
Sun Jun 21 02:13:51 PDT 2009

Jeremy Orlow:
> > What is the behavior of the following supposed to be?
> >
> > window.sessionStorage.removeItem = function(x) { alert("Wait, this works?"); };
> > window.sessionStorage.removeItem('blah');
> > alert(typeof window.sessionStorage.removeItem);

Maciej Stachowiak:
> DOM methods are normally overridable. That would make the Safari  
> behavior correct. If we want the behavior to be different in this case, 
> then the spec should spell that out. Perhaps part of the issue here is 
> that the definition of the [NameSetter] extended attribute in Web IDL 
> doesn't make clear whether or not name setter behavior takes precedence 
> over setting existing predefined attributes or methods.

The behaviour according to how the Web Storage and Web IDL specs are
currently written (I’ve just done some cleanup of this) is the Safari

  * window.sessionStorage starts off with no indexed properties and
    no named properties.

  * window.sessionStorage.[[Put]]("removeItem", function…) is called.

  * In http://dev.w3.org/2006/webapi/WebIDL/#put, none of the if
    statements in steps 1–6 will be entered, since while there is
    a [NameCreator], there already exists a property named "removeItem"
    which is not a corresponding named property.

  * So the sub-steps of step 7 are run, and a regular property is
    created on the Storage object.

  * Evaluating window.sessionStorage.removeItem calls

  * In http://dev.w3.org/2006/webapi/WebIDL/#get, steps 1–3 in the
    [[Get]] algorithm all evaluate to false, so the value of the regular
    "removeItem" property that was just created is returned.

  * The anonymous function is called, the alert(“Wait, this works?”)

  * The [[Get]] runs again and returns the same value, and the typeof
    evaluates to "function".

Another edge case:

  // Save it away.
  var f = Storage.prototype.removeItem;

  // Just a normal property deletion...
  delete Storage.prototype.removeItem;

  // window.sessionStorage doesn’t have a "removeItem" property on it or
  // in its prototype chain, so the name creator behaviour is invoked,
  // resulting in an item in the storage list being created.
  window.sessionStorage.removeItem = function() { alert("hi") };

  // Since an item in the storage list just became available, the rules
  // in
  // http://dev.w3.org/2006/webapi/WebIDL/#indexed-and-named-properties
  // come in to force, resulting in a corresponding indexed property "0"
  // and a corresponding named property "removeItem" being created on
  // window.sessionStorage.

  // Put the original removeItem back.  The corresponding named property
  // on window.sessionStorage remains.
  Storage.prototype.removeItem = f;

  // window.sessionStorage[[Get]]("removeItem") invokes the named getter
  // behaviour, which according to Web Storage will return the stored
  // value, so this statement alerts "hi".

  // This removes the item from the storage list, since the
  // [[Get]]("clear") call returns the property from the Storage
  // prototype (because the property exists in the prototype chain,
  // so the named getter behaviour isn’t invoked).

  // Because the storage list changed, "0" is no longer the index of
  // of a supported indexed property, and "removeItem" is no longer the
  // name of a supported named property.  So the rules in 
  // http://dev.w3.org/2006/webapi/WebIDL/#indexed-and-named-properties
  // state that the corresponding indexed property
  // window.sessionStorage[0] and the corresponding named property
  // window.sessionStorage.removeItem are removed.

  // This evaluates to the real removeItem function again.

A different edge case:

  // Assume that the session storage object already has an entry with
  // name "removeItem" and value 123 in its storage list when the page
  // loads.  A corresponding named property won’t be created because of
  // the rules in
  // http://dev.w3.org/2006/webapi/WebIDL/#indexed-and-named-properties
  // but "removeItem" still is the name of a supported named property.

  // This evaluates to the same as Storage.prototype.removeItem, because
  // the [NameGetter] annotation doesn’t have the OverrideBuiltins
  // argument, and there is no corresponding named property called
  // "removeItem" on window.sessionStorage.

  // Delete from the prototype.
  delete Storage.prototype.removeItem;

  // Now, the conditions in
  // http://dev.w3.org/2006/webapi/WebIDL/#indexed-and-named-properties
  // are triggered, since "removeItem" is the name of a supported named
  // property and there isn’t a property named "removeItem" on
  // window.sessionStorage or its prototype chain, and "removeItem"
  // isn’t an array index property name.  So as soon as the property is
  // deleted from Storage.prototype above, a corresponding named
  // property "removeItem" (and a corresponding indexed property "0")
  // is created on window.sessionStorage.

  // This evaluates to 123.

  // This calls
  // window.sessionStorage.removeItem.[[Delete]]("removeItem"), which
  // invokes the name deleter behaviour because "removeItem" is the name
  // of a corresponding named property.
  delete window.sessionStorage.removeItem;

Cameron McCormack ≝ http://mcc.id.au/

More information about the whatwg mailing list