Wednesday, March 11th, 2009

Digging a real OO class system with jQuery

Category: JavaScript, Library

Micah Snyder of Digg has released a plugin for jQuery that gives it an OO Class-like model:

At Digg we use jQuery extensively, but it doesn’t offer a much in the way of Object-Oriented JavaScript. Existing OOJS libraries weren’t a good fit — often trying to shoehorn traditional OOP patterns in where they don’t quite fit — so we rolled our own. Class adds OOP patterns to jQuery, modeled after the original Class object in Prototype but with significantly greater capabilities — including namespacing, limited classical inheritance and more robust prototypal inheritance.

How does it work?

javascript

  1. // Hello World
  2. var MyClass = Class.create();
  3. var mc = new MyClass();
  4.  
  5. // And now, a static class. Anytime the last argument passed to Class.create is boolean, it’ll serve as the static switch (defaults to false).
  6.  
  7. var MyClass = Class.create(true);
  8. MyClass.namespace('foo');
  9.  
  10. // Add constructor and methods
  11.  
  12. var method = {
  13.     someFunc: function(){}
  14. }
  15.  
  16. var MyClass = Class.create({
  17.     init: function(){
  18.         console.log('You instantiated a Class!');
  19.     },
  20.     myFunc: function(){},
  21.     myProp: 'foo'
  22. }, method);
  23.  
  24. var foo = new MyClass();
  25. foo.someFunc();
  26.  
  27. // Namespaces
  28.  
  29. var MyClass = Class.create(true);
  30.  
  31. //this...
  32. MyClass.namespace('bar');
  33.  
  34. //...is the same as this
  35. $.extend(MyClass, {
  36.   bar: Class.create(true);
  37. });

And, there is much more including:

  • Deep Namespaces
  • Existing Global Namespaces
  • Namespace / Method Combo Object
  • Multiple Namespaces With an Array
  • Dynamic Classes in Namespaces
  • Extending Classes

I know that the functional crowd may feel that this glue isn’t needed, but I wanted to do just on a recent jQuery project, so this is a very cool addition IMO.

Posted by Dion Almaer at 5:27 am
12 Comments

++---
2.3 rating from 67 votes

12 Comments »

Comments feed TrackBack URI

Interesting but I don’t see the point in piggybacking on jQuery’s abstraction? I think your class-based implementation is quite suitable on its own.

I never really understood the point in trying to make JavaScript something it’s clearly not. Prototypal inheritance CANNOT go hand in hand with classical – consigning to one is the only way in my opinion.

Comment by JimmyP22 — March 11, 2009

Building complex applications with inheritance is a pain if you use the strict prototypal way. Mainly because calling super class methods needs to be something like MyClass.prototype.myMethod.call(this, args); Or even worse if you use name spaces it would be something like: mylibrary.mynamespace.MyClass.prototype.myMethod.call(this, args);
when it could have been: this.parent(args); or this.Super.myMethod(args); if you use a OOP framework.

Comment by Spocke — March 11, 2009

been done alredy, by john himself! http://ejohn.org/blog/classy-query/

Comment by daitro — March 11, 2009

lol @ daitro

From the source of his post:
// Happy April Fools Day 2008
// The code is good – read for inspiration, but
// please don’t use this :-(

Comment by sixtyseconds — March 11, 2009

That script seems to be of a doubtful quality.


