Monday, March 31, 2008

Bases, merits, and defects of packed code

How many times we have seen an included JavaScript apparently incomprehensible?
These examples could explain better what I mean:
packed.it via MyMin

eval((function(M,i,n){return '0("1");'.replace(/\w+/g,function(m){return (n[m]!=i[m]&&i[m])||(i[m]=M[parseInt(m,36)])})})('alert.test'.split('.'),{},Object.prototype))


Dean Edwards packer

eval(function(p,a,c,k,e,d){e=function(c){return c};if(!''.replace(/^/,String)){while(c--)d[c]=k[c]||c;k=[(function(e){return d[e]})];e=(function(){return'\w+'});c=1};while(c--)if(k[c])p=p.replace(new RegExp('\b'+e(c)+'\b','g'),k[c]);return p}('1('0');',2,2,'test|alert'.split('|'),0,{}))


These are only two parsers which aim is to reduce code size using an inline decompression technique that is able to evaluate source code after common keywords replacement.


Basis of portable and packed code


The main goal of these services is to compress a source reducing occurrences of repeated words, using different technique to create both compressed string and inline function with decompression algo.
In this paragraph we will see a rudimentary example on how can be possible to create our own compressor. Let's go with the first function:

function pack(code, keywords){

var re = /\w+/g,
filter = {},
key;

// foreach word or number in string
while(key = re.exec(code))
// make found one unique
// if does not exists it creates them
// otherwise it overwrite them
filter[key[0]] = 0;
// for example, if code is "a b a", filter
// will contain only two properties, a and b
// with value 0 for both of them

// with found list of unique words or numbers
for(key in filter)
// avoid inherited Object.prototype parameters or methods
if(filter.hasOwnProperty(key))
// add key to array
// save into filter key position in the array
// converting them into base 36 string
filter[key] = (keywords.push(key) - 1).toString(36);
// for example, if code is "a b a", filter.a value will be 0, and filter.b will be 1

// for each word or number
// return keyword index in base 36 format
return code.replace(re, function(key){
return filter[key];
// for example, if code is "a b a"
// returned code will be "0 1 0"
});
};


var myCode = 'alert("this alert will show this text");',
myKeywords = [],
packed = pack(myCode, myKeywords);
alert(packed); // 0("1 0 2 3 1 4");

Reading comments, we can understand the logic behind a client side based compressor.
And since compression operation follows usually a "one to many" logic, where one is the operation to compress, and many are clients that will decompress code, more simple and fast will be the decompression operation, more powerful, portable, and compatible will be our algorithm.

function unpack(code, keywords){

// foreach word or number
return code.replace(/\w+/g, function(key){
// return related keywords value
// converting base 36 string into
// base 10 index
return keywords[parseInt(key, 36)];
// for example, if code is "0 1 0"
// returned string will be like
// keywords[0] + " " + keywords[1] + " " + keywords[0]
});
};

(unpack(packed, myKeywords) === myCode); // true

The last ring of our chain, is a function that is able to create automatically final result code:

function portablePack(code){
var
// keywords container
keywords = [],

// packed version of the code
packed = pack(code, keywords),

// object to make returned string evaluable
safe = {"'":"\\'", "\\":"\\\\", "\n":"\\n", "\r":"\\r"};

// to solve problems with some special char inside the string
// make packed result more safe replacing chars using safe object keys values
packed = packed.replace(/'|\\|\n|\r/g, function(match){
return safe[match];
});

// return an evaluable string
return "eval((function(p,l){return p.replace(/\\w+/g,function(k){return l[parseInt(k,36)]})})('" + packed + "','" + keywords.join(".") + "'.split('.')))";

// created string has to contain an inline function
// that should be able to return original code
// to eval function. Created string will be
// something like
// eval((function(packedString,keywords){return unpack(packedString,keywords)})("packed string", "key.words.list".split(".")))
};

This is our first home made client side compression example, not really so efficient, but good enough to understand the logic behind.


Merits of client side compression technique


It simply does not necessary require server side operations to optimize the result size of our scripts, that are every day more than ever "thanks" to the Web 2.0 era.
Required bandwidth will be less than before, while download speed will be increased, and more code we pack, more possibilities we have that ratio between source and packed code will be greater, thanks to common names for common tasks programming routines.


