0

I encountered the following behavior:

> foo = {};
{}
> foo.bar = function bar() { return arguments; }
[Function: bar]
> bar()
ReferenceError: bar is not defined
    at repl:1:2
    at REPLServer.self.eval (repl.js:110:21)
    at Interface.<anonymous> (repl.js:239:12)
    at Interface.emit (events.js:95:17)
    at Interface._onLine (readline.js:202:10)
    at Interface._line (readline.js:531:8)
    at Interface._ttyWrite (readline.js:760:14)
    at ReadStream.onkeypress (readline.js:99:10)
    at ReadStream.emit (events.js:98:17)
    at emitKey (readline.js:1095:12)

Isn't bar supposed to be a function in the current scope?

Adding [var] bar = solves the problem:

> bar = foo.bar = function bar() { return arguments; }
[Function: bar]
> bar(1)
{ '0': 1 }

But why doesn't it work without assignment to bar?

Bergi
  • 513,640
  • 108
  • 821
  • 1,164
Ionică Bizău
  • 93,552
  • 74
  • 254
  • 426
  • 1
    it is not `bar()` but `foo.bar()` where your function resides – Dalorzo Aug 13 '14 at 14:17
  • @Dalorzo I know, but it's not `function() {...}` but `function bar() {...}`. – Ionică Bizău Aug 13 '14 at 14:18
  • to scope to `this` you need to append the function to a property on `this` not on you new object. Your new object is actually appended to `this`. – Callum Linington Aug 13 '14 at 14:18
  • @No1_Melman I know that, but I want to add the function both to `this` and `foo` object. – Ionică Bizău Aug 13 '14 at 14:19
  • Don't use `this.var` in your example, but just the global `bar` variable (to limit the confusion to named function expressions, and not include the role of the [`this` keyword](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) – Bergi Aug 13 '14 at 14:20
  • well then after you declare your object on foo, set your `this` property `bar` to the `foo.bar` – Callum Linington Aug 13 '14 at 14:21

3 Answers3

3

The context you are using the function keyword in (on the RHS of an assignment) makes it a function expression, not a function declaration.

Putting a name between function and () makes it a named function, but since it is not a function declaration it doesn't create a variable in the current scope.

Note that named function expressions have memory leak issues in old-IE.

Quentin
  • 800,325
  • 104
  • 1,079
  • 1,205
  • What is a *function expression*? Is there any doc reference regarding this subject? – Ionică Bizău Aug 13 '14 at 14:20
  • 1
    MDN isn't an as good ressource as [var functionName = function() {} vs function functionName() {}](http://stackoverflow.com/q/336859/1048572) on that question (it doesn't strictly distinguish them, and adds in Mozilla's "function statement"s) – Bergi Aug 13 '14 at 14:28
1

When you are using a function declaration of that type in that context, you are creating a named function expression (NFE). Contrast this with simply declaring a named function, when you have a function declaration.

The spec says that the name of an NFE shall only be accessible inside the function itself. Here's how to see the difference:

var x = function() { console.log(foo); }      // (anonymous) function expression
x(); // ReferenceError: foo is undefined

var y = function foo() { console.log(foo); }  // NFE
y(); // function foo()...
Jon
  • 396,160
  • 71
  • 697
  • 768
1

You are essentially creating what is a named function expression. And hence it is not in the current scope but is assigned to the property of the object foo as a method instead.

When using the function keyword in an expression (as opposed to a declaration) when no name is given, you create an anonymous function as you are already aware, I'm sure.

When a name is added between the function keyword and the () in the context of an expression, you are created a named function expression.

The scope of the name of the function is within the function itself, so inside the function, you may recursively call itself using bar() but outside, it does not exist and gives you the ReferenceError that you are encountering.

Siddharth
  • 1,086
  • 3
  • 13
  • 28