-1

For example:

(function foo() {
  var a = 3;
  console.log(a);
});

var obj = {
  a: (function foo() {
    var a = 2;
    console.log(a);
  })
};

obj.a(); // 2
foo(); // ReferenceError: Not Defined

How is that I can access a function expression within obj, but not in the global object?

Edits: for cohesion and clarity

  • I think you're mixing 2 things here. The first part of your function is an IIFE and it will run only once. You cannot trigger that function to run again manually by trying to invoke it. The second code you wrote is an object having function inside it and that will work because it is present during the execution. – Sagar Agrawal Feb 22 '19 at 04:46
  • https://stackoverflow.com/questions/8228281/what-is-the-function-construct-in-javascript – epascarello Feb 22 '19 at 04:50
  • IIFE runs only once, so when you call foo() it will not invoke that IIFE and will give you reference error. – Sagar Agrawal Feb 22 '19 at 04:50
  • with the typos fixed, obj.a is not going to be a method.... it is undefined. – epascarello Feb 22 '19 at 04:52
  • @SagarAgrawal right, but isn't the IIFE not able to be called because the foo declaration is concealed within its own scope? Or does the function cease to exist upon execution? – Christopher Feb 22 '19 at 04:53
  • 1
    @Christopher -- No, in the object, you've assigned IIFE to a property. The value of the property is the return value from the IIFE which is undefined because it is not returning anything but only doing console.log. So obj.a is undefined. Always think, IIFE will execute immediately the moment it is defined. Obj.a is holding the return value of that function execution. – Sagar Agrawal Feb 22 '19 at 04:56
  • It's really unclear what you're asking about here, or where your confusion is. Your first function `foo` is part of an IIFE, but your second *isn't* an IIFE. It's just a function, it's not executed, it's assigned to `a` on `obj`. The two things are not equivalent. – user229044 Feb 22 '19 at 05:03
  • @SagarAgrawal In the interest of testing that I assigned var a to Math.random(); Yet when I call obj.a() each time it returns a different value. Does that not mean it's executing the function each time I call property a? – Christopher Feb 22 '19 at 05:05
  • Yes, of course it's executing each time you call `a`. Your code is identical to `var obj = { a: function () { ... } }`. The fact that you wrapped `function () { ... }` in parentheses doesn't make it an IIFE, it's just a function assigned to a property of an object. – user229044 Feb 22 '19 at 05:06
  • @meagar yes sorry for the confusion. Even if the first function were not an IIFE, I still cannot execute it by calling it because it doesn't belong to the global scope. However if I stuff that same function inside an obj, I can call the property and execute the function? I guess I'm asking why can obj.a access the value of foo, when making it an expression seems to suggest it belongs to it's own scope? – Christopher Feb 22 '19 at 05:08
  • @meagar right but trying calling an expression in the global object. Even if I don't make the first function an IIFE, as long as it's wrapped in (...) I cannot call it and access foo(); – Christopher Feb 22 '19 at 05:09
  • `foo` is irrelevant. `var obj = { a: function () { } }` assigns a function to the property `a`. However, `(function () { ... })()`, does not return a function that you can invoke again. – user229044 Feb 22 '19 at 05:09
  • @meagar I messed up on the syntax a little in posting this question. I don't see the difference between (function foo(){ ... }); and var obj = a: (function foo(){...}) }; Edit: and I understand that one returns a function I cannot invoke again because of scope and the other does, but I want to know how the object can access the function at property 'a' when the global object cannot access (function foo(){...}); – Christopher Feb 22 '19 at 05:11
  • You cannot call the first `(function foo() { ... })` because you're not declaring a variable `foo` in that scope. You're confusing function expressions with function declarations. `function foo() { ... }` is a declaration, and defines `foo`, but `(function () { ... })` is a function expression, and `(function foo() { ... })` is a named function expression. Neither of the function expressions can be called unless you assign the result of the expression to a variable. You would need `var foo = (function foo() { ... })`, which is identical to `var obj = { a: (function foo () { }) }` – user229044 Feb 22 '19 at 05:14
  • @meagar so because I've attached the expression to a property I can execute the function? How does obj.a know how to access (function () {...}) if it wasn't as you said declared in that scope? Or does that named function expression exist within the scope of obj? – Christopher Feb 22 '19 at 05:17
  • @meagar Hmm... interesting. I can't say that makes a whole lot of sense to me, still not sure how the variables know what the contents of foo are (or they just know to execute the function stored in them and then save the return value? That makes sense to me.), but it is what it is I guess. Props for the patience, and thank you lol – Christopher Feb 22 '19 at 05:22
  • Nothing knows what the contents of `foo` are, that's not the right way of thinking of any of this. The result of a function expression **is the function you just defined**. In the first case, you're defining a function expression and then throwing it away, because you don't assign it to anything. In the second case, you *are* retaining a handle to it, `obj.a`. You assign the function you just created to `obj.a`, so you can later invoke it via `obj.a()`. – user229044 Feb 22 '19 at 05:24