Defects of packed code


Nowadays, quite every browser supports gzip or deflate runtime decompression.
These compression algorithms are really efficient thanks to decompression speed, 10 to 100 faster than pure JavaScript operations plus evaluation, and thanks to their support provided by every server side program language.
Every time we download a client side packed code, even if file will be saved in browser cache, it has to be executed every time we will visit that page again.
So, if our goal is to increase page interaction speed during navigation, JavaScript decompression delay will be a problem.
If this problem will be hilarious or heavy, it depends only on client hardware and its browser performances.
At the same time, using a gzip or deflate compression over a packed code, will not truly increase performances and result will be bigger than clear code gzip compression.

The reason is that common compression algorithms create compressed code using a dictionary that will contain common, repeated, words or letters, found in original string.

Since JavaScript compressors usually replace numbers or words with a unique identfier to be able to recreate original string, resulted string will contain much more characters pairs than before and every baseN encoded key, that is not human friendly and for this reason rarely wrote in original code, could be one more byte inside final compressed string.

Finally, client side compressors are not, usually, 100% compatible with every kind of code, and this is another reason to prefer minifiers + gzip|deflate to obtain the best, fastest, and finally smallest, result.


Conclusion


Nowadays, pure JavaScript client side runtime decompression technique is not really a necessary, but in some case, it could do things that gzip or deflate will never be able to do, for example merging both JavaScript and CSS using a single and common keywords list to produce a unique file that could contain both JavaScript and CSS with the best size result requiring only 1 download instead of 2 (1 for JavaScript, 1 for CSS). That is what packed.it is able to do since 2007, but never forget speed issue and please remember that more great will be packed code, more delay there will be in every page that will use them.

Sunday, March 23, 2008

My 5 cents about JavaScript Prototypal Inheritance

Few days ago I read an interesting post about Simple JavaScript Inheritance.
The most hilarious thing is that prototypal inheritance is truly simple, as John wrote, but there are still a lot of developers that do not probably understand perfectly them.

In this link you can find an "all in one" page about JavaScript prototypal inheritcance and classical emulation.

As I wrote at the end of that page, please do not hesitate to correct me if there is something wrong, or please ask me more details if there is something that is not so clear.

Sorry for my not perfect yet English, and have fun with JavaScript.

(happy easter too!)

Friday, March 21, 2008

How to inject protected methods in JavaScript - Part II

As a performances maniac, I've found another way to inject protected methods, or something similar, without unnecessary overload of each public method.

Of course, precedent way is definitively more clear, linear, but if you have a constructor.prototype with a lot of private methods, the overload process will be a wall in front of method execution speed.

Each time you will use a public method, you have to set, and unset, every protected method, and at the same time, as explained in my precedent post, you cannot send the object outside during public method execution, because it will expose every method, protected included.

This new proposal is based on a Function like strategy, applied to instances: apply, and call. Please have a look at this prototype function:

function prototype(constructor, public, protected){
// webreflection - mit style
if(protected){
public.apply = function(callback, arguments){
return (callback.charAt(0) === "_" ? protected : this)[callback].apply(this, arguments);
};
public.call = function(callback){
return this.apply.call(this, callback, Array.prototype.slice.call(arguments, 1));
};
};
public.constructor = constructor;
constructor.prototype = public;
return public;
};

A usage example should be this one:

function MyMath(value){
this.value = value;
};
prototype(
MyMath,
{doStuff:function(){
return this.value * this.value;
}},
{_doStuff:function(){
return this.value + this.value;
}}
);

The first sent object will be the prototype of MyMath constructor, while the second one will contain protected methods.

About performances


As you can see in the simple prototype function, there's no override and no overhead for both public and protected methods. This means that you can use a public method directly and without problems:

var num = new MyMath(3);
num.doStuff(); // direct, fast as regular prototype


About protected methods


These simply "does not exists" :)

var num = new MyMath(3);
num._doStuff(); // error

Protected methods are not directly accessible even from instance itself. This means that these methods are safe and not mutable, if used object is created in a private scope, or runtime as showed before.

How to use protected methods



var num = new MyMath(3);
alert(num.call("_doStuff")); // 6

