srijeda, 25. srpnja 2007.

anonymous function prototype

There are several scripts that use anonymous functions and we often use them as regulars.
Is there a way to have different or dedicated prototypes for this kind of function ?

Step 1, what is anonymous function ?
The "original" anonymous function is returned from the global Function object.
var    myFunc = new Function("a", "b", "c", "return a + b + c;");
alert(myFunc(1,2,3)); // number 6

myFunc is a function with all Function prototypes or native methods and with the same constructor of a function.
Then myFunc is absolutely a function, but wich kind of function is it ? Exactly this one:
function anonymous(a, b, c) {
return a + b + c;
}

What's that ? That's a function that exists but you can't modify, get, or extend anyway because each new Function will produce a different referer for a different anonymous function.
(new Function).prototype.isAnonymous = true;
alert((new Function).isAnonymous); // undefined

You can try in a different ways creating for example a personal anonymous function, but the result will be the same ...
var anonymous = new Function;
(new Function).prototype.isAnonymous = true;
alert((new Function).isAnonymous); // undefined

// other way

function anonymous(){};
anonymous.prototype.isAnonymous = true;
alert((new Function).isAnonymous); // undefined

That's becaus, as I've just said, every anonymous instance is different from every other.
With FireFox you should view this difference using toSource Obect native method.
function anonymous(){};

var realanonymous = new Function;

alert([
anonymous.toSource(), // function anonymous() {}
realanonymous.toSource(), // (function anonymous() {})
anonymous === realanonymous // false
]);

As you can see, those parentheses are the key to understand the anonymous function.




Step 2, parentheses and virtual scope
At this point we know that an anonymous functions cannot have dedicated prototypes and aren't like regular functions too.
In some script you can see the use of parentheses to call runtime a function or to create one.
This code, for example, is an unobtrusive way to add a personal String prototype.
String.prototype.toArray = (function(base){
return base || function(){return this.split("")}
})(String.prototype.toArray);

alert("test".toArray()); // t,e,s,t

Let me explain this few lines of code.
If some script, before this one, has just defined a String.prototype.toArray or browser has a native String.toArray function, the anonymous function created using parentheses and directly called with (String.prototype.toArray) that accepts, if present, the base function, will assign to that prototype old version (base) or, if base is not defind, our prototype function (function(){return this.split("")}).
The closed anonymous function is then a special function and its really usefull to solve a lot of problems.
This is only a little example but I think you used anonymous functions every day with every scripts ;)
Since the scope inside parentheses "magically disappear", but neither for itsself nor for its internal scope, we can think that those kind of functions are exactly anonymous.
var    myAnonymous = (function anonymous(){}),
realAnonymous = (new Function);

alert([
myAnonymous, // (function anonymous(){})
realAnonymous, // (function anonymous(){})
myAnonymous === realAnonymous, // false
myAnonymous.toSource() === realAnonymous.toSource()
// true !!!
]);


Step 3, how to create a dedicate prototype
JavaScript is Object Oriented and each function is an object, then why I couldn't use "special" anonymous functions as an object ?
That's why I've created a simple solution to have customizable anonymous functions, every one will be different from every other, but everyone will have our dedicate prototypes.
This is the concept function
// anonymous explicit function
function anonymous() {

// prototype to prototype,
// this function copy each a prototype (p) to other (b) function
function p2p(p,a,b) {

// using prototype for b too isn't a good solution (imho)
// because only new anonymous will has these prototypes
for(var k in a[p])b[k] = a[p][k];
return b;
};

// we need arguments and its length plus a genric array
var l = arguments.length, a = [];

// if argument is not one or its not a function
if(l !== 1 || arguments[0].constructor !== Function) {

// create the string ([arguments[N],...,arguments[0]])
while(l)a.push("arguments[".concat(--l,"]"));

// then reverse ...
a.reverse();

// ... to assign anonymous function to arguments 0
eval("arguments[0]=new Function(".concat(a.join(","),")"));
}

// return its "prototyped" version of anonymous function
return p2p("prototype", arguments.callee, arguments[0]);
};

