Too much recursion 

Higher Order Javascript

 



   Subscribe in NewsGator Online    Subscribe in Rojo    Add to Google      Add to My AOL   Subscribe in FeedLounge   Add to netvibes  

Brendan Eich's Roadmap  Standard ECMA-262  www.schillmania.com  www.quirksmode.org 
www.snook.ca  www.davidflanagan.com  www.kryogenix.org  www.thomasfrank.se 
www.dustindiaz.com  Yahoo! UI Library  www.crockford.com  www.brainjacked.com 
chadlindstrom.ca  www.browserland.org     
       

Saturday, September 23, 2006

 

IE 5.5 IE6.x Transparent PNG fix + Mimified Brothercake Browser Detect


IE png fix. Works well. Included with a condensed/optimized version of Brothercake's Browser Detection Script. Read comments for use with or without browser detection.

// minified Brothercake browser detection object (thanks bro!)
// usage: alert(Browser.browser+'\n'+Browser.version+'\n'+Browser.OS)
var Browser = {
init: function () {
this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
this.version = this.searchVersion(navigator.userAgent)
|| this.searchVersion(navigator.appVersion) || "an unknown version";
this.OS = this.searchString(this.dataOS) || "an unknown OS";
},
searchString: function (data) {
for (var i=0,len=data.length;i var dataString = data[i].string, dataProp = data[i].prop;
this.versionSearchString = data[i].versionSearch || data[i].identity;
if((dataString) && (dataString.indexOf(data[i].subString) != -1)||(dataProp)){
return data[i].identity
} } },
searchVersion: function (dataString) {
var index = dataString.indexOf(this.versionSearchString); if (index == -1) return;
return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
},
dataBrowser: [
{string: navigator.vendor, subString: "Apple", identity: "Safari"},
{prop: window.opera,identity: "Opera"},
{string: navigator.vendor, subString: "iCab", identity: "iCab"},
{string: navigator.vendor, subString: "KDE", identity: "Konqueror"},
{string: navigator.userAgent,subString: "Firefox", identity: "Firefox"},
{string: navigator.userAgent,subString: "Netscape",identity: "Netscape"},// for newer Netscapes (6+)
{string: navigator.userAgent,subString: "MSIE", identity: "IE", versionSearch: "MSIE"},
{string: navigator.userAgent,subString: "Gecko", identity: "Mozilla", versionSearch: "rv"},
{string: navigator.userAgent,subString: "Mozilla", identity: "Netscape",versionSearch: "Mozilla"}],// for older Netscapes (4-)
dataOS : [
{string: navigator.platform, subString: "Win", identity: "Windows"},
{string: navigator.platform, subString: "Mac", identity: "Mac" },
{string: navigator.platform, subString: "Linux", identity: "Linux" }]
};
Browser.init();

// IE PNG FIX: correctly handle PNG transparency in Win IE 5.5 > 6.x
if((Browser.version>5.4) && (Browser.version<7) && (Browser.browser=='IE')){
// uncomment line below and comment line above to become independent of browser detect script
//if(window.attachEvent && (parseFloat(navigator.appVersion.split("MSIE")[1])<7)){
window.attachEvent("onload",function(){ if (document.body.filters){
var i=document.images.length; while(i--){
var img = document.images[i], imgName = img.src.toUpperCase();
if (imgName.substring(imgName.length-3, imgName.length) == "PNG"){ var
imgID = (img.id) ? "id='" + img.id + "' " : "",
imgClass = (img.className) ? "class='" + img.className + "' " : "",
imgTitle = (img.title) ? "title='" + img.title + "' " : "title='" + img.alt + "' ",
imgStyle = "display:inline-block;" + img.style.cssText;
if (img.align == "left") image.align='left'; //imgStyle = "float:left;" + imgStyle
if (img.align == "right")image.align='left'; //imgStyle = "float:right;"+ imgStyle
if (img.parentElement.href) imgStyle = "cursor:pointer;" + imgStyle
img.outerHTML= " + " style=\"" + "width:" + img.width + "px; height:" + img.height + "px;" + imgStyle + ";"
+ "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader"
+ "(src=\'" + img.src + "\', sizingMethod='scale');\">
"
} } } } ) };

 

