-
Notifications
You must be signed in to change notification settings - Fork 187
Description
What is the issue with the Web IDL Standard?
[[Set]] operation for legacy platform objects has a surprising behavior from JavaScript point of view.
TL;DR;: When a legacy platform object (P) with indexed and named properties set as a prototype of some other object (O) then one can't add indexed properties to O that are "shadowed" by non-writable indexed properties in P (same as in JavaScript), however it's allowed to add named properties to O that are "shadowed" by non-writable named properties in P (surprise!).
This issue is about Chrome not following the existing Web IDL spec while we think that there's a bug in the spec that should be fixed.
It would be nice if the Web IDL spec would be more in line with the JavaScript spec.
Assume the following setup:
var p = {};
Object.defineProperty(p, "x", {writable:false});
Object.defineProperty(p, "0", {writable:false});
var obj = Object.create(p);
obj.x = 42; // (1) rejected, as expected
obj[0] = 42; // (2) rejected, as expected
According to the JavaScript spec, [[Set]] operation (1,2) should not create a property since there's a non-writable property with the same name in the prototype chain.
However, this is not the case if the prototype is a legacy platform object exposing non-writable properties (such as HTMLCollection or NamedNodeMap, see examples below).
Moreover there's an asymmetry between readonly named and indexed properties in the prototype chain: stores to the former (3,5) succeeds while stores to the latter (4,6) are rejected.
This behavior is defined by the following step of [[Set]] operation for legacy platform objects:
2. Let ownDesc be ? LegacyPlatformObjectGetOwnProperty(O, P, true)."
Note that LegacyPlatformObjectGetOwnProperty operation is called with ignoreNamedProps set to true which hides the supported property names and makes the [[Set]] behave like there are no non-writable properties while [[GetOwnProperty]] operation for legacy platform objects states that there are non-writable properties.
The fix would be to pass false as ignoreNamedProps and maybe even drop this parameter completely.
Can you fix this please?
Example with HTMLCollection:
var element = document.createElement("p");
element.id = "named";
document.body.appendChild(element);
var p = document.getElementsByTagName("p"); // HTMLCollection
var obj = Object.create(p);
console.log(Object.getOwnPropertyDescriptor(p, "named").writable); // false
console.log(Object.getOwnPropertyDescriptor(p, "0").writable); // false
obj.named = 42; // (3) unexpectedly succeeds
obj[0] = 42; // (4) rejected, as expected
(taken from this Web platform test which exposed the issue: https://staging.wpt.fyi/results/dom/collections/HTMLCollection-as-prototype.html?label=master&label=experimental&product=chrome&product=firefox&product=safari&aligned)
Example with NamedNodeMap:
var element = document.createElement("p");
element.id = "foo";
var p = element.attributes;
var obj = Object.create(p);
console.log(Object.getOwnPropertyDescriptor(p, "id").writable); // false
console.log(Object.getOwnPropertyDescriptor(p, "0").writable); // false
obj.id = 42; // (5) unexpectedly succeeds
obj[0] = 42; // (6) rejected, as expected