Problems with extending regular Objects to support ES5 Array capabilities - javascript

I have long ago been willing to get the line between native Arrays and regular Objects totally blurred, not only extending Object with the same capabilities as Arrays got in ES5, but bundle up with my custom package of methods on both sides.
Couple of smart people thought about these paradigm changes. Like Angus Croll mentioned it in the article javascript-object-keys-finally:
"Moreover as the line between Arrays and regular Objects blurs (aided
by custom getters and setters) we’re likely to see a growth in generic
“array-like” objects which enjoy the best of both worlds – non-numeric
identifiers and access to the rich API set defined by Array.prototype.
EcmaScript 5 has apparently pre-empted this trend by introducing the
generic method, defined by one type but useable by any."
Along the way, he get things coded in the article:
extending-objects-with-javascript-getters
function extendAsArray(obj) {
if (obj.length === undefined || obj.__lookupGetter__('length')) {
var index = 0;
for (var prop in obj) {
if(!obj.__lookupGetter__(prop)) {
(function(thisIndex, thisProp) {
obj.__defineGetter__(thisIndex, function() {return obj[thisProp]});
})(index, prop)
index++;
}
};
obj.__defineGetter__("length", function() {return index});
}
return obj;
}
var myObj = {
left:50,
top:20,
width:10,
height:10
}
extendAsArray(myObj);
[].map.call(myObj,function(s){return s+' px'}).join(', ');
//"50px ,20px ,10px, 10px"
This approach is exceptionally interesting for me. However, it is also seemingly suffering a couple of serious problems!
How about extending the original myObj model with a couple of new properties?
Should we run extendAsArray on every property change to update it's concerning length property?
When a property changes, it's not just the length property that's relevant;
the array indices should also be updated, because an array-like property request definitely turns out to be undefined. So when
console.log(myObj.length) -> 4
myObj.zAxis=0
then
console.log(myObj[4]) // -> undefined!
console.log(myObj.length) // -> 4!
I have modified Angus' code accordingly, so it supports automatic update of length property on request:
function extendAsArray(obj) {
var index = 0;
for(var prop in obj){
if(!obj.__lookupGetter__(prop)){
(function(thisIndex, thisProp){
Object.defineProperty(obj, thisIndex, {
get: function(){return obj[thisProp]}
, enumerable: true
, configurable: true
, writeable: true
});
})(index, prop)
index++;
}
}
if(!obj.__lookupGetter__('length')){
Object.defineProperty(obj, 'length', {
get: function(){
return extendAsArray(obj);
}
, configurable: true
, writeable: true
});
return obj;
}
else{
return index;
}
}
The problem is: how do we updating the object's array indices together with its length property when a property is changed, added or removed?
Should I use Object.watch?
And there is still an unsolved question: how to interfere with my own unshimmed utility library, having made it also for Objects in a consistent way?
I am using the same codebase for both types: z.Object({}).mapEvery does the same as z.Object([]).mapEvery
Please avoid mentioning JQuery, and Underscore as well. I have got a comprehensive, custom list of methods for both types, and I am willing to use the standards completed possibly with my unshimmed ones, and I am not willing to refactor it!