Apply and call, in this case, are used with instance to call a method that, if contain an underscore as first prefix char, will be one from protected prototype, otherwise will be one of the public prototype. Sounds weird?

// full example
function MyMath(value){
this.value = value;
};
prototype(
MyMath,
{doStuff:function(){
return this.value * this.value;
}},
{_doStuff:function(){
return this.value + this.value;
}}
);

var num = new MyMath(3);
alert([
num.doStuff(), // 9
num.call("doStuff"), // 9
num.call("_doStuff") // 6
].join("\n"));

num._doStuff; // undefined


Why do I call them protected


If everyone can call a method, it does not make sense to call them protected.
But this time, the meaning is not the same of classical inheritance, but it is more close to the word itself: proteced.

The main goal is to have a not common or usual way to call methods, specially for libraries developers.
Every API could be based on public methods, while authors could choose to call a protected method when their need them.
This is basically a transparent layer between the developer and the final user: who will use num.call("doStuff") when you can do this: num.doStuff() ?

I know I am not so good to explain my ideas, so I hope someone will find this useful. Have a nice easter ;)

Thursday, March 13, 2008

ABC - Ajax Basic Call

I know everyone uses incredibly cool libraries that do everything in few lines, and 30 or more Kb ... but do you always need all this stuff for simple Ajax interactions?

The JavaScript ninja secret is to create everything ad hoc, where everything will be under control and will be extremely optimized and, why not, fast.

ABC goals is to let you use, simply, Ajax.

What is Ajax in few words? The possibility to send and recieve data, usually using GET, POST, or both method (POST with a query stirng).

That's exactly what you can do with ABC, and these are major features:

  • simple, fast, lightweight ... probably the only function you need for 80% of Ajax tasks

  • unobtrusive, does not change, create, modify ... absolutely nothing

  • IE cache safe, forget IE cache problems without effort

  • array compatible, send single dimensional arrays too

  • easily integrable, using around your own cool code to send entire forms or whatever you need

  • quick but not dirty, and without global scope paranoia ... one function, every number of interactions you want, syncronous or asyncronous



Here some example code:

// basic asyncronous GET request
ABC(null, "page.php?hello=ABC");

// basic asyncronous POST request
ABC({hello:"ABC"}, "page.php");

// basic syncronous GET request
alert(
ABC(null, "page.php?hello=ABC", false).responseText
);

// basic syncronous POST request
alert(
ABC({hello:"ABC"}, "page.php", false).responseText
);

// basic syncronous POST with GET request
alert(
ABC({hello:"ABC"}, "page.php?query=string", false).responseText
);

These are only the beginning ... there's more, because we all love callbacks and asyncronous requests!

ABC({
parameter1:"Hello",
parameter2:"World",
list:[1,2,3,4,5],
onLoad:function(xhr, elapsedTime){
alert([elapsedTime, xhr.responseText]);
}
});

ABC({
parameter1:"Hello",
parameter2:"World",
list:[1,2,3,4,5],
onLoad:function(xhr, elapsedTime){
alert([elapsedTime, xhr.responseText]);
},
onError:function(xhr, elapsedTime){
alert([elapsedTime, xhr.status]);
}
});


Both onLoad and onError are optional callbacks ... and that's basically how ABC works to choose GET or POST method:

  1. If first argument is null, or it does not contain object properties that are not functions, the request is GET

  2. If first argument contains an object with at least one parameter that is not an Object prototype and is not a function, the request is POST

  3. If third arguments is not present or is undefined, request is syncronous by default

  4. If third arguments is true or false like (1, 0, "ok", undefined or null), the request will be asyncronous if true, syncronous if false (basic XMLHttpRequest behaviour)
  5. If you pass fourth and/or fifth argument, these are user and pass



The good thing is that you have exactly same parameters that a regular XMLHttpRequest instance wants in open methods. This basically means that migration between some code will be ridiculously simple.

On the other hand, ABC is simple and is perfect for simple things.
Of course if you need more features ... you are higher level than ABC ... but for every other client / server interaction, are you sure you need every time so many features?

This is the source, and this is the packed.it version ... about 0.66Kb (deflate) ... and that's it! Enjoy Ajax :geek:

