Home > Programming > Closures vs Objects: FIGHT

Closures vs Objects: FIGHT

In JavaScript, there are two main patterns for creating objects with state - plain JavaScript objects and closures. In this post I’m going to highlight the similarites and consider the pros and cons of the two approaches.

An object is an entity with state and methods to access/modify that state. There are two main approaches to this, which I’ll be calling “objects” and “closures”. For the rest of this post I’ll only use the word object to refer to plain JavaScript objects, in an attempt to avoid confusion.

//object
function Person(name) {
  this.name = name;
}

Person.prototype.sayHi = function () {
  console.log('Hi there, my name is ' + this.name);
};


//closure
function person(name) {
  //using object literal but state held in closure, not in object
  return {
    sayHi: function () {
      console.log('Hi there, my name is ' + name);
    }
  };
}

Now, there are infinite variations to the above. I’m using native JavaScript constructors in the object version, but it doesn’t have to be that way. For example, I could make a function that returns an object, without having to use new:

//alternative object
function person(name) {
  return {
    name: name,
    sayHi: function () {
      console.log('Hi there, my name is ' + this.name);
    }
  };
}

Alternatively, I could come up with a more convoluted example that caches the sayHi method so it’s shared between instances.

The point is, using objects, state is shared through this. Whenever you call a method on an object, e.g.

var dave = new Person('Dave');
dave.sayHi();

this within the method will be equal to the object it was called upon. When using closures however, state is shared through the lexical scope. This highlights the first key difference between objects and closures: access to the internal state.

There are three ways to mutate the internal state of an object in JavaScript. I’ll illustrate with some examples:

//Obtain a reference to the object and assign new properties
function changeName(object, newName) {
  object.name = newName;
}

changeName(dave, 'Bob');


//Attach a function to the object and call it as a method on the object
function changeName(newName) {
  this.name = newName;
}

dave.changeName = changeName;
dave.changeName('Bob');


//call/apply a function with the object as the context
changeName.call(dave, 'Bob');

With closures, on the other hand, there is only one way to mutate the internal state – be inside the scope of the closure:

function person(name) {
  //to change `name`, you *must* be defined somewhere inside this function

  return {
    sayHi: function () {
      console.log('Hi there, my name is ' + name);
    }
  };
}

This can be a blessing and a curse. The advantage of objects over closures is that you’re not limited in the functionality you can add to an object by location in the source code. If you decide that you need to add more functionality to an object, you can do this at any point in your codebase. With a closure the only way to add functionality (with access to the internal state) is to define it somewhere inside the function that creates the closure.

The advantage of closures over objects is the same as the disadvantage but from the perspective of third party code. With an object, anybody can add or change functionality on your object, and access its internal state. With a closure, the internal state is private – it can’t be accessed from outside the closure without the use of accessor functions.

Another advantage that objects have is in terms of memory usage. With a closure, by definition, for a function to have access to the internal state it must be defined inside the closure. That means that each new closure created must have its own version of the function. Objects on the other hand have no such limitation. A function that reads from and writes to this need only be defined once – it can then be added to any object, either shared via the prototype system or through other means.

An advantage that closures have is that you don’t need to keep track of this. With closures it’s simple – you’re either in the correct scope or you’re not. With objects, if you’re in a method called on an object then this is that object, but if the method gets detached from its object (e.g. when passed as an argument) it loses its binding, or if you have a nested function inside the method. Then you need to start messing about with call and apply, and bind and other fun stuff.

So, when should you use objects and when closures? If you’re making hundreds of object-type things then they should probably be objects. If there are only a few and you have security concerns then closures are a better bet.

Privacy isn’t just a security issue – it’s useful for creating a clean separation between the public API and the private implementation. Some developers would say that JavaScript doesn’t provide privacy, so you should get used to writing objects with everything public, and tell users of your code to just not touch certain properties (for example those with a leading underscore). I think it’s useful being able to enforce privacy – it makes sure that no-one will ever write code that’s reliant on an implementation detail of yours.

