28

The closure code is very short:

var fn = function() {
    return function() {
        console.log(arguments);
    }
}

(function(arg) {
    console.log('bar');
})('foo');

Why ["foo"] is printed instead of bar? If I comment out var fn = ... , the result is as expected and bar is printed. How can those 2 pieces of code be related?

George
  • 36,413
  • 9
  • 66
  • 103
MichaelYu
  • 555
  • 2
  • 6
  • 16
  • A [fiddle for you](http://jsfiddle.net/bS2uN/) – Liam Apr 09 '14 at 10:41
  • 2
    Read the accepted answer: [Semicolon before self-invoking function?](http://stackoverflow.com/q/7365172/1612146) – George Apr 09 '14 at 10:43
  • 1
    look how beautiful the code is! i like it – doniyor Apr 09 '14 at 10:47
  • Now that you have your question answered, consider the following puzzle: `var a = d * e NEWLINE (d + e).blah() NEWLINE` (1) where are the semicolons inserted? (2) can you provide code that runs before this fragment that makes it do something? Your example and this example illustrate why auto semi insertion was a bad idea in the first place. It turns a minor, easily fixed programming error that would be detected immediately by the compiler into a series of pitfalls that trap unwary programmers by changing the meaning of their program unexpectedly. – Eric Lippert Apr 09 '14 at 15:46
  • 1
    This almost looks like a trolling attempt. Did you write this yourself or did you find it somewhere? – rvighne Apr 09 '14 at 16:15

3 Answers3

31

Without the semicolon after the } of the fn, you are actually calling the fn with argument (function...).

If you add the missing semicolon, it works as you expect:

var fn = function () {
    return function () {
        console.log(arguments);
    }
};

(function (arg) {
    console.log('bar');
})('foo');
rvighne
  • 20,755
  • 11
  • 51
  • 73
dkasipovic
  • 5,930
  • 1
  • 19
  • 25
  • A minified example would be `(function() { return function() { console.log(arguments); }})()('foo')` that also yields `foo`. – h2ooooooo Apr 09 '14 at 10:45
  • Yes, as I said, without the semicolon, although not obvious by formatting, the second part is actually joined to the first. – dkasipovic Apr 09 '14 at 10:46
  • 1
    I agree that you said it - I just added it for information. It wasn't an answer, so the correct answer was the best place to add it. :-) – h2ooooooo Apr 09 '14 at 10:47
  • Yeah yeah of course, I just wanted to point out that in this case the formatting is the culprit for what happened. He probably thought that these two parts are unrelated, because of the formatting. – dkasipovic Apr 09 '14 at 10:48
  • 2
    Actually he's not calling `fn`, but assigning the result of two invocations to it (`undefined`). – Bergi Apr 09 '14 at 10:51
  • There should also be a semicolon at the end of the `return` statement. – acelent Apr 09 '14 at 18:41
  • @D.Kasipovic - so why does the scoping break? I'm not sure I understand the control flow correctly. Care to elaborate? – PhD Apr 09 '14 at 21:49
  • Why do you think it breaks? – dkasipovic Apr 10 '14 at 06:54
4

Why ["foo"] is printed instead of 'bar'? How can those 2 pieces of code be related?

With the parenthesis around the (function(arg) {…}) it is considered as a function expression's argument, just as you expected ('foo') to be the argument of the IEFE. Actually, foo is now passed to the function that is the result of the first invocation:

var fn = (
        (function() {
            return function() {
                console.log(arguments);
            };
        })
        (function(arg) {
            console.log('bar');
        })
    )
    ('foo');

To fix this, either always put a semicolon after your assignments, or use a function declaration:

function fn() {
    return function() {
        console.log(arguments);
    }
}
(function(arg) {
    console.log('bar');
})('foo');
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
3

adding a semicolon after your variable definition like so:

var fn = function() {
    return function() {
        console.log(arguments);
    }
};

(function(arg) {
    console.log('bar');
})('foo');

logs 'bar'.

algoni
  • 645
  • 3
  • 8