13

I know that this form:

var foo = function bar() {};

will leak the bar name to the enclosing scope and create two functions in jscript.

How about:

var foo = function foo() {};

?

It still leaks the name to enclosing scope, but it's in there anyway (thx to var foo).

I know it will be defined in the whole scope, but will it create two functions and immediately dereference/destroy one of them or is this still causing a leak?

In this situation:

var bar = function() {
    foo();
    var foo = function foo() {};
}

Will we have two function objects inside bar()?

edit

Ok it most definitely creates two function objects, now the question is: does the function created by named definition get dereferenced and cleaned up by GC after the var foo line, so there is no more than one 'live' foo instance at any moment in the code above?

Or will IE being IE leave it dangling forever, since there's no way to "dereference" the foo created by the definition and it shouldn't even be there in the first place?

soulcheck
  • 36,297
  • 6
  • 91
  • 90
  • "in IE"... just fyi this has been fixed since IE9... – Christoph May 30 '13 at 11:24
  • 6
    http://kangax.github.io/nfe/ – Ven May 30 '13 at 11:30
  • @user1737909 that article doesn't say anything specifically about the `var foo = function foo() {};` where the name of the function and variable are the same. in particular, the article mentions manually dereferencing the name. I was wondering if in my case everything gets cleaned up nicely. – soulcheck May 30 '13 at 11:38
  • My 2 cents...I would stick with `var foo = function foo() {};` regardless of how it affects IE < 9. It's good style and is useful when errors are thrown to see in what function they occurred, and just using `function foo() {}` by itself isn't always viable. – Matt Browne May 30 '13 at 12:34
  • 1
    In theory, this would create a function declaration which is hoisted, then once reaching that line in the code would overwrite the function definition with the function expression, allowing the original to be garbage collected. Oddly enough, if this is done, when `toString()` is called on the function, it will show up with the name of the function, even with the odd leaking of scope of the function name. – Qantas 94 Heavy May 30 '13 at 12:35
  • @Qantas94Heavy yeah, looks like it does that. I'll try to prepare a benchmark to see if it's actually freeing the extra memory. – soulcheck May 30 '13 at 14:45
  • If you call bar() you will have a bug in your last sample code. http://jsfiddle.net/S9UhZ/4/ I think it's because foo() is called before defined. – Vitor Canova May 31 '13 at 16:30
  • @VitorCanova not in ie <= 8 :) – soulcheck May 31 '13 at 16:32
  • @soulcheck Sorry. I understood it doesn't leak in IE9+ but does't break too. ;) – Vitor Canova May 31 '13 at 16:34

1 Answers1

1

When parsing the statement var foo = function foo() {};, the var foo declaration is most likely assigned after function foo(){} is executed.

That means that function foo will be defined in the global scope, that is usual window, first.

After that, var foo becomes assigned and thus hiding window.foo from your scope for the name foo. So in fact, your code defines window.foo or window.bar, which is not garbage collected if your current scope is left.

dronus
  • 10,774
  • 8
  • 54
  • 80
  • Why would the function be defined in global scope? – Felix Kling May 31 '13 at 19:04
  • Because `function foo(){}` behaves something like `foo=function(){}` would. And `foo=something;` without an `var` statement would actually assing `window.foo` while the global scope is `window`, which it is by default for browser script. – dronus May 31 '13 at 19:18
  • That would mean that every function declaration is global, which is incorrect. `function foo() {}` is **not** equivalent to `foo=function(){}`. – Felix Kling May 31 '13 at 19:20
  • In fact there is no `var` statement for function definition, so the usual way to get a local-only function is to assign an anonymous function to a local variable, like `var foo=function(){}` would do. – dronus May 31 '13 at 19:20
  • I can prove you wrong. According to you I should be able to call `bar`: http://jsfiddle.net/Hz6uU/. Function declarations *always* create functions in the scope they are in. – Felix Kling May 31 '13 at 19:22
  • Ok, so the example only would hold for global scope. For a function defined inside a function, `bar` won't leak to window scope, but is still defined inside the function scope. But how can that be useful? For what reason should I use `foo` and `bar` to call the same function? Maybe it is useful for debugging to have the function named `bar` while I use `foo` to assign a callback... – dronus May 31 '13 at 19:36
  • 1
    Named function expressions are useful for a) debugging and b) recursion. The specification defines that the name of such a function should only be visible *inside* the function itself, i.e. not leak in the enclosing scope. But it's a known bug in IE (<9) that it creates two functions. That's what this question is about. (and since it is bug, there is nothing useful about it). – Felix Kling May 31 '13 at 19:39
  • `function baz() { var foo=function bar(){document.write('hello')}; document.write("And bar is..: "+bar); } baz(); ` would print `bar` in Chrome either. – dronus May 31 '13 at 19:43
  • I get `ReferenceError: bar is not defined`. Maybe you have `bar` defined from a previous test? – Felix Kling May 31 '13 at 19:44
  • Maybe it depends on quirks mode, I used a plain HTML file without HTML type definition. – dronus May 31 '13 at 19:45
  • 1
    I don't think Chrome's JavaScript engine treats those differently. It is defined in the specification that the name is only visible inside the function and only IE is known to have this problem. – Felix Kling May 31 '13 at 19:47
  • You're right, that was an artefact of old code it seems. Beware of strange JS state caching. – dronus May 31 '13 at 19:49