7

When working with JavaScript ES6 Proxies, the set property trap for array.length does not fire when assigning array indexes directly.

For example:

const proxy = new Proxy([], {
    set: function(obj, name, value) {
        console.log(`set: ${name}`);
        obj[name] = value;
        return true;
    }
});
proxy.push(0);
proxy[1] = 1;

Chrome 51 and Firefox 47 outputs:

set: 0  
set: length  
set: 1

While I would expect:

set: 0  
set: length  
set: 1  
set: length 

Is this per spec? I couldn't find any information on this.

sdgluck
  • 24,894
  • 8
  • 75
  • 90
kgreen
  • 518
  • 6
  • 13

1 Answers1

2

There is no need to explicitly set the length property when a value is assigned to an index. The reason why it's set with push is indeed defined in the specification:

  1. Repeat, while items is not empty

    a. Remove the first element from items and let E be the value of the element.

    b. Let setStatus be Set(O, ToString(len), E, true).

    c. ReturnIfAbrupt(setStatus).

    d. Let len be len+1.

  2. Let setStatus be Set(O, "length", len, true).

Basically: If an error happens then set the correct length in case the array already has been expanded.

a better oliver
  • 26,330
  • 2
  • 58
  • 66
  • 1
    This is a very good question but i don't see how exactly you answer the question by **There is no need to explicitly set the** `length` **property when a value is assigned to an index.** When I make `proxy[99] = 100` the `length` property never gets trapped by `set` but magically gets trapped by `get` returning 100 when accessed by `console.log(proxy.length)`. So I suppose 100 is not a calculated but an assigned value to the `length` property. When I do a `.pop()` afterwards `length` gets trapped by `set` and updates to 99. How did the `length` property become 100 in the first place. – Redu Apr 15 '18 at 01:09
  • 2
    @Redu The `.length` does get updated *behind* the scenes [when assigning to an index](http://www.ecma-international.org/ecma-262/6.0/#sec-array-exotic-objects-defineownproperty-p-desc). You could also consider every instance to have a magical getter/setter `.length` that always knows the number of items (and holes). Regardless, this update cannot be trapped by a proxy, because it happens on the array instance (proxy target) itself - unlike the `push` or `pop` methods, which do an explicit assignment on the (proxy) object that they were invoked on. – Bergi Apr 15 '18 at 10:17
  • @Bergi Thanks for your attention. I have even tried the `defineProperty` trap hoping direct value assignment at index might somehow redefine the `length` property alas no way. Then i suppose another way is to check like `(prop === "length" || target.length <= prop)` in the `set` trap to catch by index insertions to the end of the array. Is this reasonable..? – Redu Apr 15 '18 at 13:54
  • 1
    @Redu Yes, that sounds reasonable (but cast `prop` to an integer, and use the same algorithm as in the spec section I linked). – Bergi Apr 15 '18 at 14:08