Adding Support for ES2015 Number Methods to iOS 8
At Build.com, I’m working on an e-commerce app using React Native. React Native allows us to write apps in JavaScript that can run on iOS and Android phones with near native performance.
The other day, we received several crash reports from users running iOS 8. All of the reports involved method calls on JavaScript’s global Number
object.
The errors took the form of:
Unhandled JS Exception: undefined is not a function (evaluating ‘Number.parseInt’)
What are the new ES2015 Number methods?
The ES2015 update brought a lot of new functionality to JavaScript and specifically, the global Number object. Four previously global functions have been moved on to the Number object in an attempt to make JavaScript more modular.
These include:
- parseInt
- parseFloat
- isNaN
- isFinite
The Number object also received a bunch of new functions and constants. 2ality has a great post on the new features.
iOS 8 does not support the new Number methods
After a little bit of research, it turns out that iOS 8 doesn’t support a lot of the ES2015 features.
Of course, we use BabelJS to compile and polyfill our ES2015 code into code that is usable by the native JavaScript engines. Specifically, we use the react-native
preset for Babel. But based on my experience and my review of the react-native
preset, the new Number methods are not polyfilled.
This means that iOS 8 would correctly run:
var integer = parseInt('8');
but it would not be able to run the corresponding ES2015 version:
var integer = Number.parseInt('8');
What is the polyfill for the new Number methods?
MDN’s reference on the Number object has the polyfills for most or all of the new Number methods.
Many of them are as simple as:
Number.parseInt = parseInt; Number.parseFloat = parseFloat;
If it’s possible the functions might already exist (aka, you’re also targeting newer versions of iOS), then you could also add a check to see if the method already exists.
Fixing iOS 8 support for the new Number methods
The solution to this bug is to polyfill the Number object with the necessary methods. Ordinarily, I would say that this could be done with a BabelJS preset or plugin but I was unable to turn up any in my limited research.
How you polyfill the methods would depend on your code base. You could:
- put the polyfill in a central file that runs at start up of your React Native application
- look for a BabelJS plugin that fixes your particular need or you could try to get the
babel-polyfill
plugin working in React Native. A lot of people are asking about that plugin in the forums so I’m guessing it’s not easy - import the appropriate
core-js
libraries - create wrapper functions for missing methods that include the polyfill
We actually took the last approach. We use parseInt
and parseFloat
for parsing data from our API for display. Because of this, we don’t want any invalid numbers to display so we have a default return value.
The polyfilled code ends up looking like this:
toInteger(number) { if (!Number.hasOwnProperty('parseInt')) { Number.parseInt = parseInt; } const parsedNumber = Number.parseInt(number); return isNaN(parsedNumber) ? 0 : parsedNumber; }, toFloat(number) { if (!Number.hasOwnProperty('parseFloat')) { Number.parseFloat = parseFloat; } const parsedNumber = Number.parseFloat(number); return isNaN(parsedNumber) ? 0.0 : parsedNumber; },
Update for June, 2017
I’ve expanded the polyfills since this blog post was written. I recently cleaned up the code, made it more modular and published the package on npm and Github. The package now just requires a single import
or require
statement at the beginning of your application.
So, you are doing the checks in every invocation. Not who ‘polyfills’ are supposed to work.
I’d just put it t the start and hence simplify the 2 methods (by removing the checks)
Andy,
You’re right, of course, and that’s what I meant when I said, “put the polyfill in a central file”. We should probably move it into
index.ios.js
but it was a quick fix to stop a production bug. And like most “quick” fixes, it’ll probably be like that for a while 😉In my defense though, the function only runs once per page, the if test should run very quickly, and we’re only modifying the Number prototype for a very small minority of users.
Thanks for reading!
Garrett
You have more options: https://leanpub.com/setting-up-es6/read#ch_babel-helpers-standard-library
Thanks Axel! That looks like a great option.