A question of style

I’d like to solicit your opinion on something.

As you probably know, JavaScript is a very flexible language. There’s always more than one way of doing something. That becomes really apparent when it comes to objects.

Here’s one way of creating an object called Foobar. This object has some properties, foo and bar, and methods, init and execute:


function Foobar() {
    var foo,bar;
    this.init = function() {
        foo = this.foo;
        bar = this.bar;
        execute();
    };
    var execute = function() {
        alert(foo+bar);
    };
}

Here’s how you would create a new instance, assign values to the properties, and invoke the init method:


var baz = new Foobar();
baz.foo = 1;
baz.bar = 2;
baz.init();

The execute method is effectively private and can only be called from within the object, but the properties can be set externally.

Here’s another way of doing much the same thing:


function Foobar() {
    var foo,bar;
    this.setFoo = function(value) {
        foo = value;
    };
    this.setBar = function(value) {
        bar = value;
    };
    this.init = function() {
        execute();
    };
    var execute = function() {
        alert(foo+bar);
    };
}

This time, the properties are given values only through methods like setBar and setFoo:


var baz = new Foobar();
baz.setFoo(1);
baz.setBar(2);
baz.init();

The end result is pretty much the same. You can create an instance and set some properties (foo and bar), but the only method you can invoke is init: the execute method remains more or less private in both cases.

So my question is: which do you prefer?

The second one looks more like a classic example of a class that you’d see in other programming languages, but the first one is slightly lighter.

I’m aware that there are other ways of doing the same thing. I haven’t even touched on using the object literal, which would save even more space, I think.

Right now, I’m just interested in a quick show of hands. Which one do you prefer, and why? Which one do you find more readable and easy to understand, the first or second?

Posted by Jeremy on Wednesday, October 25th, 2006 at 3:50pm

Comments

I think it’s good to have a layer of abstraction, so you can build logic into your property get / set if necessary. If a consumer is directly accessing the member variables, you have no level of control about what gets returned. In a more full-blown programming language these members would typically be private, allowing you to encaspulate your implementation and keep it seperate from the public interface to your class.

Taking this approach allows you to expose properties that might not correspond to directly returning the value of a single member variable - for example, you could expose a ‘FullName’ property that returns a value based on title, first name, and surname.

So I’d go for option 2, but I can understand wanting to keep it simple…

# Posted by Oli on Wednesday, October 25th, 2006 at 4:49pm

Neither. I prefer to use prototypes because every time I don’t I find myself (or rather collegues editing my code) blowing the lid off of IE6’s memory management. An hour after working with a complicated js site and IE is using 1gb of RAM.

A while back I wrote a function to implement class-based inheritance (similiar to Dean Edwards’ Base Class) and told everyone to use that and reference EVERYTHING using "this." It doesn’t exactly prevent memory leaks, but it certainly helps to prevent them, and I have one less path to check when I’m trying to find them.

for obvious reasons, foobar.prototype.setbar is going to (potentially) take up much less memory in the long run than foobar.setbar. It would be nice to find a way to implement private variables using prototypes but unfortunately one doesn’t exist (yet).

# Posted by Mark Kahn on Wednesday, October 25th, 2006 at 5:32pm

Coming from a Cplusplus /Java/Perl background, I’d say follow this rule of thumb:

If you have restrictions on values that your member variables can have, then use a setter/getter. If you don’t, avoid them. Also, when using setters/getters, I find that it’s better to have a short meaningful name for your setter/getter than to reserve that for your private variable and give the setter/getter a more verbose name.

Therefore, I’d do something like:

var _foo, _bar;

this.foo = function(value) { if(arguments.length == 1) _foo = value; return _foo; }

That way, you can call it like:

obj.foo(3);

alert(obj.foo());

PS: Excuse the formatting, I couldn’t figure out how to get pre working in the comments PPS: I also couldn’t figure out how to enter a plus sign into the comments - the preview seems to strip them off.

# Posted by Philip on Wednesday, October 25th, 2006 at 8:30pm

I use the second method quite heavily in PHP, but not so much in Javascript. I think the decision on which technique to use comes down to the importance of the variable. Were I to anticipate that the variable would be often reasigned from an outside source I would use method #2, otherwise I would stick with method #1. Additionally the number of variables would play a part. Should there be a large quantity of variables to set I would use method #1, otherwise method #2.

