Javascript Closures vs. Prototyped Objects

Started by
8 comments, last by Barzai 11 years, 1 month ago

I've seen a lot of vague stuff about closures in javascript, usually something to the effect of, "closures are powerful, you should learn them." So, I've done some research into closures, and there's usually a pretty fancy phrase about maintaining a lexical scope after the function call has already returned. In practical usage, though, it looks like you end up making a thing that has data members and functions that interact with those data members.

But wait, data and functions for that data: isn't that just an object? I never see anyone state that prototyped objects are powerful though, and I've never seen a job listing say that they want applicants that can prototype objects. As a result I'm trying to get a better handle on the two, and who better to ask than you folks here on gameDev who know a lot about this sort of stuff.

There's a post about it here:

http://c2.com/cgi/wiki?ClosuresAndObjectsAreEquivalent

Some of the folks oppose closures, but, from what I can see, that opposition doesn't apply to the javascript case. They say that it creates an overly strong link between the 2 scopes. However, in the javascript implementation the outer scope stops existing except for in the context of the closure, so it isn't an issue there.

In any case, from what I can see, It looks like the practical differences come down to this:

Closure advantages

They are the only way I know of in javascript to actually have private data members.

Javascript is really loose, so you have to pay attention to stuff you wouldn't in other languages, like scope. Closures let you stop focusing on scope so much, because you define it expicitly when you create the closure.

Prototyped object advantages

They're faster. I've seen a couple of references like this one:

http://blogs.msdn.com/b/kristoffer/archive/2007/02/13/javascript-prototype-versus-closure-execution-speed.aspx

Which show that making prototypes is faster than making closures, probably just because you don't have to make new copies of all the functions each time.

As a result, it looks like closures are better overall if object creation speed isn't a concern, and prototypes are better if it is. However, I'm pretty new to this, so I'm probably missing a lot. Does this analysis look mostly correct? Are there other elements that come into play that I haven't thought of? Any thoughts would be aprreciated.

Advertisement

In practical usage, though, it looks like you end up making a thing that has data members and functions that interact with those data members.

This is not exactly correct, at least not in most languages. The thing you make refers to the same variables as are being closed over; not just the same data or the same references. You're not actually making any new data members. Closures can be made to look like objects (and vice versa due to computational equivalence) but are different beasts. This is more important in a language like C# where concurrency can cause weird (and/or awesome) effects with closures. Javascript does not have that concern.

The thing you make refers to the same variables as are being closed over; not just the same data or the same references. You're not actually making any new data members

That's an interesting distinction. In my mind I usually think of data members as local variables, and methods as functions with a pre-defined scope, but I guess this isn't technically correct.