The major difference from native new Function(arguments) is that my anonymous function accpets an anonymous function too.
Here there's a complete test to view some application.
// anonymous explicit function
function anonymous() {
function p2p(p,a,b) {
for(var k in a[p])b[k] = a[p][k];
return b;
};
var l = arguments.length, a = [];
if(l !== 1 || arguments[0].constructor !== Function) {
while(l)a.push("arguments[".concat(--l,"]"));
a.reverse();
eval("arguments[0]=new Function(".concat(a.join(","),")"));
}
return p2p("prototype", arguments.callee, arguments[0]);
};

// common Function prototype
Function.prototype.isFunction = true;

// only anonymous prototype
anonymous.prototype.isAnonymous = true;

// first test --------------------------------------
// new anonymous creation with the same sintax of new Function
test = anonymous("str", "alert(str)");

// just few checks
alert([
"" + anonymous.isAnonymous, // undefined, anonymous is a function
"" + test.isFunction, // true, test is a function
"" + test.isAnonymous // true, test is an anonymous function
]);

test("Hello World!"); // Hello World! [then test works perfectly]
// _________________________________________________



// second test --------------------------------------
// common function declaration using anonymous
test = anonymous(function(str){alert(str.toUpperCase())});

// just check it
alert([
"" + test.isFunction, // true, test is a function
"" + test.isAnonymous // true, test is an anonymous function
]);

test("Hello World!"); // HELLO WORLD! [then test works perfectly]
// _________________________________________________



// third test --------------------------------------
alert(anonymous(function(){}).isAnonymous); // true
// _________________________________________________



// final test --------------------------------------
anonymous(function(a){alert(a + arguments.callee.isAnonymous)})("Anonymous ? ");
// true
// _________________________________________________

Just a look at the last test, where is used arguments.callee instead of "this".
That's simply why the "this doesn't exists" inside the function ("this" inside a function is the window object).

anonymous function to add simple events

This post shows a simple anonymous function application example, a fake addEventListener.
We often use directly the method with the document element, it's simple and fast, then often our preferred way to implement an event.
I'm talking about this code
document.getElementById("myId").onclick =
function(){alert("hello")};


DOM and standars like this method to add an event
document.getElementById("myId").addEventListener(
"click",
function(){alert("hello")},
false
);


But IE doesn't implement addEventListener method (what a news ...)
document.getElementById("myId").attachEvent(
"onclick",
function(){alert("hello")}
);


The attachEvent has different problems, it isn't a standard method (then IE and few other browsers supports that) and the scope inside the callback is not the element.
This code, for example, doesn't work as expected:
document.getElementById("myId").attachEvent(
"onclick",
function(){alert(this.className)}
);


I've implemented the addEventListener in my big dollar function but often developers doesn't like "big" external libraries (scriptacolous as prototype and Dojo are some exceptions).
That's why I'm writing this simple function to add an event directly to an element, using generic on* event names.
function addSimpleEvent(
obj, // the object (i.e. window, document, element)
type, // the type (i.e. "onload", "onmouseover", "onclick")
callback // the callback (i.e. function(){alert(this)})
) {
obj[type] = (function(base){ // anonymous function
return function(evt){ // function called on event
if(!evt)evt=window.event; // event for IE browsers
if(base)base.call(this,evt); // old function, if defined
callback.call(this,evt); // callback
}
})(obj[type]) // old defined (or not) function
};

This function uses anonymous function to preserve old event (base variable), if presents, and calls every callback with the element scope (using call).
This is an example:
// imagine that other script did it ...
onload = function(){alert("Hello 1")};

// addSimpleEvent function
function addSimpleEvent(obj,type,callback) {
obj[type] = (function(base){return function(evt){
if(!evt)evt=window.event;
if(base)base.call(this,evt);
callback.call(this,evt);
}})(obj[type])
};

// you can add one, two or more events
addSimpleEvent(window, "onload", function(){alert("Hello 2")});
addSimpleEvent(window, "onload", function(){alert("Hello 3")});


// if you want, you could create another function to add multiple events of same type
function addMultipleEvents() {
for(var i = 2, j = arguments.length; i < class="jshoperators">++)
addSimpleEvent(arguments[0], arguments[1], arguments[i]);
}

