While the JavaScript weekly mailing list still points to 90s style articles about the old JavaScript Internet Explorer 5 was supporting too, the current world has different real problems to consider.
Here a quick list of things you might not know about the current status of JavaScript possibilities.
Reserved Words As Properties
Number one of the list is the myth that reserved words cannot be used as properties. Here platforms that cannot:
- iOS 4
- IE less than 9
- Android less than 2.1
So, basically, 99% of mobile browsers support properties such obj.delete()
, used in most recent JavaScript specifications, while those jurassic browsers need the obj['delete']()
convention.
// exactly same good old ES3 behavior // using ES5 capabilities Function.prototype.new = function () { var // grab the prototype p = this.prototype, // create from it o = Object.create(p), // invoke the real constructor r = this.apply(o, arguments); // if the result is not undefined or null // and the returned value is an object/function // overwrite the result return r != null && ( typeof r === 'object' || typeof r === 'function' ) ? r : o; }; // you can be Rubyish now ^_^ var instance = MyClass.new(1, 2, 3); // P.S. if you have problems with JSLint // and the r != null part in above snippet // it's just time for you to upgrade to JSHint
Please Do Not Support Too Old Browsers
As easy as that. As a developer, company, software provider, whatever, you are trapping yourself behind problems that will never be fixed in those browsers and you are limiting your customer too, embracing development for such old environment, instead of promoting an update that will benefit them in terms of both potentials, expenses, and security.
Any company that will say no to that should be kindly be abandoned, IMHO, they're already out of web/JS business and they don't realize yet.
I understand some graceful measurement should be taken in order to migrate old users, but as long as they feel confortable, they won't migrate sooner for sure.
Customers or people we'd like to let them access our service, should be informed somehow of new possibilities too.
Apple Drops 3 Years Old Software Too
If Apple not accepting non retina software anymore is not enough as an argument, think how many possibilities you are dropping to your software in order to work the same in those old browsers.
You chose Web technologies, you should catch up with these, end of the story.
Object.defineProperty() *Is* Available
Even my Palm Pre 2 webOS supports Object.defineProperty()
, together with Object.defineProperties()
, Object.getPrototypeOf()
and Object.getOwnPropertyDescriptor()
!
If you don't want to deal with all this verbosity but you like the power behind, redefine is really your best friend then!
The most widely adopted list of ES5 features down to Android 2.1 phones and webOS are:
Object.create()
Object.defineProperty()
Object.defineProperties()
Object.getOwnPropertyNames()
Object.getOwnPropertyDescriptor()
Object.getPrototypeOf()
Things like Object.freeze()
might have been introduced later on so don't trust them ... but, whenever you wanna try that:
var freeze = Object.freeze || Object; freeze({}); // frozen where possible function returnFrozen(object) { return (Object.freeze || Object)(object); }
As it is for "use strict";
and all other things that works best natively, above technique will work with Object.seal()
, Object.preventExtensions()
, and why not, a shimmable Object.isExtensible()
'isExtensible' in Object || (function(){ // no way ES3 can prevent extension so ... Object.isExtensible = function (object) { // ... if an object, it's extensible return object != null && ( typeof object === 'object' || typeof object === 'function' ) }; }());
Function.prototype get caller() {return WTF}
Generally speaking the caller
property works since ever but there are cases where it does not and this is iOS5 and lower fault.
What am I talking about? About caller over getters, with or without __defineGetter__
old style approach, the new one fails too ^_^
Bear in mind iOS 5.1 and 6.0+ are just fine so you can still use that magic, if needed.
Note a part, that magic ain't disappearing any time soon so ... go on, use caller
until there is an alternative: so far, not a single one ^_^
Function.prototype.bind()
It took literarily ages for WebKit to adopt this method so this is something available in all modern browsers but most likely not available with not so old mobile one: easy shim from callerOf!
(function (P, l) { 'use strict'; if (!P.bind) { P.bind = function (s) { var c = this, a = l.call(arguments, 1); return function bind() { return c.apply(s, a.concat(l.call(arguments))); }; }; } }(Function.prototype, [].slice));
This is the kind of code that I would like to see in CDN, not just 50K libraries for client sake!
Avoid __proto__
Not only conceptually an error and used only to gain some arguable performance boost, __proto__
is absolutely something that IE 10 and 9 will never have in a consistent way.
If you want to transform a list into an array, just var slice = Function.call.bind([].slice);
so that you can slice(whatever, optionalIndex)
ALL the things, right? The bind()
is there and costs nothing ... just use it!
Better Than Zepto
What this library is doing, except from ignoring IE as a Mobile browser, is a poor/quick&dirty design/convention to obtain a prototype swap instead of initializing things in the right way.
The previously linked code could be represented by exactly the same syntax:
// an IE9 and 10 compatible zero bullshit Zepto core var emptyArray = []; zepto.Z = function(dom, selector) { var result = Object.create($.fn); emptyArray.push.apply( result, dom || emptyArray ); result.selector = selector || ''; return result; }
While performance might not be that good in some engine, and everybody knows that you should never $('select')
twice per collection so actually, considering above snippet goes 400.000 objects per seconds, that's not a big/real deal at all!
If that is, I tell you something else is wrong in the app logic!
In any case, actually, there's some mobile platform there, those Zepto thinks is supporting, that scores more with lower results than with a prototype swap, which is the most common selector case, BlackBerry 10 is 8 thousands operations per seconds there compared with __proto__
Thomas Fuchs has been so nice in his repository I cannot even push/contributes these improvements ... surely he would get this one as an insult too, isn't it?
A Swap Oriented __proto__ Attempt
Assuming you still want to swap runtime classes because you cannot define a proper inheritance upfront, here a broken attempt to do that in IE8 and lower:
object = dunder(object, proto);
what's dunder()
dunder() is my attempt to bring a friendly cross platform way, included older IE, to swap proto at runtime.
It requires an assignment so, back to Zepto example, return dunder(dom || [], $.fn)
would be all you need to make it work everywhere.
JSON.stringify(object, *replacer*)
This is Safari specific gotcha, and it's about the replacer.
While specs say that Let newElement be the result of calling the abstract operation Walk, passing val and **ToString**(I)
, Safari will send to the receiver the number 0
instead of the string '0'
.
What's the big deal here? That in JavaScript, 0 == false
while '0' == true
so ... if you have this kind of check in your receiver thinking that if empty, nothing should be done:
if (key) { // parse your value }
Improve that check with if (key === '')
, probably the only place on earth where JSLint would have helped you for real instead of messing up your own code.
And for today, that's all folks!