One possible implication in the javascript case could be whether things are values or references. [From what it sounds like, the variables in the closure can't be references, they are definitely values.] I can see the possibility of believing a data member of a prototyped object to be a value when it is actually a reference. That could potentially create some errors.

**Edit I realized a bit after I wrote this that I have no reason at all to believe that the part I put in brackets is true. You could certainly pass an object to a variable in the closure, and that would be accessed by reference. I guess I just sort of pictured the closure as some sort of inpenetrable wall, but there's no reason for that to be the case. Here's where I'm getting this thought from, anyway:

http://snook.ca/archives/javascript/javascript_pass

I don't think you should choose one over the other. Both are core parts of the javascript language and you should learn both and how they can be used.

closures, or anonymous function can help inject logic at runtime


var img1 = new Image(), img2 = new Image();
img1.onload = function() { console.log('my image has loaded'); }
img2.onload = function() { alert('my image has loaded'); }
img1.src = 'some/image.png';
img1.src = 'some/image.png';

//after the browser has downloading the images, the image objects will call their onload function.

prototypes let you change or add functionality to existing or custom types and objects


String.prototype.hello = function() { return "hello " + this; }

console.log("world".hello());
My JS is too rusty to give an answer specific to that language, but in general:
One of the main benefits of closures is the syntactic sugar of being able to automatically capture variables from the surrounding environment.
For example, in this pseudo-code (no specific language), compare the number of lines required to make a closure that will clean up the world, compared to an object that will do the same work:
function InitWorld( onShutdown )
  var grass = new Grass
  var sky = new Sky
  onShutdown.Add( // list of functions
    function()
      grass.delete() // implicitly capture the local variables
      sky.delete()
    end )
end
 
function InitWorld( onShutdown )
  var grass = new Grass
  var sky = new Sky
  var deleter = 
  {
    a = grass,//capture the local variable into object members
    b = sky,
    OnDelete = function()
      this.a.delete() // there are no local variables here, have to use object members
      this.b.delete()
    end
  }
  onShutdown.Add( deleter ) // list of objects with OnDelete functions
end

O.K. Things are starting to make a bit more sense. I think I focused too much on one part of Telastyn's post earlier. The other part that applies to my figuring this stuff out better is


Closures can be made to look like objects (and vice versa due to computational equivalence) but are different beasts.

I've been focusing on the case in which I plan to create a thing that is going to have some information and ways to manipulate that information, and I can make that thing either be an object or a closure. In reality that is only one possible use for a closure, and a good one if you want to have private data in javascript. However, there are other uses for closures besides making something that looks like an object.

Hodgeman, that usage, wow. This may be a little off topic, but is that sort of a demonstration of why the "Closures and Objects Are Equivalent" link from my opening post has sub-parts that suggest that closures come from functional languages and objects come from object oriented?

I ask because, in your closure example, you're adding functions to onShutdown. I believe you get to do that because the data part is automatically captured by the closure. In the object example you're adding objects to onShutdown, I believe because you have to without automatic data capture. So, the closure gives much more tidy code to accomplish the same thing by leveraging the automatic data capture. Although, on rereading I think that's what you said here:

One of the main benefits of closures is the syntactic sugar of being able to automatically capture variables from the surrounding environment.

You just said it more efficiently.

Anyway, thanks for the inputs everyone. This is incredibly helpful to me.

I believe you get to do that because the data part is automatically captured by the closure. In the object example you're adding objects to onShutdown, I believe because you have to without automatic data capture. So, the closure gives much more tidy code to accomplish the same thing by leveraging the automatic data capture.

Quoted for emphasis. Using closures can be much tidier than traversing and querying objects for data at call time.

Still, that's just one benefit of closures, resp. automatic context capture.

So, I've been thinking about this a lot more, and I think I may have finally connected with a fundamental difference between objects and closures that for some reason just didn't click before:

Closures have 2 scopes to play with. They have the outer scope that get closed on, which is the scope I focused on when I thought about them before, but the inner function also has a scope. So when it gets used, it gets to play with 2 scopes instead of just one, and that allows the simplification of a lot of code. This may not be exactly accurate (and please, point it out if it isn't), but it looks like using 2 scopes lets you set things that will act as constants at run time in a really simple, tidy way. There are probably several other uses of having 2 scopes as well.

Rereading some of the posts up there, the two scopes thing seems to be implied. I just didn't quite grab it until now.

Now, I've never read any definitions of closures put quite like that before, so I recognize that somehow I may well be getting this wrong again. Does this, now, seem mostly correct?

Not exactly. The outer scope only lets you use things as constants if those things are actually constant. If the other scope's variables change, then the closure will see them change.

This is what I meant about closing over _variables_ rather than values or references.

I think I get that part, Telastyn. When I wrote the part about constants, I was thinking in term of one of the examples from the MDN article about closures, this one:

https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Closureshttps://developer.mozilla.org/en-US/docs/JavaScript/Guide/Closures

function makeAdder(x) {
return function(y) {
return x + y;
};
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
print(add5(2)); // 7
print(add10(2)); // 12
In this case, once x is set, there is no possible access to it (I think?), so it works like a constant. I get that, if you give the ability to access x in some way, it will not work as a constant.

For me the big understanding breakthrough was the notion of 2 scopes. In my mind now, closures and objects are close to each other. But they differ in that

closures:

When you set it up, you get an extra scope to play with. After setup, without work that scope is set in stone. With work, not necessarily. It takes extra effort to have multiple methods, though. You can do some important things, though, especially in Javascript where you usually only get a new scope with a function declaration. An example is the use of closures to add a unique value to a thing in a loop. Since loops don't give a new scope in javascript, exploiting the extra closure scope is useful.

objects:

1 scope, but its really easy to have multiple methods.

In any case, this is probably a bit wrong, too : ) If so, if you don't mind, I of course would appreciate correction.

Anyway, I'm incredibly happy with the input you guys have given here. I tend to really get systems of things when I can place them in a framework somehow. I feel like closures fit the javascript framework pretty well for me in my mind now, thanks to your help. Although, I'm sure I probably still don't have it quite right. : )

Cheers

**Edit

I just had a realization. In your first post, you said:

Closures can be made to look like objects (and vice versa due to computational equivalence)

It would probably be useful to me to make something that works like a closure out of some objects, rather than making something that works like an object out of a closure. That may give a lot of understanding of the 2.

This topic is closed to new replies.

Advertisement