Wednesday, March 12, 2008

Do You Like Browser Benchmarks? Here I am!

Hi guys,
today we will not talk about my last JavaScript ArrayObject creation :D

Today is the benchmark day, and in this case the test is as simple as explicative ... both Math object and scope are two things we use every day for whatever purpose in this baby Web 2.0 era!

Let me start directly with results (ORDER BY speed ASC):

Firefox 3.0b4
----------------------------------
regular avg time in ms: 9.98
scoped avg time in ms: 3.18
encapsulated avg time in ms: 12.98


Safari 3.0.4 (523.15)
----------------------------------
regular avg time in ms: 13.42
scoped avg time in ms: 6.42
encapsulated avg time in ms: 11.82


Opera 9.24
----------------------------------
regular avg time in ms: 13.82
scoped avg time in ms: 9.6
encapsulated avg time in ms: 17.64


Internet Explorer 8.0.6001.17184
----------------------------------
regular avg time in ms: 16.42
scoped avg time in ms: 6.82
encapsulated avg time in ms: 16.82


Firefox 2.0.0.12
----------------------------------
regular avg time in ms: 26.84
scoped avg time in ms: 42.06
encapsulated avg time in ms: 28.64


What kind of benchmark is it?

This is a double test that includes the usage of scoped shortcuts, and the usage of the object that you cannot absolutely get by without: the global Math one!

To understand better this kind of test, please look at these functions:

function regular(){
for(var i = 0, time = new Date; i < 10000; i++)
Math.round(i / Math.PI);
time = new Date - time;
return time;
};

function scoped(){
for(var round = Math.round, PI = Math.PI, i = 0, time = new Date; i < 10000; i++)
round(i / PI);
time = new Date - time;
return time;
};

function encapsulated(){
with(Math){
for(var i = 0, time = new Date; i < 10000; i++)
round(i / PI);
time = new Date - time;
};
return time;
};


The first one, is the most common in every day libraries / scripts, while the second one and the third one, are used by "a little bit more skilled" developers.

The second one, uses the same concept of my good old friend, the smallest FX library from 2006: bytefx

The scoped schortcut is absolutely the fastest way to use a global objet, constructor, whatever you want.

Just think about nested scopes, this amazing ECMAScript 3rd Edition more close to future than many other new program languages ... ( IMO, and sorry for exaggeration :lol: )

When you write the name of something in your scope, the engine looks obviously in the same scope, than in the external one, going on until the super global object, the window

This behavior is basically what should happen using the with statement as well ... but unfortunately, even if this is basically what's up, performances are clearly against the usage of absolutely comfortable with statement.

At the same time, there is one browser that you are probably using right now, that create a bit of confusion about everything I've just said right now: Firefox 2

With quite twice of time, using scoped shortcuts, this browser (the best I've ever used for years, and the one I'll use for other many years) reverse totally my conviction about how does scope work ... anyway, we are lucky because Mozilla staff is creating good stuff with Firefox 3 ... who cares about Firebird and other old versions? :D

Don't you really trust me and my results?
So do this bench by yourself :geek:

Tuesday, March 11, 2008

Sorry Dean, I subclassed Array again

Most library authors would love to extend the Array object (especially for those tasty iteration methods) but shy away from doing so for fear of breaking other scripts. So nearly all (with the noteable exception of Prototype) leave Array and other built-in objects alone.

This is how Dean Edwards started one of his (historic) post about subclassing Array, but I finally found the way to do it better, and You'll read why and how ... please be patience :D

The nightmare does not come only from IE


We all know how weird is Internet Explorer when you try to use an array as a constructor prototype.
What you probably do not know yet, is that IE is the only one that gives you problem "instantly instead of during". Let's start with the first, basic example:

// FireFox and Safari, plus IE, why not

function MyArray(){};
MyArray.prototype = [];

/** this should be a must ... however, who cares about that ...
MyArray.prototype.constructor = MyArray;
*/

var ma = new MyArray;
ma.push(1,2,3);
alert(ma); // 1,2,3 ... seems good, isn't it?

// now, lets use our Array thinking it's an array
var a = new Array(4,5,6);

// now, for some reson you should use your
// personal Array as is ... an Array, are you sure?
a.push.apply(a, ma);