1 Answers1

0

You're confusing a couple of different things here.

Your first statement is a function expression, not a function declaration:

(function foo() {
  var a = 3;
  console.log(a);
});

This happens to be a named function expression ("foo"), but it does not introduce a variable foo in this scope. If you wanted to introduce foo so that it can be called again, you need either a function declaration...

function foo() {
  var a = 3;
  console.log(a);
}

foo();

or, you need to assign the function expression to a variable:

var foo = function () {
  var a = 3;
  console.log(a);
}

foo();

Your next bit of code, the object declaration, effectively does this by assigning the function expression to a variable, obj.a:

var obj = {
  a: (function foo() {
    var a = 2;
    console.log(a);
  })
};

The error in your thinking here is due to confusion around foo. In both cases, foo is the name of the function, but it's not actually relevant to invoking the function. You should drop the foo because it's only confusing things.

In essence, your first snippet is equivalent to:

(function () { alert('x'); });

This line of code defines an anonymous function, but does nothing with it. The function exists briefly, is never invoked, and then is lost, because it is not assigned to anything.

Your second snippet is equivalent to:

var x = function () { alert('y') };

This code defines a variable, x, and assigns a function to it. The function can then be invoked with x(), and the function remains available as long as x is in scope.


Your original question is:

How can an object access function expression?

Which doesn't really make sense. The object can't "access the function expression", it just contains a property to which a function has been assigned, while the snippet outside the object did not retain the function in a way that would allow you to invoke it.

user229044
  • 232,980
  • 40
  • 330
  • 338
  • I think I'm understanding this now. Essentially, foo is the equivalent of the variable we can attach to an anonymous expression in order to be able to call it. Meaning, that because I've declared a variable within the object and appended a function expression to it, it can retrieve the return value of the expression in the same way a variable can with an anonymous function even though the variable doesn't have a name to reference the function by. – Christopher Feb 22 '19 at 05:29
  • I think you're confusing things by over using "function expression". A function expression is just an expression that evaluates to a function, the function returned is either retained or not. If you retain it, you can call it. – user229044 Feb 22 '19 at 05:36
  • I understand. I hadn't thought of the 'named' portion of a named function as being equivalent to a variable. Basically I can't call foo from the global object because there isn't a variable to find it that exists within the global object, but as soon as I attach it to an identifier within the global scope I can retain its value. – Christopher Feb 22 '19 at 05:39
  • The name portion of a named function expression is *not* equivalent to a variable. Maybe this is confusing you: `function foo() { }` is a **function statement** not an expression, and it defines a variable `foo` in that scope that you can use to call the function. `(function foo() { })` is a **named function expression** that does not define `foo` in that scope. Unless you assign `(function foo() { })` to a variable, ie `var x = (function foo() { })`, then you lose it. – user229044 Feb 22 '19 at 05:43
  • I just meant a function with a handle as opposed to an anonymous function e.g. there isn't a functional difference between: var a = function (){...}; And function a(){...}; sorry for mixing up verbiage. – Christopher Feb 22 '19 at 05:48