I’ve always found I use more shortcuts and a compact writing style with Javascript as opposed to other languages. For readability purposes I would write method #2 as

function Foobar() {

var foo,bar;
this.setFoo = function(value) { foo = value; };
this.setBar = function(value) { bar = value; };
this.init = function() {
    execute();
};
var execute = function() {
    alert(foo bar);
};

}

# Posted by Steve Tucker on Wednesday, October 25th, 2006 at 9:03pm

I prefer the first method because it is easier for me to read and understand, most likely because it is similar to how I first learned to write objects in JS. As you pointed out, the second one looks more like server-side code, and since I’m a front-end developer, I have no desire to write my JS code in that format. Shorter JS code works best for me.

# Posted by John Riviello on Wednesday, October 25th, 2006 at 10:15pm

The first one. JavaScript is supposed to be simple, so if you really want more formal class definitions, switch to that language. KISS when it comes to JavaScript.

# Posted by Mufasa on Wednesday, October 25th, 2006 at 10:49pm

Everybody knows that the best programmers are lazy and dumb (http://blog.outer-court.com/archive/2005-08-24-n14.html), so I’d probably opt for option #2 because it takes less effort. However, as Oli points out in the first comment, using option #1 (accessor methods) provides you with an extra layer of abstraction that allows you to either filter the data being assigned to the object member, or add extra logic - it’s also an accepted practice.

With all this in mind, my answer would be: whichever method fits the bill! ;-)

# Posted by Tim Huegdon on Wednesday, October 25th, 2006 at 10:57pm

Jeremy, the second example will create a new instance of each method every time you create a new object. So if you have:

var baz1= new Foobar();
var baz2= new Foobar();

baz1.setFoo != baz2.setFoo

This can be a big problem for memory usage.

You’re almost always better off using the prototype method (for all its warts). On the other hand, I often use nested functions to achieve much the same effect as private methods.

And don’t get me started about the ugly prototype (the library) practice of declaring classes.

# Posted by Jeff Watkins on Thursday, October 26th, 2006 at 2:00am

Given these two options, i would certain prefer the latter. In the first, there’s nothing in the interface that even mentions foo or bar, so it’s unnatural to expect the caller to know to set them. Also, as Oli mentioned right off, the abstraction provides valuable protection.

To keep it simple, I’d propose a third option:

baz.init({foo: 1, bar: 2});

# Posted by Matthias Miller on Thursday, October 26th, 2006 at 4:46am

JavaScript is JavaScript. It doesn’t need to be conforming of other programming languages’ methods so I’d go with the first one because that’s the real benefit of JavaScript: simple, easy to read, and it rocks!

# Posted by Martin on Thursday, October 26th, 2006 at 2:02pm

Definitely the latter. Encapsulation is good in any language in any setting, period. If you need to change the behavior of those variables (and you will), it’ll be a lot easier with the second method. Now if only JS had properties a la C#, you could have the best of both worlds.

# Posted by Jeff Cutsinger on Thursday, October 26th, 2006 at 4:12pm

as someone who first learned Java, then struggled to learn and read Javascript.. i prefer the latter.. but still find the fact that you need to call the overall object/class a "function", then you have more "functions" inside of that, confusing.

Java describes it cleanly.. i.e. a a Class encapsulates attributes and methods.. and the word "Class" isn’t re-used again for describing methods. A Class is a class and a method is a method. Of course, there are inner Classes as well.. but they act like a Class. There is no ambiguity.

Flexibility is handy of course. I love Perl as well, where there are many way to do the same thing.. but calling all these things a "function" in javascript is confusing and makes it challenging to debug things for those of us who learned an objected oriented language before javascript.

P.S. love the Dom Scripting book.. Great piece of work.

# Posted by Al on Friday, October 27th, 2006 at 8:56pm

Reading your post made me think you wrote a plugin for Foobar2000

# Posted by Quadro on Sunday, October 29th, 2006 at 11:27am

Generally, I prefer the second because it allows you to do check the value before you set it, so it prevents it from being set to an illegal value. Although, in your short examples, any value is valid effectively valid, so the first would be fine.

