Javascript OOP
I linked a while ago to an article that I thought was doing OOP right in Javascript. It turns out that it wasn’t quite. Under that system, constructors can’t have parameters and other badness.
After working out the details, here’s what I found. Start with a base class A and derive a class B:
function A(args){
// non-static args-independent code
this.myMethod=function(){return 'A'+this.x;};
this.x='x';
if (arguments.length==0) return;
// args-dependent code
this.myArgsDependent=function(){return args;};
}
A.prototype.myStaticMethod=function(){return 'static A';};
function B(args){
if (arguments.length==0) return;
// args-dependent code
// annoying to have two copies, but otherwise static members get overridden
// (see below)
// if that's not a problem, set this.super = B.prototype
this.super=new A(args);
A.call(this,args);
// while not strictly args-dependent, overriding methods / properties
// has to occur after the args-dependent call to the
// superclass constructor
this.myMethod=function(){return 'B'+this.x;};
this.x='y';
}
// this says "if it's not here, look for it in A"
B.prototype = new A();
B.prototype.myStaticMethod=function(){return 'static B';};
b=new B('argsFromBConstructor');
alert(b.myMethod()); // By
alert(b.myStaticMethod()); // static B
alert(B.prototype.myStaticMethod.call(b)); // static B
alert(b.super.myMethod.call(b)); // Ay
alert(b.super.myMethod()); // Ax
alert(b.super.myStaticMethod.call(b)); // static A
alert(b.myArgsDependent()); // argsFromBConstructor
Javascript doesn’t do multiple inheritance or implement interfaces, but you can run several contructor methods on a single object with the same A.call(this,args) syntax.
function C(){
// initialize this object with properties of both A and B
A.call(this,args);
B.call(this,args);
}
// If it's not in C, you have to tell it a single class to look in
C.prototype=new <which:A or B?>;
Greasemonkey closures
I’m writing up a greasemonkey script that adds onclick behavior to the span. According to the site, you do something like
thisDiv.addEventListener('click',function(){
// function code here
},true);
This works OK, but what if my code needs scope? Say I wanted to search for some divs and have them tell which match they are when clicked. This code won’t work:
for(i=0; i<allDivs.snapshotLength; i++){
var thisDiv=allDivs.getSnapshotItem(i);
thisDiv.addEventListener('click',function(){
alert(i);
},true);
}
If there were 10 matching divs, this will alert “10″ every time. On the other hand, this code will work:
for(i=0; i<allDivs.snapshotLength; i++){
var thisDiv=allDivs.getSnapshotItem(i);
thisDiv.addEventListener('click',(function(i){return function(){
alert(i);
};)(i),true);
}
This is helpful when you want your modifications to retain access to functions like GM_setValue without using unsafeWindow. This way won’t work:
for(i=0; i<allDivs.snapshotLength; i++){
var thisDiv=allDivs.getSnapshotItem(i);
thisDiv.addEventListener('click',function(){
GM_setValue('mydata',i);
},true);
}
This way will:
for(i=0; i<allDivs.snapshotLength; i++){
var thisDiv=allDivs.getSnapshotItem(i);
thisDiv.addEventListener('click',(function(i,GM_setValue){return function(){
GM_setValue('mydata',i);
};)(GM_setValue,i),true);
}
I Got Another Journal Publication
“Bit Commitment Blues” has been published in Journal of Craptology!
leave a comment