/*
second arguments to Function.prototype.apply
must be an array

expected object or arguments

type error ...
*/

Well done ... we cannot use an instance that inherits from Array as an Array. The only one that seems to be clever enough to understand that ma is basically an Array, is Opera, well done Opera Team!.

The unespected instance


Another weird situation, using precedent constructor as example, is this one:

// Every browser you can try ...

function MyArray(){};
MyArray.prototype = [];

var ma = new MyArray;
alert(ma.concat(ma) instanceof MyArray); // false

false ??? ... What does it mean, false ?
False means that if we should be able to subclass an Array with IE too, there's no browser so clever to understand that internal methods should create an instance of the same constructor ... ok, ok, it's more close to ED209 in Delta City than reality ... anyway ...

I would like to obtain an instance of my constructor, and not an array.
This simply because we could extends whatever we want and after we use every native method, so fast and so powerful, we basically will lose our enhanced constructor coming back to a native Array.

In few words, if we should be able to extend Array, we should create wrappers for every method that returns, natively, an Array ... who talk about performances?
Just think that every this.slice() inside our prototypes should convert again the result if we would like to threat them as an instance of our super extended Array. ... does it sound still cool?
map, filter, sort, reverse ... and many others!

A clever solution, that noone seems to like so much


Basically, Dean found a solution that's clever and simple at the same time.
This one has not been used so much by libraries developers ... but why?
What I could suppose, is that there are a lot of limits:

  1. it depends on iframe creation, while JavaScript could be used everywhere, not only when an element is ready to recieve an iframe inside

  2. an iframe could means a lot of problems, specially in https sites, where some browser (of course IE) has a sort of paranoia if the iframe does not contain an src that points to a file in the same domain ... and sometime, even an empty html file to use as sentinel for empty iframes could be boring ...

  3. the iframe solution, has the same problem than Array extension ... if you want more power with native methods too, you have to wrap them!



Here is an example:

// directly from Dean Edward page
onload = function(){
var iframe = document.createElement("iframe");
iframe.style.display = "none";
document.body.appendChild(iframe);
frames[frames.length - 1].document.write(
"<script>parent.Array2 = Array;<\/script>"
);

// let's play
var a = new Array2(1,2,3);
alert(a); // 1,2,3 ... Yes!
alert(a.concat([4,5,6]) instanceof Array2); // FALSE AGAIN!!!
}


bloody hell, why the native concat method of my Array2 constructor returns an Array?

No way, if You use a native prototype, its behavior will be the expected one for current enviroment ... so as new Array ported inside the iframe will generate an instance of Array2 for every method that returns a partial or full copy of the Array.

More light in the black hole, please


Even if I agree with Dean when He says

shy away from doing so for fear of breaking other scripts. So nearly all (with the noteable exception of Prototype) leave Array and other built-in objects alone.

(removing the notable exception) ... I think that sometime prototypes could save our work, avoiding huge brainstormings to find alternative solution.

Array.prototype.to


Exactly, a stupid, short, simple, damned Array.prototype that has this goal:
Transform an Array like instance into a generic Array like instance (does it sound redundant?).

Array.prototype.to = function(constructor){
if(this instanceof constructor)
return this;
var self = new constructor;
Array.prototype.push.apply(self, Array.prototype.slice.call(this, 0));
return self;
};

This prototype could solve every kind of Array like transformation problems.

Do You need a jQuery from an Array ?

[document.body, document.getElementById("test")].to(jQuery).each(
function(element){
// do whatever stuff
});

You can use this stupid prototype to transform your results as well, but basically, you can use this prototype for every kind of Array like object.

jQuery.prototype.to = Array.prototype.to;
jQuery("input").to(Array).sort(function(el1, el2){
return el1.value < el2.value ? -1 : 1;
}).to(jQuery).doStuff();

Performances are really good, and compatibility is excellent. Starting from IE 5.5 and more, adding your own little simple push prototype plus a Function.prototype.call ... and you'll have support for IE4 too, even if this will not do make sense!

I know that a prototype to a global native variable is never a good thing to assing, but:

  1. Array or Array like objects (arguments) are often (always?) looped using their length and not using for in

  2. if you want to add aprototype, why do not add one that is strictly related with the same constructor and cosntructor like objects?