// and use it in this way
addMultipleEvents(window, "onload",
function(){alert("Hello 4")},
function(){alert("Hello 5")},
function(){alert("Hello 6")}
);

Just test this script to view this sequence of alerts

Hello 1
Hello 2
Hello 3
Hello 4
Hello 5
Hello 6

What's about compatibility ? Every browser that supports call and doesn't loose base variable during execution, then IE 5.5+, FireFox, Opera, KDE, Safari and many others.

I hope this little function will be usefull for you window, document, or element common events.

Are speed tests really usefull for developers

Yesterday my favourite portal HTML.it has posted a speed test inside its blog.
This JavaScript benchmark was posted on this site.

I think that those kind of tests are only a "point of view" and aren't comparable with real javascript usage.
As I've showed on my for and while loop test, every operation is a single case to analize and every single case has not everytime the same result.

For example using a for and an <= expression with every loop should be faster in some browser and should be slower in some other.
Then it's not always a good way to compare some internal loop operations because a browser should be faster to push a string inside an array but should be slower to execute that kind of for loop.

Often speed depends on garbage collector too, that should be faster in some point of execution and slower in some other.

These concept are true with every other benchmark of that site.

Math engine, as Ajax declaration, are faster with FireFox and really bad with IE because the object has a dedicated try catch for every IE browser.
I usually don't use that way to declare an XMLHttpRequest then my library should be faser than Opera with IE too.
If you change some piece of execution code, you can see that IE6 or 7 is even slower than FireFox with some function.

What I mean is that a real "every day" application will "never" use 4000 try catch but should use a lot of Math operations and DOM elements using many array and Ajax declarations too.
Every Ajax object or class should be simple or really complex and some browser should declare it faster or slower than other one.

Another generic relevant thing is code optimizzation ... you could use "only Opera" to surf the web but if a library contains bad practices its code execution will be slow in every case.

And again, the use of "var" before every temporary variable should be slower or faster, look at the MathEngine function ... is this usefull ?
is this a real application example ?

The StringFuncs has 2 operations that are only for human eyes because if you don't call those functions how can you test them ?
str.toLowerCase;    // yeah! a string has a toLowerCase prototype ..
str.toUpperCase; // yeah! a string has a toUpperCase prototype ..

// P.S. I think that He's just forgot it :)


A "StringBuilder" function should be a better test too because every JS developer knows that using string += something isn't a good speed practice and the use of concat instead of '+''+''+''+''+' ... is faster too.
A StringBuilder operation is not different from array.push, but doesn't use sort and reverse as ArrayFuncs does.

Is a StringBuilred competition another usefull test to do ? I think that ...
function StringBuilder() {
function StringBuilder() {
this.append = function(what){
arr.push(what);
};
this.toString = function(){
return arr.join("");
};
var arr = [""];
};
var startTime = getTime(), i = 4001, sb = new StringBuilder;
while(i--)
sb.append("a piece of code".concat(i));
sb = sb.toString();
var endTime = getTime();
getElement('speed_sb').innerHTML = (endTime - startTime);
getElement('speed_total').innerHTML = eval(getElement('speed_total').innerHTML) + (endTime - startTime);
};


... and Should we care about few milliseconds ?

Then this is what I think: these speed tests are a must only for Rhino or SpiderMonkey developers because a javascript developer doesn't need to care about performances (in this way) ... He needs to care about generic code optimizzations using lightweight code implementations without redundant operations inside a cross-browser code.
That's what a developer should care about, not dedicated speed test for this or that function.

Running with a Number

I think this post is only for basic JS developers and shows how a simple function or a simple operation should be wrote in different ways.
In this specific case, I would talk about logic used for a single function while I was optimizing bytefx.

The problem
I've two numbers, x and y, I need to change x, adding or removing a "speed" value, while x is not equal to y.

This simple problem has a lot of solutions. This is probably the simplest one:
function xRun2y(x, y, speed) {
// check wich number is greater than other one
if(x < y) {

// ok, x is less than y ... then add speed
x += speed;

// x can't be greater than y ...
// x can be only less than y ... or equal
if(x > y)
x = y; // stop run
}

// other case, x is greater than y
else if(x > y) {

// well, in this case we remove speed from x
x -= speed;

// but x can't be lower than y ... then ...
if(x < y)
x = y;
}

// we don't need to care about x == y
// just return x
return x;
};

