Search code examples
javascriptgoogle-chromefirefoxpolyfillscore-js

What is the problem with array.push implementation in chrome based browsers?


I had thought array.push was a very basic function so I was surprised to see Babel polyfill array.push for Chromium browsers. I checked the MDN document for array.push and saw that it says:

corejs-array.push

I checked core-js document and its implementation but it is unclear how it "fixes" the problem in Chromium browsers.

So what is the problem? And how are Firefox/Safari implementations different from Chromium's implementation? Checking the following output for reference.

The corejs3 polyfill added the following polyfills:
  es.object.to-string { "ie":"10" }
  es.promise { "ie":"10" }
  web.dom-collections.for-each { "ie":"10" }
  es.array.from { "ie":"10" }
  es.string.iterator { "ie":"10" }
  es.array.push { "chrome":"115", "edge":"110", "ie":"10" } //Only for Chromium, not for FF & Safari
  ...

BTW, to let babel not polyfill for array.push I have to add exclude to babel setting like this

     "useBuiltIns": "usage",
     "shippedProposals": true,
     "corejs": "3.33"
     "exclude": ["es.array.push"]

Solution

  • So what is the problem?

    Some engines (in particular V8) are failing the Array/prototype/push /set-length-zero-array-length-is-non-writable test case of the test262 suite. That's a bug, and core-js provides a workaround.

    Now what does the test check for? A really obscure edge case:

    • if you take an array and make its .length non-writable
    • then proceed to call .push(), which would attempt to write the .length and fail
    • but actually do not pass any arguments, so the .length doesn't actually change
    • and if you still expect this to throw an exception

    …then V8 lets you down: it doesn't throw the exception that it should throw but simply returns 0 (the length of the unchanged empty array).

    Also there appears to be a second problem, with really old Firefox versions, from before the feature of non-writable .length properties was introduced (10 years ago!), that it would not throw the expected TypeError but an InternalError.

    It is unclear how it "fixes" the problem in Chromium browsers.

    The polyfill - just like any other polyfill - overwrites Array.prototype.push with a conforming implementation that simply assigns the respective properties on the receiver. This includes the assignment to .length, even with an unchanged value, which will throw as expected. (Well actually it calls an array-set-length.js method to do that, which has to do the writability check explicitly in some engines).