Function.prototype.toEvent (bindAsEventListener)


Function.prototype.toEvent

Function.prototype.bindEventListener

This one keeps this and sends event object as the first argument (no more checking!). It also has only one parameter or parameters maybe- the argument/s you want to send to your function. Thats it! Bonus: the last argument is the co-ordinates of the event.
Explanation:Say you want to attach an onclick event to a button with id of 'myBut':
document.getElementById('myBut').onclick=
So far so good. Lets make a function for it to connect to. Remember, the first argument of an event is e. (IE doesn't use that, but we've made IE act like the rest now). Notice how this is our button.
function doSomTing(e,h,w){
alert(this.nodeName+ " " h + w);
}

OK. so lets attach this function to our event. We need to pass 2 arguments (e is automagically sent):

document.getElementById('myBut').onclick= doSomTing.toEvent('Hello ','World')

Here it is:

// Function.prototype.toEvent, .bindAsEventListener( args ) rem2006
// Important: sends event as the first argument to your function in IE also!,
// event XY [Array][x,y] is passed as last arg, your passed args are in the middle :)
// example: myElement.onclick= myFunc.toEvent( myArguments );
//
Function.prototype.toEvent = Function.prototype.bindAsEventListener= function(){
var _method= this, r=[], len=arguments.length, i=0;//alert(len)
for (i;i return function( ev ){ r[0]= ev= ev || event;
var db=document.body, dd=document.documentElement;
r[r.length++]=(ev.pageX)? [ev.pageX, ev.pageY] :
[ev.clientX + db.scrollLeft+ dd.scrollLeft,
ev.clientY + db.scrollTop + dd.scrollTop];
return _method.apply(ev.target|| ev.srcElement, r);
};
};

Friday, September 22, 2006

 

String.prototype.exe part2


Think I got it this time:
// executes string as body of function, args = comma seprated arguments
// ex.: 'var h=arguments[0]; var w=arguments[1]; alert(h+"\\n"+w)'.exe('Hello','World');
String.prototype.exe = function(){
eval( 'function(){' +this+ '}' ).apply(this,arguments);
};

Tuesday, September 19, 2006

 

Javascript Speed Tester new version


Test your javascript functions out with jsSpeedTester v0.45:

online: http://ottbot.hismercy.ca

download with this.js api: http://ottbot.hismercy.ca/jsSpeedTester.v.0.45.zip

Sunday, September 17, 2006

 

goodbye expando hello addData, getData


Why are expando's needed? To hold data. Sometimes, the data is another node(bad for ie). So how do we store data about an element? Say a div wants to know who its 2 'brother nodes' are, or an element wants to keep track of its size changes? Whatever, check this out:

String.prototype.addData= String.prototype.ad = function(n,v){
if (!window.elData){window.elData=[]}
if( !elData[this] ){ elData[this]=[] }
if( !n ){ elData[elData.length++]=this }else{ elData[this][n]=v };
return this;
};
String.prototype.getData= String.prototype.gd = function(n){
return( n )? elData[this][n] : elData[this];
};

Now add all the data you want. Say the div previously mentioned has an id of 'blah':
'blah'.ad('b1','divb1id').ad('b2','divb2id');
el.id.ad(size);

Getting the data is also easy:
b1= 'blah'.gd('b1'); b2= 'blah'.gd('b1');
getSizeHistory=el.id.gd();

This can also be used for classNames, function args...

 

String.prototype.cssObj


String.prototype.cssObj( styleObject[Object][optional] )
String.prototype.cssObj= function( styleObj ){ styleObj = styleObj || {};
var pairs=this.replace( /(^\s*)|(;\s*$)/g, '' ).split( /\s*;\s*/ ),selector,propAndVal,i=pairs.length;
while( i-- ){ propAndVal= pairs[i].split( /\s*:\s*/ );
selector=propAndVal[0] ;if( selector.match(/-/) ){ selector=selector.cc() }
styleObj[ selector ]= propAndVal[1].toLowerCase()}; return styleObj;
};
String.prototype.camelCase= String.prototype.cc = function(){
return this.replace(/-\D/gi, function(match){return match.charAt(match.length - 1).toUpperCase()} );
};


This code fits in wonderfully with many of the dom creation functions around, like the one on here. Example:
var s={ backgroundColor:'#f00',position:'absolute', width:'50px', height:'50px'};
'padding:5px; border-width:4px; border-style:solid; border-color:#333'.cssObj(s);

Sunday, August 20, 2006

 

Easy Class setTimeout call keeping 'this'


I'm working on an a.p.i called this.js. Its a jquery clone in its functionality... I needed to call functions within the same class, keeping this all the same. (arguments can be passed using the same technique, but it borks in IE6..its better to have the arguments as class members anyway). Here is some code from this.js showing the technique:
/// fadeIn 
this.fadeIn= function ( speed, delay ){
this.el.style.visibility='visible';
this.op(0); this._fadeIn.count = 0;
if (delay) { var _me=this;
setTimeout( function(){_me._argList[1]= speed; _me._fadeIn()}, delay*1000, _me );
} // call the fade function and returns this
else{ this._argList[1]= speed; this._fadeIn() }; return this;
};

Sunday, August 06, 2006

 

DOM Node Creation Helpers


These are the foundation of this.js(another a.p.i!), available for download.
// DOM Node Creation Helpers R.E.M. Aug.2006
// Generic Get Element, $, getEl()
// Args:[id],[element],[array]of.. Returns: [element] or [array] of elements
var $ = function getEl(e) {
if (typeof e == 'string') {return window.document.getElementById(e);}
if (e[0]) {var i=e.length; while(i--){e[i]=arguments.callee(e[i]);}return e;}
return e; //element
}
// Generic Append Element(),$A, appendElement()
// Appends [element] to [element] or [Array] of elements
var appendElement = $A =function(bag, marbles) {
if (marbles.constructor == Array){var l=marbles.length,i;
for(i=0;i else {bag.appendChild(marbles);} return bag;
}
// Generic Create Element, $X, exNihilo()
// Creates element and/or adds attributes to node and/or adds styles to node
var exNihilo = $X =function (el,attributes,styles) {
if (el==='textnode')
{ return document.createTextNode(((attributes)? attributes:' ')); }
var node=(el.constructor==String)?document.createElement(el): el,arg;
if (attributes){for (arg in attributes){node[arg]=attributes[arg];} }
if (styles) {for (arg in styles) {node.style[arg]= styles[arg];} }
return node;
}

Friday, August 04, 2006

 

FireFox innerText


FireFox, Opera innerText fix:
// Firefox InnerText R.E.M 2006
// Credits: Matthias Hertel , Erik Arvidsson, check by jvance
// emulates IE's innertext on Firefox's Proprietary __defineGetter__
if (typeof HTMLElement != "undefined" && typeof HTMLElement.prototype.__defineGetter__ != "undefined") {
HTMLElement.prototype.__defineGetter__("innerText", function () {
if (this.textContent) { return(this.textContent) }
else{var r=this.ownerDocument.createRange(); r.selectNodeContents(this);return r.toString();}});
HTMLElement.prototype.__defineSetter__("innerText", function (sText) {
if (this.textContent) {this.innerHTML=sText.textContent; }
else {this.innerHTML = sText.replace(/\&/g, "&").replace(//g, ">"); }} );
}
// opera innerText is broken
String.fixText=function($INPUT) {
return $INPUT.replace(/\&/g, "&").replace(/\</g, "<").replace(/\>/g, ">");
}

 

DOM Node Creation Helper Function-updated


Updated: Added functionality for text node creation: Just pass in node type as 'textnode' and then the second argument is your text, defaults to if omitted.


Updated: Now you can use it to add styles or attributes to an existing node. Just pass in the node (instead of a type of node).

// Generic Create Element,  $X,  exNihilo() R.E.M. 2006 
// Creates element and/or adds attributes to node and/or adds styles to node
var exNihilo = $X =function (el,attributes,styles) {
if (el==='textnode')
{ return document.createTextNode(((attributes)? attributes:' ')); }
var node=(el.constructor==String)?document.createElement(el): el,arg;
if (attributes){for (arg in attributes){node[arg]=attributes[arg];} }
if (styles) {for (arg in styles) {node.style[arg]= styles[arg];} }
return node;
}

You can call it with some code like this:
var node=exNihilo( 'span',
{innerHTML:'hello World'},
{border:'2px solid red',padding:'20px'} )

document.body.appendChild(node);
To add styles or attributes to existing nodes, pass in a node[element] instead of nodeType[string]:

// change/add color style of node
$X(node,0,{color:'#ff0000'})

Friday, July 28, 2006

 

Bizzare Firefox Speed Tests


Here are some speed tests done in Firefox. IE6 does not exibit same behaviour. Anybody can come up with a 'best practises' rule after looking this please post it.
I'd say, instantate your objects with the same type before you get/set them within a loop.









#TESTFUNCTIONSECONDS
#1
var _test2={};
%%
_test2._value = 123;
1.139 µs
#3
var _test2={};_test2._value=0;
%%
_test2._value.mmm = 123;
36.800 µs
#4
var _test2={};_test2._value=0;_test2._value.mmm=123;
%%
_test2._value.mmm = 123;
28.275 µs
#5
var _test2={_value:123};
%%
_test2._value.mmm = 123;
30.300 µs
#6
var _test2={_value:{mmm:123}};
%%
_test2._value.mmm = 123;
1.276 µs
#7
var _test2={};_test2._value={};_test2._value.mmm=123;
%%
_test2._value['mmm'] = 123;
1.326 µs
#8
var _test2={};_test2._value={};
%%
_test2._value.mmm = 123;
1.339 µs

Thursday, July 27, 2006

 

Higher Order DOM Scripting


Here is an example of using functional programming to speed up DOM scripting. We'll take a Quirksmode text select script, (beautiful in its own right), and give it the functional treatment.
After the first function call(in this case), or after initialization, what this type of programming gives us is a function that no longer needs any environment object checks. This is as fast as browser programming can get.
//Select text from http://www.quirksmode.org/js/selected.html
function getSel(){
if (window.getSelection){
getSel=function(){return window.getSelection() }; return getSel() }
else if (document.getSelection){
getSel=function(){return document.getSelection()};return getSel() }
else if (document.selection){
getSel=function(){return document.selection.createRange().text};return getSel() }
else {getSel=function(){return null}}
}
document.onmouseup=function(){ alert(getSel()) };

Sunday, July 23, 2006

 

Say Your Prayers with Javascript


Boy I love Javascript. Now its even saying my prayers for me. :)
Heres an app I coded, called Rosary.Beads.v1.0.
It says the rosary (a Catholic prayer said on beads) automatically.
It features low tech cross-domain 'ajax' counter, 2 images, flash audio, and slightly overcomplicated js. ;)
Online Link
Download link < ~360k

 

Confirm User Exit


Here is some code that alerts users that leaving the page might be a bad idea. It counts the number of attempts to leave the page and stops displaying the message after n attempts.
function confirmExit(){
if(!this.times) {this.times=0}
times++; if(times==2){window.onbeforeunload=''}
return 'All your sensitive information (email,posts,Google searches) '+
'is gathered by smart routers and warehoused in your namespace';
}
window.onbeforeunload= confirmExit;

Wednesday, July 19, 2006

 

Your GUI & CSS- just say no


Here is one large web app developer saying no to the use of CSS. Why we don't use css for appearance!
Gotta love it!

Tuesday, July 18, 2006

 

Function Fun


Here I'll post some small functions. Hopefully a few will give you a smile :)
myFun=function(){
var me=arguments.callee;
me.browser= (document.all)
? function(){alert("Hi I'm IE")} : function(){alert("Hi I'm FireFox")};
myFun=function(myFun){
arguments.callee.caller.browser();
alert(myFun);
}
myFun(myFun);
}();
This function at first glance exhibits some strange behaviour. Not the fact that it tests for document.all ;), but the result of alert(myFun). I thought it would have been == arguments.callee.caller, like this:
myFun=function(){
var me=arguments.callee;
me.browser= (document.all)
? function(){alert("Hi I'm IE")} : function(){alert("Hi I'm FireFox")};
myFun=function(myFun){
me.browser();
alert(arguments.callee.caller+"\n~~~~~~~~~~\n"+myFun);
}
myFun(me);
}();
alert(myFun);
Result of alert(myFun): undefined... and

myFun=function(){
var me=arguments.callee;
me.browser= (document.all)
? function(){alert("Hi I'm IE")} : function(){alert("Hi I'm FireFox")};
myFun=function(){
me.browser();
alert(arguments.callee.caller+"\n~~~~~~~~~~\n"+myFun);
}
myFun(me);
}();
alert(myFun);
Result of alert(myFun): undefined... and here is an anonymous function:
new function(){
arguments[0].message();
}({message:function(){alert('called by null')}});




Sunday, July 16, 2006

 

Namespacing and Application Structure #1


I use the YAHOO style architecture; thanks in no small part to Dusin Diaz. But even with his good examples, I still didn't feel at home. Then I came across this code:
__=function typesNamespace(){
window.isBool = function(a){
return typeof a=='boolean';
}}();
// alert(__); = 'undefined'
// alert(typesNamespace) = 'error undefined' ???
Which confused me (not hard). The author emailed me back and explained:

"It is actually the exact same thing as writing:


window.isBool = ....
The types namespace isn't a great example, but the reason I do this is so that I can have private variables that don't pollute the global namespace:


(function whateverNamespace(){
var AAA, BBB;

_w.someFunction = function(){
// do stuff with AAA or BBB
}
})();
This way AAA and BBB don't exist under window[]."-Mark

~~~~~~~~~~~~~~~~

Here is a couple blocks of code which are under the REM namespace, both blocks do the same thing. Looking at the first block tells me what is actually happening.
// block #A
var REM={};
(function(){
REM.b=b='boolean';//b is private
REM.isBool = function(a){
return typeof a==b;
}
})();
alert(REM.isBool + "\n"+ REM.isBool(true) + "\n" + REM.b);
//
// block #B
var REM=function(){
var b='boolean'; //b is private
return { isBool: function(a){
return typeof a==b;
}, b: b // but b is returned here
}
}();
alert(REM.isBool + "\n"+ REM.isBool(true) + "\n" + REM.b);
~~~~~~~~~~~~~~~~

Friday, July 14, 2006

 

Quick and Dirty Multiple Inheritence in Javascript


This has no checks for overriding properties so last object(arguement) wins:

/*function newObject() richard maloney 2006
Args: 2+ objects
Usage:send in n objects and it'll return one object inheriting
all the prop & methods of the objects passed in */
function object() {
var o=arguments,len=o.length-1,nextObj;
while(len--){
function f() {}
f.prototype =o[0], nextO=o[len+1];
for ( var i in nextO) { f.prototype[i]=nextO[i]; }
}
return new f();
}
You like? Here is some testing code:
  // setup the objects    
myFruitObj= {a:'apple', b:'banana'};
myFruitObj.peel=function(){this.b='banana peel';}
myFruitObj2={c:'carrot', d:'dill pickle'};
myFruitObj3={e:'eel', f:'fish', time:function(){alert('lets eat some'+ this.e)} };
// example call to our new function in this case
// existing myFruitObj3 is overridden
myFruitObj3=object(myFruitObj,myFruitObj2,myFruitObj3);

for ( var i in myFruitObj3) {
alert(i +" : "+ myFruitObj3[i])
}

Thursday, July 13, 2006

 

Javascript's Limitations


I'm reminded of a quote from the faq pages at javascript.comp.lang in answer to the quesion: What can be done with Closures?
"Strangely the answer to that appears to be anything and everything. I am told that closures enable ECMAScript to emulate anything, so the limitation is the ability to conceive and implement the emulation. That is a bit esoteric and it is probably better to start with something a little more practical."-Richard Cornford

 

Almost ajax- Synchronous Javascript Remote Scripting


Ok, its time I started to do some

Ajax

(

Asynchronous JavaScript and XML

) type stuff. Why? Maybe it'll help get me a job. There are already so many libraries and good stuff out there, I'm not going to re-invent the wheel. In the next few weeks I'll look at some good/and/or/popular ajax 'suites'. I got my eye on a few obscure ones; I'll share these after I know what a bit more.
For today though, I needed a cross-domain solution for this app I'm making.
So here it is; its a bit of a hack but it works in the real world. Check the recursion out. Good for one use. Goes something like this:

// the php file which sends a javascript file has function myFunction
// var done is to keep track of setTimeout checks
doIt=function(){
this.done=0;
var s=document.createElement("script");
s.src="http://www.XX.com/js.php";
s.type='text/javascript'; s.id='loadScript';
document.body.appendChild(s);s=null;
doIt=function(){
this.done++; //alert("this.done = " + this.done);
if (this.done>15){return;} // number of setTimeout trys before forgetting it
if (functionFromJs.php){
alert('All Good');
//do stuff
}
else {setTimeout('doIt()',333);}
}
setTimeout('doIt()',333);
}

Monday, July 10, 2006

 

Changing scope with With


/* create a global variable - y - that refers to an object:- */
var y = {x:5}; // object literal with an - x - property
function exampleFuncWith(){
var z;
/* Add the object referred to by the global variable - y - to the
front of he scope chain:-
*/
with(y){
/* evaluate a function expression to create a function object
and assign a reference to that function object to the local
variable - z - :-
*/
z = function(){alert(x);
//alert(this);
//... // inner function expression body;
}
}
return z;
}

/* execute the - exampleFuncWith - function:- */
exampleFuncWith()();
alert(x);
"When the exampleFuncWith function is called the resulting execution context has a scope chain consisting of its Activation object followed by the global object. The execution of the with statement adds the object referred to by the global variable y to the front of that scope chain during the evaluation of the function expression. The function object created by the evaluation of the function expression is assigned a [[scope]] property that corresponds with the scope of the execution context in which it is created. A scope chain consisting of object y followed by the Activation object from the execution context of the outer function call, followed by the global object.

When the block statement associated with the with statement terminates the scope of the execution context is restored (the y object is removed), but the function object has been created at that point and its [[scope]] property assigned a reference to a scope chain with the y object at its head."-Richard Cornford. March 2004

Saturday, July 08, 2006

 

My Dad is Paralyzed


July/08/06
Yesterday, Friday, my dad, a well-known local entertainer and celebrity, was going to lunch. (He had his usual weekend gig that night and just completed his weekly radio show) Going to lunch, he slipped on the sidewalk on a beautiful summer day, fell, and bonked his head. Later, at 3:00pm he lay in the emergency ward, paralyzed from the neck down. Today, Saturday, we await the outcome of an 8 hour surgery. The best we can hope for they say is that he will breathe on his own. Before his surgery, he mouthed 'will I ever sing again?'. Need I say more my friends...
Update: July/11/06 Surgery went 'fine' and 'No'.
Update: July/31/06
Today my dad was moved from I.C.U. to Trauma, meaning he can breathe on his own now without a ventilator. He still has O2 going into a trachiotomy. Still paralyzed, no change there. Prognosis for speech, OK; for singing???
Is my dad mad at God? 'No, he has a plan'.
Another quote 'This will make me a better person'.
Oh, and he's planning a comeback, Nov.11/2007 8:00p.m., live on stage, Centerpoint theatre.

Friday, July 07, 2006

 

~ js ramblings ~


"You can pass a this parameter to setTimeout or setInterval, but it requires a helper function":
setInterval(function (t) { animate.call(t); }, 50, this);
"Notice that the first arg is a function reference, not a string. This may not be well-known, but in combination with Function.prototype.call (or .apply) and extra trailing args to setInterval (or setTimeout), it does the job."-Brendan Eich

"Use a closure to fix the setInterval problem" -Guido Wesdorp :
animateEl = function(el){
var _this = this;
this.animate = function(){
setInterval(_this.animate(), 50)
}
}

"There's another way to call an object's member function in a setInterval or setTimeout call. You have to create a bind() member on the Function object's prototype first:
Function.prototype.bind = function( object )
{
var method = this;
return function()
{
method.apply( object );
}
}
Then you can 'bind' a member function to a setTimeout call like this (assuming your object has a method named foo)"-Tom Trenka:
setTimeout( this.foo.bind( this ), 50 );

Thursday, July 06, 2006

 

Doug Crockford's function object(o)


//taken from: http://www.crockford.com/
function object(o) {
function f() {}
f.prototype = o;
return new f();
}

 

Javascript Closures for Dummies



Here is a great article by Morris Johns:

Javascript Closures for Dummies

Some of John's points:


Heres some good stuff on stopping IE memory leaks,(I wonder if IE7 will fix most of them, not to worry 'bout it though; if your building a big app or lots of closures and dom stuff, heres some ways to stop them:
if (window.document.all) window.onunload= ... ;) 
Simon Willison explains: "Closures make it easy to create a memory leak without meaning to. Consider this:
function addHandler() {
var el = document.getElementById('el');
el.onclick = function() {
this.style.backgroundColor = 'red';
}
}
The above code sets up the element to turn red when it is clicked. It also creates a memory leak. Why? Because the reference to el is inadvertently caught in the closure created for the anonymous inner function. This creates a circular reference between a JavaScript object (the function) and a native object (el). There are a number of workarounds for this problem. The simplest is this:
function addHandler() {
var el = document.getElementById('el');
el.onclick = function() {
this.style.backgroundColor = 'red';
}
el = null;
}
This works by breaking the circular reference. Surprisingly, one trick for breaking circular references introduced by a closure is to add another closure:
function addHandler() {
var clickHandler = function() {
this.style.backgroundColor = 'red';
}
(function() {
var el = document.getElementById('el');
el.onclick = clickHandler;
})();
}
The inner function is executed straight away, and hides its contents from the closure created with clickHandler."-©2006 A ReIntroduction to Javascript

Monday, June 26, 2006

 

Javascript Tips


Conditionals
If you are doing some sort of comparison conditional, where one operand of that conditional is a literal, it's actually better to list the literal operand first:

if ( "someString" == someVar )
if ( 3 == myNum )

Why? Because if you mistype the equality operator (==) and instead type the assignment operator (=) -- a fairly common typo, then you will discover this error at runtime. Tracking down the cause of these errors can be difficult, but switch the order of your operands and the mistake of assigning a variable to a literal error instantly and give a useful line-number (even in IE!)

If you have any cool tips please post 'em here.

Archives

June 2006   July 2006   August 2006   September 2006  

This page is powered by Blogger. Isn't yours?