Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does browser get Symbol.unscopables twice?

with(new Proxy({}, {
  has() { return true },
  get(obj, key, proxy) { return console.log(String(key)) } })
) {
  a--
}

Output in Chrome:

Symbol(Symbol.unscopables)
a
Symbol(Symbol.unscopables)

Output in Firefox:

Symbol(Symbol.unscopables)
Symbol(Symbol.unscopables)
a

As I understand, one getting is related to reading value and the other - to assigning.

It's logical that a-- should write to the same place where a was read from. No, it's not.

But getting value for Symbol.unscopables twice hints us, that it's possible to pass one object for reading and the other one for writing.

Is it really meant to work like that? What does specification say?

Actually, it almost works in Chrome and FF - it's possible to read from one obect and to write into the other one, but it leads to different results:

Update: Safari 10 reads it only once.

var a, b, flag = true

with (a = { x: 7 })
  with (b = { x: 4, get [Symbol.unscopables]() { return { x: flag=!flag } } })
    x++

                 // Chrome   FF       Safari   Edge
console.log(a)   // {x:5}    {x:7}    {x:7}    {x:5}
console.log(b)   // {x:4}    {x:8}    {x:5}    {x:4}

PS: Same question in Russian

like image 832
Qwertiy Avatar asked Nov 14 '16 18:11

Qwertiy


1 Answers

Per spec, @@unscopables should be read only once for "x++", a far as I can tell. See details in https://mail.mozilla.org/pipermail/es-discuss/2017-February/047725.html

So both Chrome and Firefox are buggy here. Safari gets this right.

See also https://bugzilla.mozilla.org/show_bug.cgi?id=1341061 and https://bugs.chromium.org/p/v8/issues/detail?id=5992

like image 138
Boris Zbarsky Avatar answered Sep 30 '22 19:09

Boris Zbarsky