Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Closures vs. classes for encapsulation?

I'm new to JS (from C++/etc), and it's just occurred to me that closures seem to be a simpler and more convenient way to handle encapsulation than classes. This code seems to give a simple way to handle encapsulation:

function addProperty(o) {    var value;     o["get"] = function()  { return value; }    o["set"] = function(v) { value = v; } }  // create two independent objects which are instances of pseudo-class 'addProperty', // which each have their own version of a set of local fields, and methods that // operate on those fields: var a = {}; addProperty(a); var b = {}; addProperty(b); 

If you just want a class to handle encapsulation (in C++, I find this is most of the time), is there any good reason to use a JS class instead of a closure? The code above seems to me to be more intuitive and compact than JS classes. No constructors, prototypes, or excessive use of 'this'. You also get the benefit that you must explicitly declare local fields, instead of hoping that you don't make any typos in your constructor.

EDIT

Ok, I'll just clarify. Seems like the 'class' word gets some backs up. A "class", to me anyway, is an extension of the type concept, and JS doesn't qualify on that front, but I can do various class-y things with what my book (Flanagan) spends 50 pages calling classes. Sort of.

Anyway, the real question is this: I'm using jQuery tabs on my first web app. I noticed yesterday that this doesn't work, because my JS code doesn't keep any private state for each tab. When I swap between tabs, the dynamic/mouse parts of my code no longer work properly.

So, what's the best way to introduce private state into the app? Most of the code is safe, but everything that handles dynamic behaviour needs some way to encapsulate per-tab local state. With a C++ background, the obvious answer to me is to write a class that defines the dynamic parts of a tab, and to instantiate a new 'tab' object each time a tab is created. What I'm finding it difficult to get my head around is whether JS pseudo-classes actually make any sense here, or whether I should extend the code above.

Just read the module patterns link from Jonathan, and it now seems to me to be that that may be the answer.

Thanks.

like image 434
EML Avatar asked Jan 04 '12 15:01

EML


People also ask

Is closure same as encapsulation?

A closure is an example of encapsulation: it encapsulates the body of code together with the lexical scope. The only means of access into the capsule is through the function: the function is like a "method", and the elements of the captured lexical environment are like "slots" in an object.

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.

What are advantages of closure?

Advantages of closuresThey allow you to attach variables to an execution context. Variables in closures can help you maintain a state that you can use later. They provide data encapsulation. They help remove redundant code.

Is Class A closure?

A class instance has properties and methods, and usually multiple of them, whereas a closure is simply a function that you can call - with a single functionality. The syntax to invoke them is different, the extra method name is sometimes superfluous and sometimes beneficial.


2 Answers

The reasons to avoid closures is overhead.

Your get and set functions are trivially 20x slower than properties. Your closures also have a large memory overhead that is O(N) with the number of instances.

Also note that these encapsulated variables have zero real benefit, they just infer performance penalties.

var AddProperty = {   constructor: function (v) { this._value = v; return this; },   get: function () { return this._value; },   set: function (v) { this._value = v; } };  var a = Object.create(AddProperty).constructor(1); var b = Object.create(AddProperty).constructor(2); 

I noticed yesterday that this doesn't work, because my JS code doesn't keep any private state for each tab.

Your problem is not that you don't have private state, it's that you're using global state.

The easy solution is to have an object per tab (or a "struct" if you prefer) and store state in it.

So all you have to do is define a tab

var Tab = {   constructor: function (...) {     /* init state */   },   doTabStuff: function () { /* some method */ },   ... } 

And then create new tabs when you need them

var tab = Object.create(Tab).constructor(...) 
like image 147
Raynos Avatar answered Sep 21 '22 23:09

Raynos


The benefit of a function for the purposes of encapsulating functionality is that you can use the module pattern:

http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth

The module pattern provides the capability of creating private members and methods, without something with a lot of overhead like ease.js:

http://easejs.org/

like image 31
Jonathan Rich Avatar answered Sep 19 '22 23:09

Jonathan Rich