ArrayObject, and my last call for a truly subclassed Array


Thanks to precedent idea, the Array.prototype.to, I totally redraw my ArrayObject, now compatible with quite every JavaScript 1.6 method without other dependencies, and finally extendible in the most simple possible way, to create your own Array like library. Do you want an example?

// first of all, your constructor
function MyArrayLikeLib(){
// be sure that basic behavior is Array like
// using ArrayObject constructor
ArrayObject.apply(this, arguments);
};

// extend your constructor with an ArrayObject instance
MyArrayLikeLib.prototype = new ArrayObject;

// finally, add one or more prototypes to your personal
// constructor ... but DO NOT FORGET the constructor!
MyArrayLikeLib.prototype.constructor = MyArrayLikeLib;


var demo = new MyArrayLikeLib(1,2,3);
alert(demo); // 1,2,3
alert(demo.concat(new MyArrayLikeLib(4,5,6))); // 1,2,3,4,5,6
alert(demo.concat(new MyArrayLikeLib(4,5,6)) instanceof ArrayObject); // TRUE
alert(demo.concat(new MyArrayLikeLib(4,5,6)) instanceof MyArrayLikeLib); // TRUE


Thanks to the to prototype, natively created in the ArrayObject itself, you will recieve for every method that returns an array like object, an instance of your constructor.

How can it be possible?

// one ArrayObject prototype method, the slice one
slice: function(){
return Array.prototype.slice.apply(this, arguments).to(this.constructor);
}

It's diabolic simple if you remember to assign the real constructor to the prototype!

How to add prototype methods to ArrayObject inherited constructor


Uhm ... this is quite a newbie question, isn't it? :lol:
However, just forget the new Object assignment, or use the object in a different way:

function A(){ArrayObject.apply(this, arguments)};
A.prototype = new ArrayObject;
A.prototype.constructor = A;
(function(prototype){
for(var key in prototype)
A.prototype[key] = prototype[key];
})({
doMyStuff:function(stuff){
this.push(stuff);
return this.sort();
},
each:function(callback){
this.foreach(callback, this);
}
});


A simple benchmark


This page contains some simple speed challenge between native Array and ArrayObject.
Of course in some case ArrayObject is a bit slower, specially with Safari beta for widnows, but those are the worst case scenario, where for compatibility and unexpected behaviors reason I had to put more code, while every, forEach, indexOf, join, lastIndexOf, pop, push, reverse, shift, and finally some, are native when your browser is cool, are compatible and fast enough, when your browser is IE.

The bad news, what You cannot do with ArrayObject


You know, arguments is exactely an ArrayObject like variable ... and what's up if you do something like this?

function length(){
for(var i = 0; i < 3; i++)
arguments[arguments.length] = i;
alert(arguments[0]); // 2
alert(arguments[1]); // undefined
};

length();

You cannot use the length as a getted/setted property as is for native Arrays, but hey, you have native push method, why should you use the length in that way?
(speed? ... if you think that will boost up your applications, use native Arrays inside those loops, and finally convert them.to(ArrayObject)) ;)

Kind Regards


P.S. just another tricky usage of Array.prototype.to

function args2arr(){
arguments.to = [].to;
return arguments.to(Array);
};
alert(args2arr(1,2,3)); // 1,2,3

Thursday, March 6, 2008

Jaxer and packed.it ... not possible yet

Unfortunately, my experience with Jaxer has been really cool but this project is too young to be used as a server side project, and this is only my opinion.

First of all, the simple File API is great, but if you look for binary safe in the search form, you'll be redirect in an empty page ... quite hilarious, isn't it?!

Anyway, I did not test the file.open("wb") mode, probably it's working, probably not ... who care about that? Me, because to pre compile packed.it projects using MyMin and then Zlib I need to write in binary mode ... no way guys!

At the same time, there's not a true bridge for Java, at least that what I was looking for, since Jaxer could be integrated with TomCat, I wonder what are they waiting for to create an easy interface to call directly Java, or whatever mature server language you want.

It will be an extreme start up improvement for your project, what's not possible yet, will be with some Java, Mono, Python, Ruby, PHP, or whatever is it, wrapper.

