-1

The two function objects:

// toplevel
var f1 = function(){return k;};
var f2 = (function(k){return function(){return k;}})(42);

have the same source code "function(){return k;}" but f1 is a function where k is looked up in the global environment, f2 is instead a closure that captured a local k.

Is it possible to tell f2 is a closure? typeof for both is "function" and doesn't help...

For example storing the source code of a function in a database may make sense as you can rebuild the function with eval. Storing the source code of a closure instead is not going to work because of captured variables.

6502
  • 112,025
  • 15
  • 165
  • 265
  • 4
    Why do you need to differentiate between a function that is a closure and one that isn't? – Quentin Mar 27 '16 at 20:29
  • What do you mean different? Even if you define `f1` and `f2` as exactly the same you'll get: `f1 === f2 // false` – Omri Aharon Mar 27 '16 at 20:29
  • @Quentin: while it may make sense to store a function source for example in a database, storing a closure source wouldn't work because a closure cannot be rebuilt from that alone... – 6502 Mar 27 '16 at 20:31
  • 1
    @6502: But both of your functions pull `k` from their enclosing context, so it doesn't really make sense to store *either one*'s source in a database. (In fact, although you describe `f1` as a "pure function", it's actually `f2` that's the pure function, since it always returns the same value (42), whereas `f1`'s behavior depends on a variable whose value can change between invocations.) – ruakh Mar 27 '16 at 20:38
  • @ruakh: indeed "pure" can have many meanings and most often is about not depending on anything but parameters; removed that word as it was probably confusing. – 6502 Mar 27 '16 at 20:42
  • How do you define "function" and how do you define "closure", exactly? – Oriol Mar 27 '16 at 20:44
  • There _is_ a non-standard method in `Function.prototype` called `Function.caller` that lets you identify what called a specific function. You will probably have to incorporate it in some fancy way into the returned function (closures like this are still considered top-level definitions, so they return null if `caller` is called on them directly) , but otherwise I think what you're asking for is pretty much impossible from a pure Javascript standpoint. – Akshat Mahajan Mar 27 '16 at 20:45
  • if your question is regarding detecting functions that use bound or unbound variables, keep in mind that in `f1`, `k` could've been defined in only certain ways; in node.js environment for example it can be defined by either: a module `k = require(...)`, global context `k = global...k` or in a bigger closure. – homam Mar 27 '16 at 20:50

3 Answers3

2

Closures aren't types. Closure is what lets a function access variables in its scope, even after that scope should be gone. Check out he books You Don't Know JS for a more detailed description of this.

The second thing you put is an immediately invoked function. The ( ) around the function makes it an expression. It gets evaluated and Returned, and then is immediately invoked.

What's happening is that f1 is defined in the top level scope, but f2 is defined in an inner scope of an immediately invoked function and then returned to the top level. Closure is what lets f2 access k after its defined scope should have been destroyed. It would be said that f2 has a closure on k.

In short, no there is no way for you to tell in what scope the function was created.

ncphillips
  • 736
  • 5
  • 16
1

As ncphillips said, Closure isn't a js type. It's a data structure designs to solve the dynamic scope problem. You can take a look at this link : https://en.wikipedia.org/wiki/Scope_(computer_science)#Lexical_scope_vs._dynamic_scope In most functional programming language, the closure is transparent to the developer, there isn't a way to visit or control this structure. Every time the vm create a closure(commonly happens when you declare a function), it looks up the scope chain and 'make a link to them (that's my word, maybe not very clear)'. In your code :

var f1 = function(){return k;};
var f2 = (function(k){return function(){return k;}})(42);

You can see, the function that f1 ref to and the function f2 ref to have different scope chain, although they both return k, but what k refs to isn't the same area. It's not saying that if f2 or f1 is a closure, they are both function, they both have their closure, but in this example, they don't ref to the same closure.

They both return k, when they do that, they will look inside their closure ( more or less equals their scope chain)to find the 'k'. For f1, you didn't give it a 'k' in this code, so it keep look up, until global, if still hasn't a 'k', then return undefined. For f2, the scope in function(k){} is f2's 'lowest scope', and it found a 'k', so return it. This is the difference.

The keyword of closure creation is function declare, when the vm declare a function, it give the function a closure, rely on the scope that the declaration happens.

My English isn't good, just hope this can help you.

cyl19910101
  • 176
  • 1
  • 7
0

If you look in the Chrome debugger at f1/f2.prototype you get an expandable Object{}. Inside you have a constructor that is also expandable. Once you expand that, inside you can see a <function scope> item, that contains k and its value.

According to the ECMA standard, the scope of a closure is inaccessible programatically.

That being said, I wrote a proof of concept code that could determine if a function is a closure or not, tailored on your example functions. Different types of closure need more complex mechanisms, but it might work:

var k=10;
var f1 = function(){return k;};
var f2 = (function(k){return function(){return k;}})(42);
function isClosure(f) {
    var testF=new Function('return ('+f.toString()+')();');
    return testF()!=f();
}

alert('f1 is '+(isClosure(f1)?'':'not')+' a closure\r\nf2 is '+(isClosure(f2)?'':'not')+' a closure');
Siderite Zackwehdex
  • 6,293
  • 3
  • 30
  • 46