I guess this is your question:
how do we updating the object's array indices together with its length property when a property is changed, added or removed?
You create methods to do it, so you essentially mimic the Object internal methods. I don't think you can do that with getters and setters, but I may be wrong about that.
The rest is more of a comment than an answer.
I have long ago been willing to get the line between native Arrays and regular Objects totally blurred
The line is already totally blurred. Arrays are Objects, the only thing that sets them apart is their special length property.
EcmaScript 5 has apparently pre-empted this trend by introducing the generic method,
ES5 didn't introduce generic methods, they have been in the language since ed 3 at least.
defined by one type but useable by any
Not at all, in fact ES5 is more restrictive. In ed 3, call and apply coerce the thisArg to an object using Object(*thisArg*), or substitute the global object if nothing was passed. Not so in ES5 which passes thisArg unmodified.
The restriction on using arrays as objects is related to convention, not the language itself. Most developers see a clear divide between when an object or array should be used. There are few cases where you really need to use an array like an object, but no doubt they exist. jQuery is an example of where an Object leverages Array properties, e.g. the elements collected by a selector are added as numeric properties and there is a length property that is the number of elements. That way generic array methods can be applied to jQuery objects (all in ed 3, by the way).
The Object.watch method is in JavaScrpit™, it's not part of ES5 so use with caution.
A major problem with creating your own version of built–in objects is that you'll probably end up wrapping every built–in method in a native one (like jQuery wraps every DOM method pretty much) and start setting getters and setters on every property, or end up with function calls to replace property access (e.g. jQuery's val, attr and prop methods). Rather tedious, and slow if performance matters.
Oh sorry, I mentioned jQuery… :-(
It just seems to be more sensible to design a library or framework to make the best use of the features that the language has, rather than trying to force it to do things it doesn't do well, or does not do natively.
But full marks for trying. :-)

There is a library watch.js out there, which is watching out for either property updates or new property addition as well.
try out!
It is working with setInterval, so it is not performance-friendly however.
When Harmony is out, we can do things that simply:
Object.observe(obj,Observer);
Check the spec for that:
Harmony
But, when later object extension is not in focus, i can freeze up the whole object upon initialization, not to be bothered with neither property changes nor property addition.
The code is changed accordingly:
extendAsArray = function z_extendAsArray(obj){
var index = 0;
for(var prop in obj){
if(!obj.__lookupGetter__(prop)){
(function(thisIndex, thisProp){
Object.defineProperty(obj, thisIndex, {
get: function(){return obj[thisProp]}
, enumerable: true
, configurable: true
, writeable: true
});
})(index, prop)
index++;
}
}
if(!obj.__lookupGetter__('length')){
Object.defineProperty(obj, 'length', {
value:index
});
if(!Object.freeze){
Object.defineProperty(Object, "freeze", {
enumerable: false
, configurable: false
, writable: false
, value: function (obj) {
var props = Object.getOwnPropertyNames(obj);
for(var i=0; i<props.length; i++){
var desc = Object.getOwnPropertyDescriptor(obj,props[i]);
if("value" in desc ){
desc.writable = false;
}
desc.configurable = false;
Object.defineProperty( obj, props[i], desc );
}
return Object.preventExtensions(obj);
}
});
}
Object.freeze(obj);
}
return obj;
};
Also i have found out what Angus Croll, who has been mentioned by the previous post has talked about it.
"Yes, we can make use of the equivalent functionality offered by well written libraries like underscore.js, but still we’re locked into non-standard, inverted signatures in which methods are static and objects are merely extra arguments – an ungainly arrangement for an instance-only language. At some point all supported browsers will be ES5 compliant, at which point the shimmed codebase can simply remove it’s shim library and carry on, while the unshimmed one must choose between a major refactor or a perpetually non-standard and static utility library."

Related

Javascript persistent-sorting Object "class"