Because of this, I tend to favour closures, falling back to objects when memory becomes a concern, but that’s largely a personal preference.

  1. Sergio
    September 23rd, 2011 at 13:32 | #1

    Great article, thanks for the point of view.

  2. tilde
    September 26th, 2011 at 08:16 | #2

    enlightening, thanks.

    On the fourth example, shouldn’t it be dave.changeName(“Pete”); ?

  3. September 26th, 2011 at 09:22 | #3

    @tilde Ah, I see what you mean. I’ve added in an argument to that changeName method now, thanks.

  4. Dmitry Pashkevich
    November 3rd, 2011 at 10:48 | #4

    Good insight!

    I would add to the penultimate paragraph (about third-party access to your objects) that for same reasons closures are also much more unpleasant to debug without modifying the source code. No-one will ever mess with your internal implementation nor debug your plugin if it has issues.

  5. November 3rd, 2011 at 10:57 | #5

    @Dmitry Pashkevich That’s true, although I generally don’t use a debugger for debugging – I prefer to just use console.log – so that doesn’t really affect me. Which reminds me, I’ve been meaning to do a post about print statements vs debuggers for a while, thanks!

  6. February 24th, 2012 at 08:25 | #6

    Nice detailed article, clarified well. Thanks for sharing :)

  7. August 3rd, 2012 at 15:44 | #7

    Thanks for this post. It clarified some details for me.

    I’ve been meaning to do a post about print statements vs debuggers for a while, thanks!

    I looked for this and did not find a post. Did you write one on this subject? I would be very interested. Thanks.

  8. August 3rd, 2012 at 16:48 | #8

    @Karl Sadly I never got around to writing that post, sorry! I did collect this data though: https://docs.google.com/spreadsheet/ccc?key=0AlCIVvqRCrTtdHl2SXZlMmtiSTQ2Yk9QOFR1bUYzbVE

  9. Perry
    February 22nd, 2013 at 17:31 | #9

    That was an excellent explanation. Thank you!

    I think this koan story is relevant :)

  10. Jacob
    March 18th, 2013 at 21:51 | #10

    I thought one of the benefits of closures is the ability for each instance to reference (essentially static) members inside the closure so those members aren’t duplicated.

    “That means that each new closure created must have its own version of the function. ” I didn’t realize that was the case. So is this saying if I have..

    function person(){...}
    person.prototype.getName();
    var person1 = new Person();
    var person2 = new Person();
    

    Then getName() isn’t actually duplicated in each instance? Or perhaps your usage of closures is different than what I am thinking of in this case?

  11. July 13th, 2013 at 15:01 | #11

    Getting Gotten Married sproul providing Wedding not seem to study well on the telephone set. This is grounded in Punjab and mostly subscribers you suffered harm as a effect of winning or using mathematical product? And they’re actually overnice highest in the western hemisphere and merely oversteped in the creation by the Shanghai existence Financial Center.

  12. September 15th, 2014 at 08:07 | #12

    I think that is one of the most important info for me.

    And i’m glad studying your article. But should remark on few common issues, The site taste is wonderful, the articles is in point of fact great : D.

    Excellent process, cheers

    Also visit my web site … internal links work ([www.ask.com](http://www.ask.com “www.ask.com”))

  13. October 13th, 2014 at 12:58 | #13

    Everything is very open with a very clear explanation of the issues. It was truly informative. Your site is extremely helpful.

    Thank you for sharing!

  14. October 18th, 2014 at 02:02 | #14

    Currently, the most common occurrence of your is in the government and safety contractor relationship. When it comes to military services weaponry and warfare, you will discover very specific stipulations plus ways of billing that must be put into practice or else fraud has been wholly commited. Defense contractor companies, you should think, may find fraud also intimidating when the government can be involved, but the reality is that it happens quite often. Just how are lots of of these firms a

  15. October 21st, 2014 at 01:55 | #15

    Она была 46. Чат Мари Росарио Silayan BAILÓN в реальном lifewas третий бегун в 1980 г-жа Вселенная конкурсе в С

  16. October 29th, 2014 at 01:11 | #16

    Mutta tärkein viestini on vanhemmille Trayvon Martin. Siellä pyssymiehiä hyökkäsivät aluksi paikallinen vankila, polttava kahden poliisin autot, Bauchi valtion poliisin tiedottaja Nike Kengät Hassan Muhammed kertoi Associated Press.The pyssymiehiä sitten suunnattu työntekijän leiri Libanonin rakennusyhtiö Setraco, joka on alue building tie, Muhammed sanoi . Toinen Tweet lukee, “Ne, jotka kärsivät Little Man oireyhtymä maun yht

  17. October 31st, 2014 at 01:00 | #17

    Ik Networked hard om resultaten disenheartening, want het leek dat mensen alleen gereageerd als ik bood hen gunsten. Een van je sterke punten is een talent voor het zien van de grappige kant van plechtige situaties. Om eerlijk te zijn, ik niet zoals het schrijven van artikelen voor iets van $ 3 … Vertegenwoordiger van de voorstelling was een 48 yard run door Green Ellis op een 3 en 1 play recht door het midden, dat het opzetten van de Bengals eerste touchdown en een 31 yard run door Peerman op

  1. January 10th, 2012 at 06:48 | #1
  2. May 25th, 2012 at 00:49 | #2
  3. September 29th, 2014 at 11:14 | #3
  4. October 8th, 2014 at 03:26 | #4
  5. October 28th, 2014 at 17:51 | #5
  6. October 29th, 2014 at 07:32 | #6
  7. October 30th, 2014 at 02:31 | #7
  8. November 1st, 2014 at 11:20 | #8

Comments parsed as Markdown.