...
if(this.constructor == Object || typeof this.init != undefined) {
...

The latter expression will always evaluate to `true`, since `typeof` always returns a string. Did they forget quotes around `undefined`. It’s also not clear why there is a limitation of `constructor` being an Object. What if I want to pass an object that inherits from `Object.prototype` but doesn’t really have `Object` as its `constructor`? It would be better to check for either [[Class]] or use `typeof`.

Another oddity:

$.each(ns, function() {
_this.namespace.apply(_this, [this]);
});

Nice. Creation of a useless array in a loop just to pass it to `apply`? `call` would do just fine (and faster and more memory effecient, of course)

Further down, we have:

...
for(i in this) {
...

which obviously creates `i` in a global scope : /

And another case of inefficient array creation in a loop:

...
if(extendee[i] && extendee[i].constructor == Function && ['namespace','create','sup'].indexOf(i) == -1) {
...

I also don’t see how it’s modeled after Prototype.js. Prototype.js uses `beget`-like pattern for inheritance. They, on the other hand, seem to manually iterate over methods with for/in. Those are 2 completely different approaches.

There’s also no fix for JScript’s DontEnum bug, which might bite them one day. I also couldn’t find any unit tests…

Comment by kangax — March 11, 2009

@sixtyseconds

forgot to use the tag [sarcasm][/sarcasm]

Comment by daitro — March 11, 2009

He actually did do something similar, which is not a joke:
http://ejohn.org/blog/simple-javascript-inheritance/

Comment by whyisjasontaken — March 11, 2009

Hmm…didn’t a library have a class system in it years ago natively that rocks, keeps code organized, introduces custom events and chaining in a integrated fashion???

Oh yeah Mootools! that’s right!

Here is my analogy for this article:

When IE first did tabbed browsing lay people everywhere were like “Oh my god tabs how awesome.” I can vouch, I still have friends who aren’t working in internet technology who think FireFox is the one doing the UI and functional copying…

So I see this post, and so many recently, in much the same way, namely: “Oh my god look what you can do with jQuery, brilliant!!!” – make sure to read emphatically like a guinness commercial puppet for full effect.

Using Google more would solve many problems folks, there is the whole new world out there beyond the little js lib box. (don’t bust my balls over the chance Aladdin reference). I mean I don’t use jQuery much but I read John’s blog sometimes and try and stay up with developments they do…

Comment by csuwldcat — March 11, 2009

Meh. Why not just use the power of the language itself? Could you justify to a software architect this approach? To the argument that this would create a codebase that would not work exactly (note: exactly) in the way someone from a classical OO background would expect, and would be confusing for those who weren’t (ie. the massive pool of developers who are trained in javascript), what would you say? To a recruiting manager: how would you explain that you’ve architected a codebase which makes it more difficult to find cheap talent, for zero performance or other benefit? Do you believe debugging will be more difficult by injecting this sort of inheritance into another sort of library model *on top of* a language which *both* of these layers abstract, differently? Does the added complexity, man-hours and other negatives go away due to some benefit? And what is that benefit?

Comment by nataxia — March 11, 2009

@nataxia

I coded things in regular old script before using a lib (not for long, it sucks) and even used Mootools without digging into the Class framework for quite a while. The thing is when I started using classes the pieces fit together so seamlessly. Binds, mutators, chaining, binding with custom events, extensibility of the code, DRY, reuse++, modularity, class inheritance and extends, it makes it a snap to do just about anything cleanly and efficiently with little fuss.

I would never go back, ever. Just a different world when you dig into it.

Comment by csuwldcat — March 11, 2009

@csuwldcat

The first and most important thing to say is that I am glad that you see the value of a consistent development model. That being said, I leave you with some Crockford, in particular the last bit, and the thought that it is to me ridiculous to say that the most popular language in the world has a model that is hard to use:

JavaScript can be used like a classical language, but it also has a level of expressiveness which is quite unique. We have looked at Classical Inheritance, Swiss Inheritance, Parasitic Inheritance, Class Augmentation, and Object Augmentation. This large set of code reuse patterns comes from a language which is considered smaller and simpler than Java.

Classical objects are hard. The only way to add a new member to a hard object is to create a new class. In JavaScript, objects are soft. A new member can be added to a soft object by simple assignment.

Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies. Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive.

I have been writing JavaScript for 8 years now, and I have never once found need to use an uber function. The super idea is fairly important in the classical pattern, but it appears to be unnecessary in the prototypal and functional patterns. I now see my early attempts to support the classical model in JavaScript as a mistake.

Comment by nataxia — March 12, 2009

“I have been writing JavaScript for 8 years now, and I have never once found need to use an uber function.”

Just as well, because the function Crockford published on his site (http://www.crockford.com/javascript/inheritance.html) doesn’t work in the general case. Try it for more than three levels of inheritance. Caused me such a headache :(

P.S. sorry I realise this is a very old thread!

Comment by kchriss — November 3, 2011

Leave a comment

You must be logged in to post a comment.