As you can see by yourself, this simple function could create a range of numbers from Nstart to Nend.
This is an example:
// from 10 to 0
var start = 10, end = 0, speed = 1,
arr = [];
while(start !== end) {
start = xRun2y(start, end, speed);
arr.push(start);
};
alert(arr); // 9,8,7,6,5,4,3,2,1,0

// from 0 to 10
var start = 0, end = 10, speed = 1,
arr = [];
while(start !== end) {
start = xRun2y(start, end, speed);
arr.push(start);
};
alert(arr); // 1,2,3,4,5,6,7,8,9,10

These operations should be usefull to move an element, to change some value from a startPoint to endPoint ... but, as i've said, there are different ways to do that.

This way is, for me, a better way to write the same function.
function xRun2y(x, y, speed) {

// check wich number is greater than other one
if(x < y)

// with a ternary operator we can do everything inline
x = x + speed > y ? y : x + speed;

// other case, x is greater than y
else if(x > y)

// well, in this case we remove speed from x
x = x - speed < class="jshoperators">? y : x - speed;

return x;
};

Simple ? Clear ? ... I like this way as I like ternary operator, it's a must to write compact but efficient code.
However, look at this last function ... don't You see something strange ?
If and else if do exactly same operations ... only plus sign and greater than are diferent.
How we could create these similar operations in a single line ?
Using eval, sure !
function xRun2y(x, y, speed) {
var temp = x < class="jshoperators">? ["+", ">"] : ["-", "<"];
return eval("x".concat(temp[0], "speed", temp[1], "y?y:x", temp[0], "speed")); };

Yess !!! ... seems perfect ? ... or seems the evil ? Let me explain that :)
function xRun2y(x, y, speed) {

// we need to create dedicated ternary operation
var temp = x < class="jshoperators">?

// if x is lower than y we need to add speed
// and verify that x + speed is not greater than y
["+", ">"] :

// in other case we need to remove speed from x
// and check if x is not lower than y
["-", "<"];

// if x is lower than y this string is:
// x + speed > y ? y : x + speed
// else if x is greater than y ...
// x - speed < y ? y : x - speed
return eval("x " + temp[0] + " speed " + temp[1] + " y ? y : x " + temp[0] + " speed"); };

... simple ? cool ? ... no, it's not cool !
Eval in this case isn't absolutely dangerous or a problem while ternary operator is.
The answer is simple, we have reduced code size with a simple and fast function but we do everytime two operations.
These are x + speed or x - speed in both cases duplicated.
It's true, a simple addiction shouldn't be a problem for code execution, but if there's a way to use a better function, why we shouldn't use that ?
function xRun2y(x, y, speed) {

if(x < y)
// we need minimum value because
// if x + speed is greater than y
// we want y
x = Math.min(x + speed, y);

else if(x > y)
// we need maximum value because
// if x - speed is lower than y
// we want y
x = Math.max(x - speed, y);

return x;
};

Final solution
We don't care about case x == y but an operation like this one Math.min(1,1) returns 1 and not an error than why we couldn't use ternary operator ?
function xRun2y(x, y, speed) {
return x < class="jshoperators">? Math.min(x + speed, y) : Math.max(x - speed, y);
};

Do you think this is the best way to run from a Number to another ? I think so :)

bytefx less than 3Kb ? ... NO, less than TWO

What an incredible compressor ... i didn't know it but seems really really a good compressor !!!
I'm talking about memtronic javascript compressor that allows me to pass from about 2.7 Kb into 1.98 Kb (with comments) !!!

Sure, it's not a big difference from Dean Edward packer but now I can say that I've created an FX library in exactly 1.889 byte (without comments) ... it's hilarus for me, I didn't know that some compressor was able to reduce size in this way.

Thank you memtronic !!! Your compressor is fantastic !!!
 

parapeta alexferris briansvadowsky richard sam tony david frankpdas chris bravetina