Search code examples
javascriptecmascript-6salesforceshim

Looking for hacks to shim objects when their prototype are sealed


In my environment (Salesforce Commerce Cloud), String and String.prototype, Array and Array.prototype, Object and Object.prototype are sealed. I have no control over this sealing.

My environment only supports ES5 and I would like to use an ES6 shim (https://github.com/paulmillr/es6-shim) to be able to use convenient ES6 methods like find(), reduce() or even startsWith()...

I can't use these shims because errors are thrown when I try to augment prototypes. Do you know any tricks to bypass this restriction? I mean using Array.prototype.find() without providing my own implementation.

For example, a solution where I could use new ES6Array([]), before being able to use ES6 function, would be a suitable solution for me. I just want to avoid making my own implementation of shims. I want to use the paulmillr implementation as much as possible.

Is it possible to use shadowing hacks to use paulmillr implementations? I've been trying on my side to do that but it doesn't lead to any compliant result.


Solution

  • es6-shim is a polyfill and will surely fail if prototypes are sealed, because it's supposed to modify them.

    The approach that is needed here is ponyfill. As the description says,

    In general, you should not modify API's you don't own.

    A ponyfill, in contrast, doesn't monkey patch anything, but instead exports the functionality as a normal module, so you can use it locally without affecting other code.

    tl;dr; Polyfills are naughty as they patch native APIs, while ponyfills are pure and don't affect the environment.

    Some of them are labeled on NPM with ponyfill keyword.

    core-js provides library version of it that doesn't pollute global namespace and thus can be used as a ponyfill, so generally there's no reason to look any further:

    import * as find from 'core-js/library/fn/array/find';
    
    find(array, 'foo')
    

    Notice that some core-js/library exports are polyfilled implementations (Promise, Map, etc.):

    import { Promise as PolyfilledPromise } from 'core-js/library';
    
    PolyfilledPromise.resolve();
    

    While other ones are collections of polyfilled methods, because it's impractical or impossible to provide independent implementation for them (Array, Object):

    import { Array as arrayPonyfills } from 'core-js/library';
    const { find } = arrayPonyfills;
    
    find.call(array, 'foo');