Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript - Use closures sparingly?

Tags:

I'm watching http://www.youtube.com/watch?v=mHtdZgou0qU, and at about 13:37 (hehe), he shows a slide of a list of things to avoid due to the addition of a new object onto the scope chain.

I understand what he's saying with using and try-catch statements, as well as accessing out-of-scope variables, but I don't understand why closures should be avoided. If the closure's local variables are going to be on the top of the scope chain, where's the performance loss?

like image 545
mowwwalker Avatar asked Mar 19 '12 00:03

mowwwalker


People also ask

What is disadvantage of closure in JavaScript?

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 I use closure in JavaScript?

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 the advantages of closures in JavaScript?

The advantage of closures in javascript is that it allows you to bind a variable to an execution context. var closedIn = {}; var f = function(){ closedIn. blah = 'blah'; // closedIn was just "closed in" because I used in the function, but it was defined outside the function. }

Should I use closures?

Practical closuresClosures are useful because they let you associate data (the lexical environment) with a function that operates on that data. This has obvious parallels to object-oriented programming, where objects allow you to associate data (the object's properties) with one or more methods.


2 Answers

It's because, to look up variables that are not local, the VM has to walk up the scope chain to find them. Local variables, on the other hand, are cached, so a local variable lookup is much faster. The more nested a function is, the longer the scope chain becomes, and the more the potential performance impact increases.

This is partly why you often see code like this in popular JS libraries:

(function(window, document, undefined) {   // ... })(window, document); 

Here, window and document become local variables, so looking them up becomes much faster, which becomes pretty noticeable if you reference these objects thousands of times from within your code.

This page has a really in-depth description of scope chains and execution contexts. (The entire article is interesting if you have the time to read it.)

Overall, though, modern browsers optimize all of this stuff to the point where it's basically negligible, so it's not something I would worry about.

like image 142
Sasha Chedygov Avatar answered Sep 25 '22 18:09

Sasha Chedygov


The linked video explains why closure can inflict some performance hits starting about 11:08.

Basically, he's saying that for each nested function, it adds another object to the scope chain and therefore accessing variables outside of the closure will take even longer.

To find the value associated with a variable, the Javascript interprer follows this process:

  1. search the local scope object
  2. if 1 didn't work, search the parent scope object
  3. if 2 didn't work, search the parent's parent scope object
  4. keep searching parent scopes until
  5. you search the global scope
  6. and if it's still not found, throw an undefined variable error.

In a normal function, to find a variable, you only have to search at the top of the scope chain. A closure, on the other hand, to find parent variables will have to search down the scope chain, sometimes several levels deep. For example, if you had some closures like this (note that this is a very contrived example):

function a (x) {   function b (y) {     return (function (z) {       return x + y + z;     })(y + y);   }   return b(x + 3); } 

From the innermost function, to evaluate the expression x + y + z, it has to traverse up three levels in the scope chain to find x, then it has to traverse up the scope chain again two levels to find y, and then finally once to find z. In total, it had to search six objects in the scope chain to return the final result.

This is unavoidable in closures, because closures always have to access parent variables. If they didn't there would be no purpose in using a closure.

Also note that in Javascript, there is a significant overhead in creating functions, especially closures. Take, for example, this fairly simple closure:

function a(x) {   return function (y) {     return x + y;   } } 

And you call it several different times, like this

var x = a(1); var y = a(2); var z = a(3); alert(x(3)); // 4 alert(y(3)); // 5 alert(z(3)); // 6 

You'll notice that the function returned from a has to keep what was passed as an argument in the parent function even after the parent function has already been called. This means that the interpreter has to keep in memory what you passed in to every function that you have called so far.

like image 24
Peter Olson Avatar answered Sep 24 '22 18:09

Peter Olson