looking for a full-immersion/face-to-face HTML5, JavaScript, and Mobile Web Development training in the heart of London? Book your spot
Showing posts with label objects. Show all posts
Showing posts with label objects. Show all posts

Thursday, August 16, 2012

JavaScript recent Bits and Bobs

Quick post about few things landed, or not yet, in JavaScript world.

preciseTime()

In this era loads of +new Date, JSC offers since quite a while a handy global function called preciseTime().
Since this function offers more accuracy than milliseconds, and I am talking about microseconds, which is 1/1000 of a millisecond, it's the best option we have to measure benchmarks or be sure that some time elapsed between two statements in a synchronous code flow.

You might don't know that a loop between new Date and another new Date could produce completely unexpected results such a negative integer which is kinda unexpected since zero is the best case we would consider.

This behavior is behind ticks and clocks, more or less same reason setTimeout or setInterval have never been accurate in therms of delay.

preciseTime, this is the obvious name of my latest git repository, could be shimmed or polyfilled quite easily via a node module I can't npm install for some reason, or through java.lang.System.nanoTime for Rhino.

enjoy!

Object.getPropertyNames()

In MDN Proxy Fundamental Traps chapter there are two functions I was kinda waiting for, and one of these is Object.getPropertyNames().

As you might know, Object.keys(object) returns an array of enumerable object properties.
A similar behavior could be obtained via this shim:

// warning: this is not fully ES5 standard
"keys" in Object || !function(hasOwnProperty){
Object.keys = function keys(object) {
var keys = [], key;
for (key in object)
// not considering IE < 9 quirks
hasOwnProperty.call(object, key) && keys.push(key);
;
return keys;
};
}({}.hasOwnProperty);


On the other hand, Object.getOwnPropertyNames returns an Array of all properties defined in the object, even those not enumerable or as getters/setters, but without considering inherited properties.
For all ES3 browsers is basically the same of above Object.keys() shim since it's not possible to define not enumerable properties in a meaningful way.
To be really honest, probably all IE < 9 browsers should use the check over isPropertyEnumerable() check via Object.keys, and leave the provided shim as it is since actually, those not enumerable properties are those that this function could return in a meaningful way, and talking about shims ... never mind ...

In ES5 world there's no other way to retrieve all properties names defined in an object so this methods is pure awesomeness!

Right ... What About Object.getPropertyNames()

What is not possible right now, and in a world where inheritance is all over the place as JS world is, is the ability to retrieve not only own properties, but inherited properties too.
In a duck typed system we need to know all characteristics of an object to be sure "it's a duck". Right now there's no standard way to obtain all properties an object could use, and this is where Object.getPropertyNames() becomes handy: you receive all inherited properties of an object too, together, of course, with own properties.
In my shim, this is obtained through the __proto__ de facto standard property.


At this point we can recognize a duck properly, the only method eventually missing is the one able to give us a list of not enumerable properties per each object ... but with these tools, we can create one, if truly necessary.

Object.getPropertyDescriptor()

Oh well, this is about another annoying thing ... the fact we know that obj instanceof Class but we have to be upside-down to know if a property, defined as default in the Class.prototype has been redefined or it's simply that bloody default.
This is about this method, shimmed in the previous gist as well, and able to retrieve the descriptor of a property that might, or might not, be inherited. How cool is that?

The only thing I am not sure about, is if the method should consider up to prototype === null, including Object.prototype or not ... right now is not, since I believe nobody would ever check for hasownProperty descriptor, as example, with a generic object.

global methods, classes, and shit

This is more a hint, whenever you are curious about what's exposed through your global object, you can simply perform this check, and inside an about:blank page:

console.log(
Object.getOwnPropertyNames(this).sort().join("\n")
);

Where if you want alphabetic order, you might consider this elaborated version if previous one did not work as expected.
Run it once in your browser, environment, console:

!function(global){
function alphabetically(a, b){
var
alen = a.length,
blen = b.length,
len = Math.min(alen, blen),
i = 0,
ac, bc, c
;
while (i < len) {
ac = a.charCodeAt(i);
bc = b.charCodeAt(i);
c = ac - bc;
if (c) return c;
++i;
}
return alen - blen;
}
var getOwnPropertyNames = Object.getOwnPropertyNames;
if (!getOwnPropertyNames) {
getOwnPropertyNames = function getOwnPropertyNames(object) {
var hasOwnProperty = {}.hasOwnproperty, keys = [], key;
for (key in object)
hasOwnProperty.call(object, key) && keys.push(key)
;
return keys;
};
}
function getAllKeys(object, ordered) {
var keys = getOwnPropertyNames(object);
ordered && keys.sort(alphabetically);
return keys;
}
console.log(getAllKeys(global,1).join("\n"));
}(this);

Wednesday, August 17, 2011

JSONH And Hybrid JS Objects

I have already described JSONH and now I also have the proof that it's as safe as native JSON is but on average 2X faster than native JSON operations with both small (10 objects), medium (100 objects), and massive (5000 objects and not a real world case, just a stress test to see how much JSONH scales) homogenous collections.
Wherever it's not faster it's just "as fast" but the best part is that it seems to be always faster on slower machines ( mobile ).
Moreover, the 5000 objects stress example shows that JSONH.stringify() produces a string with 54% of original JSON.stringify() size so here the summary: JSONH is faster on both compression and decompression plus it produces smaller output


yeah but ... what About Hybrid Objects

To start with, if you don't recognize/understand what is an homogenous collection and ask me: "what about nested objects?", all I can do is to point you out that Peter Michaux explained this years before me.
Have a look there and please come back after the "aaaaahh, got it: right!"

Hybrid Objects

Nowadays JSON is used everywhere but not everywhere with homogeneous collections. A simple example to screw up JSONH possibility is an object like this:

// result of a RESTful service, Ajax, query
// once again about generic articles: book!
var result = {
category: "books",
subcategory: "fantasy",
description: [
{
title: "The Lord Of The Rings",
description: "Learn about the darkness"
}, {
title: "The Holy Bible",
description: "Learn about both light and darkness"
},
// all other results out of this list
]
};

If we receive an object with one or more properties containing an homogeneous collection, as is description in above example, we may already decide to use JSONH advantages.

JSONH On Hybrid Objects

It's that easy!

// before we send/store/write data on output
result.description = JSONH.pack(result.description);
print(JSON.stringify(result));

If the client is aware about the fact one or more specific property is an homogeneous collection, to obtain the original object we can do this:

// stringifiedResult as XHR responseText
var obj = JSON.parse(stringifiedResult);
obj.description = JSONH.unpack(obj.description);

// or simply via JSONP callback
data.description = JSONH.unpack(data.description);

For the same reason JSONH is faster than JSON, this operation will grant us less bandwidth to both send or receive objects, and faster conversion performances.

As Summary

I am willing to think soon about a possible schema able to describe homogeneous collections properties out of an object ... a sort of JSONH "mapper" to automate the procedure on both server side and client side and any suggestion will be more than welcome.
At least so far we know already how to adopt this solution :)