Is this in your roadmap? None, I can read about DRW but come on guys, the server before the client!

You can have the best Ajax based solution on client, but if the server could do things that a basic PHP / JS interaction could do since 2000 or before, I wonder why you are putting so much effort on client side, where we have a lot of choice, while what we do not have, is simply Jaxer, but on server ;)

Finally, good stuff, and good project, I wish you all the best but please, think about Ajax after a good bridge ... and of course, I eat JavaScript in the morning and I compile them during the night :lol: ... are you still looking for a JS ninja ?

Enjoy Jaxer, at least for fun, this project will become awesome the day it will integrate JS2 engine!


P.S. I created a parseIni method as well ... this is not probably perfect but hey, about 20 minutes debug included :geek:

MyMin = {Creator:function(){}};
MyMin.Creator.prototype.parseValue = function(value){
var result;
switch(true){
case value instanceof Array:
result = [];
for(var i = 0, length = value.length; i < length; i++)
result[i] = this.parseValue(value[i]);
break;
case /^true$/i.test(value):
result = true;
break;
case /^false$/i.test(value):
result = false;
break;
case /^[0-9]+$/i.test(value):
result = parseInt(value);
break;
case /^[0-9]*\.[0-9]+$/i.test(value):
result = parseFloat(value);
break;
default:
result = value;
break;
};
return result;
};
MyMin.Creator.prototype.parseIni = function(fileContent){
var self = this,
pos = 0,
result = {},
trim = /^\s+|\s+$/g,
section,
name,
value;
while(pos < fileContent.length){
pos = fileContent.indexOf("[");
if(pos < 0)
break;
fileContent = fileContent.substr(++pos);
pos = fileContent.indexOf("]");
if(pos < 0)
break;
section = fileContent.substr(0, pos++);
if(!section)
continue;
fileContent = fileContent.substr(pos);
pos = 0;
result[section] = {};
fileContent.replace(/(\[.+\]|.+=[^;\n\r]+)/gm, function(match, sub, p){
if(pos === 0 && /^\[.+\]/.test(match))
pos = p;
else if(pos === 0){
value = match.split("=");
name = value[0].replace(trim, "");
if(/\]$/.test(name)){
name = name.substr(0, name.indexOf("["));
if(!result[section][name])
result[section][name] = [];
result[section][name].push(self.parseValue(value[1].replace(trim, "")));
}
else
result[section][name] = self.parseValue(value[1].replace(trim, ""));
}
});
fileContent = fileContent.substr(pos);
pos = 0;
};
return result;
};

Wednesday, March 5, 2008

Turbo ArrayObject

Today I am more clever than two days ago :lol: ... that's why ArrayObject has now a turbo compressor, specially with those methods that do not require an intermediate wrapper:

  • every

  • forEach

  • indexOf

  • join

  • lastIndexOf

  • pop

  • push

  • reverse

  • shift

  • some



These methods, if susported (if not use JSLRevision ;)), works directly in core.
The result is that every Array like instance now are more fast than ever, considering that join, pop, push, reverse, indexOf, shift, and forEach are widely used in a lot of projects.

This object could be the core for libraries like jQuery, or other that emulates array behaviour ... and I solved problems with sort plus some minor fix.

It has been successfully tested in FireFox, IE, Safari, and Opera.

Seems cool? I hope so :geek:

Sunday, March 2, 2008

JavaScript ArrayObject

I think this constructor could be a good start point for a lot of projects.

We know that IE has problems while it try to extend an array, disabling length modification.

That's why I have created this wrapper that does not require weird strategies (e.g. iframe with a different enviroment) and works with a wide range of browsers.

Honestly, I did not test performances against pure arrays, but I did everything to make code as fast as possible, using good practices and creating an in-scope shortcut for the Array.prototype.

Have a look here if you are interested in this constructor, ignore them if you do not think this is a good idea :)

P.S. Please note that this constructor does not care about missed prototypes, it only does its wrapping work and nothing else. To improve Array compatibility and methods, please remember my JSL Revision. Including them in your page, You'll not have problems with every ArrayObject method, eccept for reduce and reduceRight (I will create a good implementation of those function, I promise!)