Skip to content

Instantly share code, notes, and snippets.

@bga
Created January 5, 2011 03:36
Show Gist options
  • Save bga/765893 to your computer and use it in GitHub Desktop.
Save bga/765893 to your computer and use it in GitHub Desktop.
/*
my OOP in js is more and more closer to java/c++/c# :P
1) now it allows create instance w/o <new> keyword (all native classes supports instance creating w/o <new> except <Date>)
2) removes <prototype> extra word when you access to static fields and methods(<Class.prototype = Class> magic)
3) automatic delegates/<Function#bind>. My delegates always is begined from '_on' prefix
4) has own implementation of <instanceof> operator - <Object#_hasBaseClass>
5) base constructors call via special <Object#_callBaseConstructor>
6) derivation do not uses prototype machanism(because slow resolving). I use just copy _methods/InternalTypes/CONSTS. Yes its based on codestyle. But you can use <typeof> or <Object#toString> instead.
*/
(function($G)
{
var _overwrite = function(dest, src)
{
for(var i in src)
{
if(src.hasOwnProperty(i))
dest[i] = src[i];
}
};
var _extendClass = function(dest, src)
{
for(var i in src)
{
if(src.hasOwnProperty(i) && !/^[a-z]/.test(i) && !dest.hasOwnProperty(i))
dest[i] = src[i];
}
};
Object._create = Object.create ||
('__proto__' in {}) && function(pr){ return {__proto__: pr} } ||
function(pr)
{
var _fn = function(pr){};
_fn.prototype = pr;
return new _fn();
}
;
$G._defClass = function(def)
{
var Class =
def._construct == null && function()
{
//if(!this._hasBaseClass(Class))
if(this.constructor !== Class)
{
var obj = Object._create(Class);
_bindDelegates(obj);
return obj;
}
} ||
function()
{
//if(!this._hasBaseClass(Class))
if(this.constructor !== Class)
{
var obj = Object._create(Class);
_bindDelegates(obj);
Class._construct.apply(obj, arguments);
return obj;
}
else
{
_bindDelegates(this);
Class._construct.apply(this, arguments);
}
}
;
_overwrite(Class, def);
Class.prototype = Class;
Class.prototype.constructor = Class;
var delagateNames = [];
for(var i in Class)
{
if(Class.hasOwnProperty(i) && i.slice(0, 3) == '_on')
delagateNames.push(i);
}
var _bindDelegates = Class.__jbBindDelegates =
delagateNames.length > 0 && function(obj)
{
var i = delagateNames.length;
while(i--)
obj[delagateNames[i]] = obj[delagateNames[i]].bind(obj);
} ||
function(obj){}
;
if(def.extend && def.extend !== Object)
_extendClass(Class, def.extend.prototype);
return Class;
};
Object.prototype._hasBaseClass = function(Class)
{
var v = this.constructor;
while(v != null)
{
if(v === Class)
return true;
v = v.extend;
}
return false;
};
Object.prototype._callBaseConstructor = function(Class, args)
{
Class.__jbBindDelegates(this);
(Class._construct || function(){}).apply(this, args || []);
};
})(this);
// example
(function($G)
{
var Class = _defClass({
_construct: function(a)
{
this.a = a;
},
_foo: function()
{
Class.n += this.a // access to static fields via <Class.%fieldName%> instead <that.%fieldName%>
},
_onA: function(a) // delegate
{
this.a = a;
},
n: '' // static field
});
var c = Class('a'); // no <new> ! but you can use <new> prefix if you want
c._foo();
(c._onA)('A'); // no explicit .bind anywhere
Class._foo.call(c); // not <Class.prototype._foo.call(c)>!
console.log(Class.n); // not <Class.prototype.n>! Like in C++!
var Derived = _defClass({
extend: Class,
_construct: function(a, b)
{
this.b = b;
this._callBaseConstructor(Class, [a]);
//Class.call(this, a);
},
_foo: function()
{
Class.n += '<' + this.a + '>';
},
_bar: function()
{
Class.n += this.b;
},
_onB: function(b) // delegate
{
this.b = b;
}
});
console.log(String(Derived.n)); // check that <Class#n> is not copied
var d = Derived('a', 'b');
d._foo();
d._bar();
(d._onB)('B'); // no explicit .bind anywhere
(d._onA)('A');
Derived._foo.call(d); // static_cast<Derived*>(&d)->_foo(); ie cast and call
Derived._bar.call(d);
console.log(Class.n);
console.log(d._hasBaseClass(Class));
console.log(d._hasBaseClass(Derived));
console.log(d._hasBaseClass(RegExp));
})(this);
@subtleGradient
Copy link

No generics?
E.g.

Array.map(myArray, fn)

What happens if you do

MyClass.someMethod()

without using call?

@subtleGradient
Copy link

I usually use calling a constructor without the new operator as casting.
E.g.

myThingInstance = new MyThing(arg1, arg2)
myCastedThing = MyThing(existingObject, arg1, arg2)

That makes way more sense to me personally. It falls in line with how JavaScript itself actually works too.

castedAsString = String(123)
casterAsNumber = Number(true)

@bga
Copy link
Author

bga commented Jan 5, 2011

@subtleGradient MyClass._someMethod() calls static method.
Array.map is js only sugar.
Now im making better version.

@subtleGradient
Copy link

I think it's very valuable to follow the existing conventions defined in the JavaScript spec itself. Cf. https://developer.mozilla.org/en/new_in_javascript_1.6#Array_and_String_generics

This convention of having generic versions of all prototype methods has been in use in MooTools for years.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment