11

At our company we have pretty large body of PrototypeJS based JavaScript code, which we are porting to jQuery for several reasons (not really important here). I'm trying to set up coding guidelines to make/keep things tidy during the porting.

One observation from wading through the prototype based implementation is that a lot of code is written in OOP style (using Prototype's Class.create), but the code is not "object oriented" in spirit. The general pattern I've seen: one "constructor" which you are expected to call (but not call twice, because the constructor uses hardcoded DOM id's), a bunch of other "functions" and event handlers, which you are not expected to call (but the because there is no "private" in JavaScript, you don't know that) and data sharing between all these functions through this. Seen from the caller's point of view there is just one "callable" and nothing else.

I'm starting to believe that OOP in JavaScript can and maybe should be avoided in a lot of cases. At least for our use case, which is not the next generation Goole Wave UI, but simply put: a bit of AJAX based enhancements, registering some event handlers here and there, minor DOM manipulations and such.

  • the functionality we need seems to be implementable just fine in the typical jQuery non-OOP way, using closure magic to obtain encapsulation and privateness. As side effect, the minification efficiency of the ported code is much better.
  • OOP in JavaScript is non-traditional and confusing if you are coming from a "traditional" background. There are a lot of attempts and frameworks to approximate traditional OOP, but IMHO this makes things even more confusing and fragile.
  • One thing that Crockford's "JavaScript the good parts" taught me, is that the true power of Javascript lies in function scopes and closures, much less in OOP patterns.

I'm wondering if there is wider support for this feeling that OOP in JavaScript doesn't really cut it as the sacred mantra, like it is in other languages/platforms. And, in extension, what kind of non-OOP/closure based patterns are much more preferable.

Stefaan
  • 210
  • 2
  • 5
  • 3
    Javascript does its "OOP" using functions and closures. Private methods are realized by declaring them the right way in the right scope. Yes, it's *different*, but it's *possible*. It doesn't have to be "sorta OOP", you just need to apply it correctly. In fact, it helps to wrap your head around Javascript's way of OOP, since it gives you a new perspective on what "classic OOP" in other languages is and how little you actually need to implement it; one language construct (`function`) is sufficient. – deceze May 15 '13 at 15:59
  • 1
    @deceze That would make a decent answer, if you added a short code sample. – Robert Harvey May 15 '13 at 16:06
  • possible duplicate of [Are there any OO-principles that are practically applicable for Javascript?](http://programmers.stackexchange.com/questions/180585/are-there-any-oo-principles-that-are-practically-applicable-for-javascript) and of [How to handle large scale js+jquery projects using well written, Object-Oriented JavaScript and jQuery code?](http://programmers.stackexchange.com/questions/95435/how-to-handle-large-scale-jsjquery-projects-using-well-written-object-oriented) – gnat May 15 '13 at 16:06
  • @gnat: The first one, maybe. Not the second. I think the OP is asking the opposite. – Robert Harvey May 15 '13 at 16:09
  • @Robert I hereby give permission to use that comment as answer, if a code sample is added. I'm not fluent enough in Javascript to quickly whip one up correctly at the moment, as I'm a little busy. :) – deceze May 15 '13 at 16:09
  • @RobertHarvey as long as the opposite is exact, this shouldn't matter don't you think? I mean, good, correct, thorough *answer* to particular question would naturally cover it's exact opposite – gnat May 15 '13 at 16:12
  • @deceze I consider closures to be the "inverse" of OOP: in OOP you inject functions in the data container/struct and with closures you inject data in the function (scope). – Stefaan May 15 '13 at 16:13
  • 1
    @Stefaan "Classes" are containers that data is injected into which is only accessible to certain functions ("methods") within that container. This can be modeled perfectly using functions and aspects of closures, it's the same idea. Maybe you're thinking of deeply nested trees of callbacks within callback; if so nobody said that's either good or OOP. – deceze May 15 '13 at 16:16
  • @deceze Exactly. That's the pattern we here are converging to at the moment, I think. But I'm hesitant to call it "OOP". The thing that makes me hesitate is that there is not really an clear tangible "object/container" to be oriented around. Unless you consider the memory associated with the current scope hierarchy to be the "container", but that's not as well/clear defined on the level of source coude as it is in "traditional" OOP. – Stefaan May 15 '13 at 16:31
  • @deceze well you do lose inheritance, generic methods and the ability to have a program that creates a lot of objects. That's a lot when you can just use underscore prefix/suffix. – Esailija May 15 '13 at 17:22
  • + to you for getting away from Prototype and into JS.Net ... erm, I mean jQuery! It's power level is "Over 9000!" – SpYk3HH May 24 '13 at 14:40

3 Answers3

4

People tend to get caught up in advanced patterns with OOP. MVC, MVVM, MVVC and every other permutation of 'M', 'V', and 'C'. I've never opened up a js project with 20,000+ lines and said to myself: "Thank god this is in MVC", because the reality is that most projects with 20,000+ lines are going to be a terrible mess.

Having said that, I still think large projects are almost impossible without OOP. At the very least, the ability to write complex objects and store them in separate files and namespace-protect them from collisions using a library like dojo will save you thousands of hours of painful debugging.

"Oh", you might say to yourself, "Well, I can write modular groups of functions in separate javascript files with the best of them. I don't need to use OOP." Well, my friend- congratulations, because you're already effectively using OOP without even knowing it. So as long as that's the case, why not just go one step further and use actual classes?

It's true that javascript relies on the prototype model, however, the base of OOP is pretty much inheritance/encapsulation/polymorphism, and javascript can do that perfectly well. Take a look at dojo.js.

CodeOwl
  • 141
  • 2
  • 2
    Is code written in a browser really large enough to warrant full-scale object-orientation? – Robert Harvey May 15 '13 at 16:11
  • 1
    I've seen javascript projects that are pretty big. Hell, they're making Quake ports with WebGL for gosh sakes. – CodeOwl May 15 '13 at 16:12
  • 1
    @Robert Just because it's in the browser doesn't mean it's trivial. I find Google Maps a perfect example of a very non-trivial app/API that uses Javascript OOP quite well. – deceze May 15 '13 at 16:13
  • 3
    @RobertHarvey: Allan Kay argued that by role browser are operating systems rather than applications (as opposed to how they were designed in the end). In that spirit I would ask whether code written "in an OS" is really large enough to warrant full-scale object-orientation. It's no longer uncommon for JavaScript project to have 1MLOC and more. – back2dos May 15 '13 at 16:16
  • 2
    @back2dos: No disrespect to Alan Kay, but that comment makes no sense. Browsers are not operating systems, and they never will be (they don't have first-class access to the file system, for starters). I might call a browser an application platform, but not an operating system. – Robert Harvey May 15 '13 at 16:21
  • And who is writing web pages with sixteen megabytes of Javascript code (assuming 16 characters per line, which is probably conservative)? Who is downloading them? The largest full-scale application framework [listed on this page](http://en.wikipedia.org/wiki/Comparison_of_JavaScript_frameworks) is 500K bytes. – Robert Harvey May 15 '13 at 16:26
  • @RobertHarvey Still, large javascript projects exist. And the language isn't helpful to organize stuff in modules. I have seen 40000 lines long files. Everyones was just adding components and no one was refactoring. – Simon Bergot May 15 '13 at 16:28
  • @RobertHarvey application are often way bigger than frameworks. Frameworks are just a "standard" way of dealing with a class of problems. – Simon Bergot May 15 '13 at 16:30
  • Just playing devil's advocate, as always. – Robert Harvey May 15 '13 at 16:30
  • 2
    "*why not just go one step further and use actual classes?*" - Because many modules (while being objects) neither use constructors nor inheritance. And even if you need only one of them there's no need for a full-blown class-emulation. – Bergi May 15 '13 at 16:31
  • 3
    @RobertHarvey: No disrespect to you, but *that* comment makes no sense. Firstly, an operating system is hardly defined by "first-class access to the file system". By that definition, iOS is hardly an OS. And there have been operations systems, before there have been file systems. Also you can buil a web app against a web service through HTTP that will give you anything an FS gives you. – back2dos May 15 '13 at 16:31
  • @RobertHarvey: There was a [conference specifically targeted at developers writing JS apps with more than 1mloc](http://mloc-js.com/) so obviously this is a real world scenario. – back2dos May 15 '13 at 16:33
  • No current, self-respecting operating system gives you only limited access to a sandbox, like a browser does. – Robert Harvey May 15 '13 at 16:33
  • 2
    @RobertHarvey: Quite to the contrary. Any decent recent OS always puts some restrictions on how you access files. Even Windows tries. That's an important feature of a file system in fact. – back2dos May 15 '13 at 16:36
  • We're getting a bit far afield from the question, aren't we? That a browser is not an OS seems axiomatic to me. There are a wealth of services that an OS provides that a browser does not. First-class access to the OS, with advanced security features, is just one of them. We tried the whole "browser as an OS" thing a few years ago. Guess what? Browsers still run on top of an OS. – Robert Harvey May 15 '13 at 16:37
  • @RobertHarvey: I agree, but I think it would be up to you to find a plausible argument why browsers are so critically different from operating systems that software written to run in them must inherently be non-complex. – back2dos May 15 '13 at 16:39
  • Like I said, I was just playing devil's advocate. If you're running a game platform and you have one million lines of code in the browser, fine. It only has to be downloaded once. If you're running one million lines of code in the browser for a line-of-business application involving multiple web pages, you're probably doing it wrong, unless you're doing very sophisticated, real-time analysis of data, flying a drone, or something like that. – Robert Harvey May 15 '13 at 16:42
  • @RobertHarvey Not all JavaScript is running in a browser these days. – Gort the Robot May 15 '13 at 17:14
  • @StevenBurnap: Yes, I know about Node.JS – Robert Harvey May 15 '13 at 17:15
  • Large projects without OOP are certainly possible, e.g. Unix and Linux. – kevin cline May 15 '13 at 17:19
2

I feel it's important to point out a couple of things:

  1. OOP and classes are two fully orthogonal concepts. Classes could just as well work with structs/records (and in fact they do in some languages). They incidentally happen to be useful for constructing specific kinds of objects.
  2. Access control is a nice tool for encapsulation, but it's not a prerequisite. In JavaScript it's common to prefix "private" members of an object with an underscore. Whether or not you choose to access those anyhow is for you to decide. In most languages there are some means to get past access control if you really want to. It's just a really silly thing in general to write code against something that was never consciously exposed by a human being for you to consume (and can for example change at any time).
  3. OOP is certainly not about how specific parts of your system are implemented (let alone the syntax involved) and I would thus argue that the implementation cannot be "object oriented in spirit" or not. OOP is mostly a relatively clever mechanism for indirection built on encapsulation and polymorphism. In essence, it is little more than "Tell, Don't Ask".

If you want to jump through hoops to turn JavaScript into something it isn't, you may be unhappy with the result. So instead, you could pick any of the available languages that compile to JavaScript but are closer to what you might want a programming language to look like (Haxe, ParenScript, TypeScript, CoffeeScript, ScriptSharp, Dart, Java (through GWT), C/C++ (through Emscripten) ... in fact almost any other popular language can be translated to JavaScript with varying quality).

But if you use JavaScript for what it is, you will find a language that allows "class-oids", mixins/traits, AOP and what not. More often than not, you will realize than limiting yourself to Java-esque idioms might not be the best idea. Nonetheless, they undoubtedly come in handy at times.

back2dos
  • 29,980
  • 3
  • 73
  • 114
  • 1. I'm not sure why you talk here about classes. I didn't mention classes, because they're not a built in concept in JS. 2. I don't care about access control, much like Python's "We're all consenting adults here". The main problem with pseudo-privateness in JS (underscore prefix) is that it's bad for minification efficiency, which is important for us. 3. I'm afraid I don't understand what you are trying to tell here. About the rest of your answer: I think I agree here: approximating Java-style OOP in JS makes things weirder than just adhering to JS's true, but potentially confusing, nature. – Stefaan May 15 '13 at 20:27
  • 2
    @Stefaan: 1. "[...] a lot of code is written in OOP style (using Prototype's Class.create)" - so you do talk of classes and you seem to assume mimicking them to be "OOP style". 2. "The main problem with pseudo-privateness in JS (underscore prefix) is that it's bad for minification efficiency" - that's a property of the minifier and not of JavaScript. [Closure can be made to get rid of underscores](http://bit.ly/10zO052). 3. You judge object orientation "from wading through the [...] implementation", all the while object orientation is all about interfaces. – back2dos May 16 '13 at 05:07
0

One observation from wading through the prototype based implementation is that a lot of code is written in OOP style (using Prototype's Class.create), but the code is not "object oriented" in spirit. The general pattern I've seen: one "constructor" which you are expected to call (but not call twice, because the constructor uses hardcoded DOM id's), a bunch of other "functions" and event handlers, which you are not expected to call (but the because there is no "private" in JavaScript, you don't know that) and data sharing between all these functions through this. Seen from the caller's point of view there is just one "callable" and nothing else.

Not every Javascript project needs OOP. I wouldn't go there unless I were using an existing OO framework like ExtJS. In your case, where it seems the only use of OOP is misuse, I think you should skip it entirely. Since you are switching to jQuery, just follow the jQuery plugin architecture. Write custom plugins when convenient.

kevin cline
  • 33,608
  • 3
  • 71
  • 142