Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why not to use closures for object attributes?

I'm currently writing objects in javascript and I would like to do it in a clear, nice way, using best practices etc. But I'm bothered that I must always write this. to address attributes, unlike in other OO languages.

So I got the idea - why not just use closures for object attributes? Look at my example object. So instead of this, classical way:

var MyObjConstructor = function (a, b) {

    // constructor - initialization of object attributes
    this.a = a;
    this.b = b;
    this.var1 = 0;
    this.var2 = "hello";
    this.var3 = [1, 2, 3];

    // methods
    this.method1 = function () {
        return this.var3[this.var1] + this.var2; 
            // terrible - I must always write "this." ...
    };

}

... I would do it using closure and then I don't need to write this. every time to access the attributes!

var MyObjConstructor = function (a, b) {

    // constructor - initialization of object attributes
    // the attributes are in the closure!!!
    var a = a;
    var b = b;
    var var1 = 0;
    var var2 = "hello";
    var var3 = [1, 2, 3];

    // methods
    this.method1 = function () {
        return var3[var1] + var2;
            // nice and short
    };

    // I can also have "get" and "set" methods:
    this.getVar1 = function () { return var1; }
    this.setVar1 = function (value) { var1 = value; }
}

Also, it has a hidden benefit that the attributes really cannot be accessed any other way than by get/set methods!!

So the question is:

  1. Is this a good idea? Is it "clean", is it conforming to best practice?
  2. Are there any other semantical differences between these 2 solutions?
  3. Are there any traps with using closure like this?
like image 756
Tomas Avatar asked Oct 20 '11 11:10

Tomas


People also ask

What are the disadvantages of using closures?

Disadvantages of closures There are two main disadvantages of overusing closures: The variables declared inside a closure are not garbage collected. Too many closures can slow down your application. This is actually caused by duplication of code in the memory.

When should closures be used?

Closures are frequently used in JavaScript for object data privacy, in event handlers and callback functions, and in partial applications, currying, and other functional programming patterns.

Are closures like objects?

Objects are a subset of closures, so they carry some similar traits. Note: objects and closures over lexical scopes are equivalent. Idiomatic style of programming in a language that allows nested function definitions takes advantage of this fact, rather than being confounded by it.

Are closures function objects?

Function objects (C++) As of the 2011 revision, the C++ language also supports closures, which are a type of function object constructed automatically from a special language construct called lambda-expression.


2 Answers

95% performance decrease.

An actual Benchmark so for your (simple) example were talking 50%-85% performance decrease across browsers.

Seriously, closures are slow as hell.

Now using closures for data isn't the problem, but using closures for functions/methods is. And you can't do one without the other. Methods that live on the prototype have no mechnanism of accessing local variables that live inside the constructor.

And the other problem is your "classical" example doesn't use the prototype :\

What you really want is

  • Doing OO properly
  • Understanding prototypes as classes

So the following is also bad.

var MyObjConstructor = function (a, b) {

    // constructor - initialization of object attributes
    this.a = a;
    this.b = b;
    this.var1 = 0;
    this.var2 = "hello";
    this.var3 = [1, 2, 3];

    // methods
    this.method1 = function () {
        return this.var3[this.var1] + this.var2; 
    };

}

You want

// constructor - initialization of object attributes
var MyObjConstructor = function (a, b) {
    this.a = a;
    this.b = b;
}

Object.extend(MyObjConstructor.prototype, {
    var1: 0,
    var2: "hello",
    var3: [1, 2, 3],
    // methods
    method1: function () {
        return this.var3[this.var1] + this.var2; 
    }
});

For some value of Object.extend. Here were placing any common data or methods on the prototype and sharing that data among all instances. This way we are not memcopying everything everytime everywhere.

// terrible - I must always write "this." ...

The alternative is duplicating state for every single object. The closure pattern is nice and all but it's just not performant.

like image 80
Raynos Avatar answered Oct 17 '22 21:10

Raynos


To answer your questions directly:

1. Is it OK to use objects as closures? Is it conforming to best practices?

Yes. In some situations you really want to have private fields so this is the only way one the ways to do that. For a real, concrete, example have a look at Deferreds/Promises in Dojo or JQuery. The Promises implement just the non-mutating subset of deferreds so they need to keep their inner Deferred private to avoid others from changing it directly.

Do remember that you should only really use hidden fields where you really need them (and not for trivial reasons like not having to type "this"). Using plain old public fields and "normal" objects is also perfectly fine, especially if you consider that they have some advantages that the closure version doesn't have:

2. Is there any semantic difference between these two versions?

Yes.

  • You can't inspect private fields directly (duh). This also means you can't easily clone objects or do other kinds of reflection on them.
  • Accessing a field via an object property instead of a direct reference allows you to use prototypal inheritance. The parts that matter are that:
    • You have a hard time overriding things in a subclass (variables in a closure are static, not virtual)
    • You can't add other methods latter that use these hidden fields (since they are only accessible inside the constructor function). Particularly nasty for subclassing.

3. Are there any traps on using a closure like this?

Most Javascript engines today are less performant on code with lots of closures compared to code that uses prototypes. Not a "real" reason for a difference (since LISP engines have been fine with closures since forever) but something you will have to live with.

like image 36
hugomg Avatar answered Oct 17 '22 19:10

hugomg