But say, for example, your object depended upon foo and bar being integers within a certain range, you’d have to do the second so that you could check.

The other alternative, which is the best of both worlds, is to do the following. Unfortunately, browser support is an issue here.

function Foobar() {
    var _bar = 0;
    this.__defineGetter__("bar", function() { return _bar; });
    this.__defineSetter__("bar", function(value) {
        if (value >= 0 && value <= 100) _bar = value; 
    });
}

var x = new Foo();
x.bar = 10;
x.bar = 150;
alert(x.bar);

# Posted by Lachlan Hunt on Sunday, October 29th, 2006 at 3:01pm

So, I may be paraphrasing everyone’s responses here, but it seems like version 2 is the more "correct" programmatically because it allows you to check the values before setting them, but version 1 is generally more obvious and readable, at least to people who aren’t necessarily coming from a higher level programming language.

It seems that there’s general agreement on the answer: it depends. It depends on what you’re doing and the complexity of your script.

Thank you everybody for chiming in. I appreciate it.

# Posted by Jeremy Keith on Sunday, October 29th, 2006 at 5:02pm

For the quick show of hands, I prefer the first.

If you’re not going to make any verifications, go straight ahead and set the vars straight away.. but sometimes ("it depends") you might want that little layer for verification purposes, so you can have hybrids. Some properties have getter/setters others don’t…

This would make much more sense if you could protect variables against public access, ie, specify the level of access you wanted for each property (public, private, protected… as in Java or other OO languages). Is there a way to do this I don’t know of? If there isn’t, then it actually makes no difference, since someone using that object can get/set the value without using the getters/setters.

# Posted by André Luís on Thursday, November 2nd, 2006 at 4:08am

I’ve kind of got private methods in both examples: the init method is public, the execute method is private. See how init is set using the this keyword, but execute is set using var? Using var inside an object like that effectively creates something that’s private (although it can always be overwritten through the prototype).

Douglas Crockford has more to say on this: http://javascript.crockford.com/private.html

# Posted by Jeremy Keith on Thursday, November 2nd, 2006 at 12:24pm

For the show of hands, I put both of my hands up for number one. I simply disgusted by getters and setters as separate (public) functions. If you need to protect the interface to members via functions, one should be able to to declare accessors like you do in python [1] or delphi [2].

I know that this isn’t supported in javascript, but as an answer to what I like best it’s the answer.

[1] http://docs.python.org/lib/built-in-funcs.html#l2h-57

[2] http://www.delphibasics.co.uk/RTL.asp?Name=Property

# Posted by jens persson on Tuesday, November 7th, 2006 at 6:14pm

You could effectively pass in your values to the constructor - by passing the extra setters for the client code.

var F = function(a, b) { this.init(a, b); }; Foo.prototype = { setA : function(name) {

},
setB : function(name) {

},
init : function(a, b) {
    this.setA(a);
    this.setB(b);
}

};

/* * instantiate :) */

var o = new F(‘hello’, ‘world’);

But yeah, if I had to pick - I’d pick your second option (over the first) Jeremy :)

# Posted by Dustin Diaz on Wednesday, November 8th, 2006 at 1:23am

To this day I still have no idea how to post code on this website and make it look good. Will you be a good lad and share with us your comment input policy?

# Posted by Dustin Diaz on Wednesday, November 8th, 2006 at 1:25am

Do you know how well supported watch and unwatch are? if they are well supported, it would make the first choice much, much better.

# Posted by Jeff Cutsinger on Thursday, November 9th, 2006 at 9:56pm

Sorry, didn’t realize links weren’t allowed. The url for a reference is http://developer.mozilla.org/en/docs/CoreJavaScript1.5Reference:GlobalObjects:Object:watch

# Posted by Jeff Cutsinger on Thursday, November 9th, 2006 at 9:58pm

Sorry. Comments are closed.

October 2006
SunMonTueWedThuFriSat
1234567
891011121314
15161718192021
22232425262728
293031    

Recommended Reading

XML Subscribe

Grab the RSS feed for this blog.

JavaScript API

Grab the RSS feed of comments for this entry.