Attending to it's specification, JSON elements (and javascript objects) are unordered so, even in almost all cases, when you iterate over a javascript object, you get elements in the same order they was defined; you definitively cannot trust in that order because engine is allowed to alter it.
This is extremely rare. I have been able to observe it one time, but I don't find that code right now and I don't remember the exact version of JS engine (but it was node). If I manage to find it, I will add it to this post.
That being said, the point is that code relying in this behaviour can (and should) be considered buggy because, even it will work as expected in most engines, it may fail typically because of internal engine optimisations.
For example:
"use strict";
var x = {
b: 23,
a: 7
};
function someSorting(input) {
var output = {};
Object.keys(input).sort().map(
function(k){
output[k] = input[k];
}
);
return output;
};
x = someSorting(x);
// Some smart engine could notice that input and output objects have the
// exact same properties and guess that, attending the unordered nature of
// javascript Object, there is no need to actually execute someSorting();
console.log(x);
// Usually will display: { a: 7, b: 23 }
// But perfectly we could got: { b: 23, a: 7 }
I know there is too many literature (even StackOverflow questions) about this (NON-) issue and "workarrounds" to achieve the expected behaviour by sorting keys in a separate array.
But doing so code goes too messy compared in simply trusting in key order.
I'm pretty sure that this can be achieved in a more elegant fashion by implementing a so-called "sObject" alternative having native Object as its prototype but overloading it's native iterator and setter so that:
When any new property is added, it's key is appended to an Array index mantained under the hood.
When an sObject instance is iterated, our customized iterator uses that index to retrieve elements in the right order.
In summary: Actual Object specification is right because, in most cases, properties order doesn't care. So I think that engine optimisations that could mess it are wonderfull.
But it would be also wonderful to have an alternative sObject with which we could do something like:
var x = new sObject({b: 23, a: 7});
...and trust that we could iterate it in the same exact order or, also / at least, do some sorting task over it and trust that this will not be altered.
Of course!! I'm initalyzing it with a native javascript Object so, in fact, theoretically we can't trust that it will be populated right (even I can't imagine why any engine optimisation should alter it before any operation).
I used that notation for brevity (and, I confess) because I expect that, in that case should work always (even I'm not really sure). However we even could sort it later (which, in most cases we will do that way) or use other kind of initialization like providing a JSON string or an array of objects (or arrays) with single key and value pairs.
My concern is: Such a thing exists yet? I wasn't able to find it. But sure I'm not the first guy thinking in that...
I can try to implement it (I'm thinking about that). I think it's possible and that I could achieve it. But it's not as simple so first I want to be sure that I'm not reinventing the wheel...
So any comments, suggestions, etc... will be welcome.
Sure, you could do all this. You will need some machinery such as Object.observer, which is currently only available in Chrome. We can define this as the following:
function myObject(object) {
// if the object already has keys, bring them in in whatever order.
var keys = Object.keys(object);
// Override Object.keys to return our list of keys.
Object.defineProperty(object, 'keys', { get: function() { return keys; });
// Watch the object for new or deleted properties.
// Add new ones at the end, to preserve order.
Object.observe(object, function(changes) {
changes.forEach(function(change) {
if (change.type === 'add') keys.push(change.name);
if (change.type === 'delete') keys = keys.filter(function(key) {
return key === change.name;
});
});
});
return object;
}
Note that Object.observe is asynchronous, so even after you add a property to the object, it won't be reflected in the custom keys property until after a tick of the clock, although in theory you could use Object.deliverChangedRecords.
The above approach uses a function which adds the new ordered key functionality to an existing object. Of course there are other ways to design this.
This "solution" obviously cannot control the behavior of for...in loops.

Alternative methods for extending object.prototype when using jQuery

Some time ago I tried to extend Object.prototype... I was surprised when later I saw errors in the console which comes from jQuery file. I tried to figured out what is wrong and of course I found information that extending Object.prototype is a "evil", "you shouldn't do that because JS is dynamic language and your code will not work soon" and information that jQuery will now add hasOwnProperty method to their for in loops.
Because I didn't want to leave jQuery, I drop the idea about extending Object.prototype.
Till now. My project getting bigger and I am really annoyed because I have to repeat many times some parts of the code. Below is a bit of the structure which I am using in my projects:
charts.js:
CHARTS = {
_init: function () {
this.monthlyChart();
/*
*
* more propertys goes here
*
*/
return this;
},
monthlyChart: function () {
//create my chart
return {
update: function () {
// update chart
}
};
}()
/*
*
* more propertys goes here
*
*/
}._init;
dashboard.js
NAVBAR = {
_init: function () {
/*
*
* more propertys goes here
*
*/
return this;
},
doSomething: function(){
$(document).ready(function(){
$('.myButton').on('click', function(){
var data = [];
// calling property from charts.js
CHARTS.monthlyChart.update(data);
});
});
}
}._init
As I mentioned project is really big now - it's over 40 js files and some of them has a few thousands line of code. It is really annoying that I have to repeat _init section every time, as well as I many functions I have to repeat $(document).ready && $(window).load.
I tried to find another solution for my problem. I tried to create class with init property (more you can find here) but I this solution forced me to add another "unnecessary" piece of the code to every file and accessing other file object property makes it to complicated too (return proper objects everywhere etc). As advised in the comment I started reading about getters and setters in JS.
After all I created something like that:
//Auto initialization
if (typeof $document === 'undefined') {
var $document = $(document),
$window = $(window),
$body = $('body');
}
Object.defineProperty(Object.prototype, '_init', {
get: function () {
// if object has no property named `_init`
if (!this.hasOwnProperty('_init')) {
for (var key in this) {
// checking if name of property does starts from '_' and if it is function
if (this.hasOwnProperty(key) && key[0] === '_' && typeof this[key] === 'function') {
if (key.indexOf('_ready_') > -1) {
//add function to document ready if property name starts from '_ready_'
$document.ready(this[key].bind(this));
} else if (key.indexOf('_load_') > -1) {
//add function to window load if property name starts from '_load_'
$window.load(this[key].bind(this));
} else {
// else execute function now
this[key].bind(this)();
}
}
}
return this;
}
}
});
and my object:
var DASHBOARD = {
_runMe: function(){
},
_ready_runMeOnReady: function(){
},
_load_runMeOnLoad: function(){
},
iAmAString: ''
}._init
It seems that this solution works with jQuery. But is it safe to use? I don't see any problem the code can cause and I don't see any further problems that it may cause. I will be really happy if somebody will tell me why I shouldn't use this solution.
Also I'm trying to understand how it works in details. Theoretically I defined property for the Object.prototype by defineProperty, without assigning value to it. Somehow it doesn't cause any errors in jQuery fore in loop, why? Does that mean that property _init is not defined at some point or at all because I am defined only getter of it?
Any help will be appreciated :)
By not including the descriptor in Object.defineProperty(obj, prop, descriptor) JavaScript defaults all the Boolean descriptor attributes to false. Namely
writable, enumerable, and configurable. Your new property is hidden from the for in iterators because your _init property is enumerable:false.
I am not a fan of JQuery so will not comment on why in regard to JQuery
There is no absolute rule to adding properties to JavaScript's basic type and will depend on the environment that your code is running. Adding to the basic type will add it to the global namespace. If your application is sharing the namespace with 3rd party scripts you can potentially get conflicts, causing your code or the third party code or both to fail.
If you are the only code then conflicts will not be an issues, but adding to object.prototype will incur an addition overhead on all code that uses object.
I would strongly suggest that you re examine the need for a global _init. Surely you don't use it every time you need a new object. I am a fan of the add hock approach to JavaScript data structures and try to keep away from the formal OOP paradigms
Your question in fact contains two questions.
It seams that this solution works with jQuery. But is it safe to use? I don't see any problem the code can cause and I don't see any further problems that it may cause. I will be really happy if somebody will tell me why I shouldn't use this solution.
First of all, there are three main reasons to avoid modification of built-in prototypes.
For-in loops
There is too much code using for-in loop without hasOwnProperty check. In your case that is jQuery code that does not perform check.
Solutions
Don't use for-in loop without .hasOwnProperty check.
Doesn't apply in this case because it's third-party code and you can't modify it.
for-in loop traverses only enumerable keys.
You have used that solution. Object.defineProperty creates non-enumerable properties by default (ECMAScript 5.1 specification)
Not supported by IE8.
Conflicts
There is risk of property name. Imagine that you use jQuery plugin that checks for existence of ._init property on objects - and it can lead to subtle and hard to debug bugs. Names prefixed with underscore are widely used in modern JavaScript libraries for indicating private properties.
Encapsulation violation (bad design)
But you have worser problem. Definining global ._init property suggests that every object have universal initialization logic. It breaks encapsulation, because your objects don't have full control over their state.
You can't rely on presence of _init method due to this. Your coworkers can't implement their own class with
Alternative designs
Global initializer
You can create global function initialize and wrap all your objects that require initialization in it.
Decouple view and logic
Your objects should not merge logic and view in one object (it violates single responsibility principle) and you are victim of spaghetti code.
Moreover - object initialization should not bind it to DOM, some controller objects should be a proxy between your logic and display.
It can be good idea to inspect how popular client-side MVC frameworks have solved this problem (Angular, Ember, Backbone) have solved this problem.
Is it safe to use getters and setters?
Yes. But if you only support IE9+.
Is it safe to modify Object.prototype?
No. Create another object to inherit all of your application objects from.
Why extending basic JavaScript objects is eval evil?
Because EVERY SINGLE object created on the webpage where your script is loaded will inherit that property or method.
There is a lot cons like collisions and performance overhead if you do it that way.
There is a lot of ways to make it better, let me show you the one I use.
// Here we create the base object:
var someBaseObject = {};
someBaseObject.someMethod = function () {
// some code here
}
someBaseObject.someProperty = "something";
// And inherit another object from the someBaseObject
someObject = Object.create(someBaseObject);
someObject.someAnotherMethod = function () {
// some code here
}
This approach allow us to leave the Object prototype alone, and build a prototype chain where someObject inherits from someBaseObject, and someBaseObject inherits from Object.
The only thing I want to say by this post: leave base objects alone and build your own, so you will have much less headache.
Note: Object.create is supported in IE9+. Here is shim for IE8 and lower by Douglas Crockford:
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}

Obtain the same result as a for..in loop, without any for..in loop

(Let us suppose that there is a good reason for wishing this. See the end of the question if you want to read the good reason.)
I would like to obtain the same result as a for in loop, but without using that language construct. By result I mean only an array of the property names (I don't need to reproduce the behavior that would happen if I modify the object while iterating over it).
To put the question into code, I'd like to implement this function without for in:
function getPropertiesOf(obj) {
var props = [];
for (var prop in obj)
props.push(prop);
return props;
}
From my understanding of the ECMAScript 5.1 specification about the for in statement and the Object.keys method, it seems the following implementation should be correct:
function getPropertiesOf(obj) {
var props = [];
var alreadySeen = {};
// Handle primitive types
if (obj === null || obj === undefined)
return props;
obj = Object(obj);
// For each object in the prototype chain:
while (obj !== null) {
// Add own enumerable properties that have not been seen yet
var enumProps = Object.keys(obj);
for (var i = 0; i < enumProps.length; i++) {
var prop = enumProps[i];
if (!alreadySeen[prop])
props.push(prop);
}
// Add all own properties (including non-enumerable ones)
// in the alreadySeen set.
var allProps = Object.getOwnPropertyNames(obj);
for (var i = 0; i < allProps.length; i++)
alreadySeen[allProps[i]] = true;
// Continue with the object's prototype
obj = Object.getPrototypeOf(obj);
}
return props;
}
The idea is to walk explicitly the prototype chain, and use Object.keys to get the own properties in each object of the chain. We exclude property names already seen in previous objects in the chain, including when they were seen as non-enumerable. This method should even respect the additional guarantee mentioned on MDN:
The Object.keys() method returns an array of a given object's own
enumerable properties, in the same order as that provided by a
for...in loop [...].
(emphasis is mine)
I played a bit with this implementation, and I haven't been able to break it.
So the question:
Is my analysis correct? Or am I overlooking a detail of the spec that would make this implementation incorrect?
Do you know another way to do this, that would match the implementation's specific order of for in in all cases?
Remarks:
I don't care about ECMAScript < 5.1.
I don't care about performance (it can be disastrous).
Edit: to satisfy #lexicore's curiosity (but not really part of the question), the good reason is the following. I develop a compiler to JavaScript (from Scala), and the for in language construct is not part of the things I want to support directly in the intermediate representation of my compiler. Instead, I have a "built-in" function getPropertiesOf which is basically what I show as first example. I'm trying to get rid of as many builtins as possible by replacing them by "user-space" implementations (written in Scala). For performance, I still have an optimizer that sometimes "intrinsifies" some methods, and in this case it would intrinsify getPropertiesOf with the efficient first implementation. But to make the intermediate representation sound, and work when the optimizer is disabled, I need a true implementation of the feature, no matter the performance cost, as long as it's correct. And in this case I cannot use for in, since my IR cannot represent that construct (but I can call arbitrary JavaScript functions on any objects, e.g., Object.keys).
From the specification point of view, your analysis correct only under assumption that a particular implementation defines a specific order of enumeration for the for-in statement:
If an implementation defines a specific order of enumeration for the
for-in statement, that same enumeration order must be used in step 5
of this algorithm.
See the last sentence here.
So if an implementation does not provide such specific order, then for-in and Object.keys may return different things. Well, in this case even two different for-ins may return different things.
Quite interesting, the whole story reduces to the question if two for-ins will give the same results if the object was not changed. Because, if it is not the case, then how could you test "the same" anyway?
In practice, this will most probably be true, but I could also easily imagine that an object could rebuild its internal structure dynamically, between for-in calls. For instance, if certain property is accessed very often, the implementation may restructure the hash table so that access to that property is more efficient. As far as I can see, the specification does not prohibit that. And it is also not-so-unreasonable.
So the answer to your question is: no, there is no guarantee according to the specification, but still will probably work in practice.
Update
I think there's another problem. Where is it defined, what the order of properties between the members of the prototype chain is? You may get the "own" properties in the right order, but are they merged exactly the way as you do it? For instance, why child properties first and parent's next?

Use a property or method to mark a class as special? (in JavaScript)

In JavaScript, I want to mark object A as special, so that when A is accessed by B, B can check whether A is marked so that B treats A as different from other objects. (Think that B is a serializer that processes many different objects, and A has to be serialized in a certain way.)
Now, I can either
1: set a property in A, e.g., A.special=true
2: define a method, e.g., A.isSpecial(), which if the method exists, it shows that A is special.
I know that both of these do the same thing. From the design point of view, are there any differences, which makes one preferable?
From the design point of view, are there any differences, which makes one preferable?
The boolean property is much simpler, and easier to test. If it is not defined, A.special will result in undefined which is falsy already.
If you'd use a method, you would need to test typeof A.special == "function" && A.special() as only A.special() would lead to an exception if the method was not defined.
The method solution would only be preferable if you'd need to dynamically calculate the specialness (it might depend on other properties?) and don't want to update a boolean flag always along with updating those properties. However, for that case there's also the middle way of using a getter property (if you don't need to support old IEs).
Accessing the property is definitely faster:
this.special = true;
But outside A's code, someone can do A.special = false. There's no way to prevent that.
Using a method forbids other objects to modify the value. In A's constructor you can define:
...
var special = true;
...
this.isSpecial = function() {return special;};
In modern browsers, there's a way to get the best of both: Object.defineProperty. So you can define a property and forbid external sources to change it:
Object.defineProperty(this, "special", {value: true, writable: false, configurable: false});
This isn't available in IE7 and lower, and in IE8 is defined only for DOM objects and using the get and set property definitions:
Object.defineProperty(this, "special", {get: function() {return true;}});
This isn't faster than calling an isSpecial method.
Using a property A.special = true; is going to be faster (although I doubt this is a performance critical piece of code).
The advantage of doing a method A.special = function() {...}; is that you get a layer of indirection and can put more advanced logic in there. E.g.,
A.special = function() { return foo && bar && !baz ? true : false; };

What modernizer scripts exist for the new ECMAScript 5 functions?

ECMAScript 5 has quite a few nice additions. John Resig has a good overview here. Here is a good ECMAScript 5 compatibility table.
A lot of this stuff can be "faked" for browsers that don't support these functions yet. Do you know of any scripts that can do this? I'm particularly interested in Object.create.
For example, Douglas Crockford's JSON script checks if JSON functions exist before creating them.
If there was more like the JSON one we could include them when we need to use the new functions.
Crockford recommends this kind of Object.create shim:
if (typeof Object.create != "function") {
Object.create = function (o) {
function F(){}
F.prototype = o;
return new F;
};
}
But please don't do this.
The problem with this approach is that ES5 Object.create has a signature of 2 arguments: first — an object to inherit from, and second (optional) — an object representing properties (or rather, descriptors) to add to newly created object.
Object.create(O[, Properties]); // see 15.2.3.5, ECMA-262 5th ed.
What we have is an inconsistent implementation with 2 different behaviors. In environments with native Object.create, method knows how to handle second argument; in environments without native Object.create, it doesn't.
What are the practical implications?
Well, if there's some code (say, a third party script) that wants to use Object.create, it's rather reasonable for that code to do this:
if (Object.create) {
var child = Object.create(parent, properties);
}
— essentially assuming that if Object.create exists, it must conform to specs — accept second argument and add corresponding properties to an object.
But, with the above-mentioned shim, second argument is simply ignored. There's not even an indication of something going wrong differently. A silent failure, so to speak — something that's rather painful to detect and fix.
Can we do better?
Well, it's actually impossible to create a fully-conforming Object.create shim using only (standard) ES3 facilities. The best solution is to create a custom wrapper method.
There are, however, few alternative (less than optimal) things you can try:
1) Notify user about inability to work with second argument
if (!Object.create) {
Object.create = function (o) {
if (arguments.length > 1) {
throw Error('second argument is not supported');
}
// ... proceed ...
};
}
2) Try to handle second argument:
if (!Object.create) {
Object.create = function (parent, properties) {
function F(){}
F.prototype = parent;
var obj = new F;
if (properties) {
// ... augment obj ...
}
return obj;
};
}
Note that "properties" is an object representing property descriptors, not just property names/values, and is something that's not very trivial to support (some things are not even possible, such as controlling enumerability of a property):
Object.create(parent, {
foo: {
value: 'bar',
writable: true
},
baz: {
get: function(){ return 'baz getter'; },
set: function(value){ return 'baz setter'; },
enumerable: true
}
});
The other inconsistency in the original shim is that it doesn't take care of parent object being null.
var foo = Object.create(null);
This creates an object whose [[Prototype]] is null; in other words, object that doesn't inherit from anything, not even Object.prototype (which all native objects in ECMAScript inherit from).
foo.toString; // undefined
foo.constructor; // undefined
// etc.
This is, by the way, useful to create "proper" hash tables in ECMAScript.
It's possible to emulate this behavior, but only using non-standard extensions, such as "magical" __proto__ property (so implementation would be not very portable or robust). Solution to this problem is similar: either emulate ES5 implementation fully, or notify about inconsistency/failure.
es5-shim http://github.com/kriskowal/es5-shim/
This was part of the narwhal stand-alone javascript environment, but has been broken out on its own. It's pretty darn mature and precise.
es5 - JavaScript/EcmaScript 5 in 3 is a collection shared at BitBucket. Object.create in particular is an easy one to fake, made popular by Crockford et al, but improved on here by Justin Love, focussing on many ES5 parts.
If you don't mind learning the library and writing some code yourself, you can find some code implementations of the ECMAScript 5 library at
https://developer.mozilla.org/En/JavaScript/ECMAScript_5_support_in_Mozilla
For example, the code for Array.filter
And then Crockford has JSON.parse/stringify in json2.js
https://github.com/douglascrockford/JSON-js

Categories

Resources