- Desktop
- Chrome 7+
- Firefox 4+
- Safari 5+
- Opera 12+
- IE 9+
- Mobile
- Android 2.2+, 3+, and 4+, stock browser
- Android 4.1+ Chrome
- Android and Symbian Opera Mobile
- Android Dolphin Browser
- Android Firefox
- iOS 4+, 5+, and 6+, Safari Mobile
- iOS Chrome Browser
- Windows Phone 7+ IE9 Mobile
- Windows 8+ RT and Pro
- webOS stock Webkit browser
- Chrome OS
- Firefox OS
- I believe Blackberry supports them without problems with their advanced browser
- I believe updated Symbian too but I could not test this
- Server
- node.js
- Rhino/Ringo
- JSC
- BESEN and others I could not test too
Please note that even if
Object.freeze()
and others might not be supported, create
, defineProperty
, and defineProperties
are, as it is for example in Android 2.2 stock browser.As summary, unless you are not so unfortunate you have to support that 8% (and dropping) of IE8 market share, there are really no excuse to keep ignoring JavaScript ES5 Descriptors.
Update the build process now updates tests automatically in the repository web page.
Descriptors Are Powerful
Things we can improve using ES5 descriptors are many, including new patterns we never even thought were possible since most of them might result not implementable in many other programming languages.This is as example the case of the inherited getter replaced on demand with a direct property access, a pattern discussed in The Power Of Getters post, a pattern described from jonz as:
Right now this syntax seems like obfuscation but the patterns it supports are what I've always wanted, I wonder if it will ever become familiar.
Descriptors Are Weak Too
Not only the syntax might look completely not familiar for everything that has been written until now in JavaScript, but current specifications suffer inheritance problems. Consider this piece of malicious code:Object.prototype.enumerable = true; Object.prototype.configurable = true;And guess what, every single property defined without specifying those properties, both
false
as default, will be enumerable and deletable so for/in
loops and trustability will be both compromise.Even worst, if
Object.prototype.writable = true
comes in the game, every attempt to define a getter or a setter will miserably fail.I don't think we are planning to write this kind of code to ensure desired defaults, right?
Object.defineProperties( SomeClass.prototype, { prop1: { enumerable: false, writable: false, configurable: false, value: "prop1" }, method1: { enumerable: false, writable: false, configurable: false, value: function () { return this.prop1; } } });Not only the moment we would like to assign a getter, we are trapped in any case, since we cannot have both
writable
and get
, even if inherited, but above code has been always written in JS such:
SomeClass.prototype = { prop1: "prop1", method1: function () { return this.prop1; } };OK, this way will enforce us to use
Object#hasOwnProperty()
in every loop and does not guarantee that those properties won't change in the prototype, but how about having the best from both worlds?
redefine.js To The Rescue
This tiny library goal, which size once minzipped is about 650 bytes, is to use the power of ES5 descriptors in an easier, memory safe, and more robust approach.redefine( SomeClass.prototype, { prop1: "prop1", method1: function () { return this.prop1; } });That's pretty much it, an ES3 alike syntax with ES5 descriptors and the ability to group definitions by descriptor properties.
redefine( SomeClass.prototype, { prop1: "prop1", method1: function () { return this.prop1; } }, { // we want that prop1 and method1 // can be changed runtime in the prototype writable: true, // we also want them to be configurable configurable: true // if not specified, enumerable is false by default });As easy as that, that group of properties will all have those descriptor behavior and everything is safe from the
Object.prototype
, you have 50 and counting tests for the whole library that should cover all possibilities with the provided API.
More Power When Needed
What if we need to define a getter inline? How to not have ambiguity problems since the value is accepted directly? Like this :)redefine( SomeClass.prototype, { get1: redefine.as({ get: function () { return 123; } }), prop1: "prop1", method1: function () { return this.prop1; } }, { writable: true, configurable: true });That's correct,
redefine
can understand developers intention thanks to a couple of hidden classes able to trivially remove ambiguity between a generic value and a meant descriptor, only when needed, as easy way to switch on ES5 power inline.Wen we need a descriptor? We set a descriptor!
If the descriptor has properties incompatible with provided defaults, latter are ignored and discarded so we won't have any problems, as it is as example defining that getter with
writable:true
as specified default.
Much More In It!
There is a quite exhaustive README.md page plus a face 2 face in the HOWTO.md one.Other 2 handy utilities such
redefine.from(proto)
, a shortcut of Object.create()
using descriptors and defaults as extra arguments, and redefine.later(callback)
, another shortcut able to easily bring the lazy getter replaced as property pattern in every developers hands, are both described and fully tested so I do hope you'll appreciate this tiny lib effort and start using it for more robust, easier to read and maintain, ES5 ready and advanced, client and server side projects.Last, but not least,
redefine.js
is compatible with libraries such Underscore.js
or Lo-Dash
, being an utility, rather than a whole framework.
No comments:
Post a Comment