0

Hello I have started to learn some javascript and I can't wrap my head around this in "normal" functions. I don't understand why the following two functions output different results. f2 outputs 5, while f1 outputs 1. Why is that?

var f1 = function(){
  var x= 1;

  var add = function(){
    x=5;
  };

  var result = function(){
    console.log(x);
  };

  return {
    add: add,
    result: result
  };
};

f1().add();
f1().result();

var f2= (function(){
  var x= 1;

  var add = function(){
    x=5;
  };

  var result = function(){
    console.log(x);
  };

  return {
    add: add,
    result: result
  };
})();

f2.add();
f2.result();
3
  • 1
    You're using the same x global variable, as you didn't declare it with var, is that the intention? Commented Jan 21, 2014 at 0:36
  • Sorry, I forgot. I added var, but f1 still outputs 1. Commented Jan 21, 2014 at 0:38
  • There is no this here. :-) Commented Jan 21, 2014 at 0:50

2 Answers 2

1

The first example shows two invocations of f1().

  • The first invocation of f1() creates a new variable scope with x set to 1, and returns the object with the methods. The .add() then sets that x to 5.

  • The second invocation of f1() creates another new variable scope with x again set to 1, and returns the object with the methods. The .result() then returns that x which is still 1.


The second example only invokes f2() once, so there's no new variable scope with x and new methods being created.


So basically f1's two invocations initializes x with each call, and returns two different objects with methods that closer over the two different x variables.

The f2 is invoked once so there's one x variable shared by the one object with methods returned. Therefore the .add() call and the .result() call are using the same x variable.

Sign up to request clarification or add additional context in comments.

8 Comments

Almost. The first one does not really require two invocations. If he would execute f1 and save the result in a variable and then execute the methods, bot f1 and f2 would return the same result
@Kenneth: Yeah, by "requires" I meant that the example shows two separate invocations. Maybe that wasn't the best word to use.
Okay, where would I have to save the results in a variable?
+1, each call to f1 creates a new execution context with a new x each time, whereas f2 is called once and the same execution context is on the scope chain of add and result so they share the same x.
@user1870482: Not sure what you mean. But if you want your object methods to share the same variable, then you need to save that object. That's what you're doing by invoking the function immediately and saving the object to f2.
|
1

Let me outline what happens in your code:

// Declares a function named f1.
var f1 = function () {
  // Searches each scope (the scope of f1, the scope containing f1, etc.) for
  // a variable named x. If found, it will reassign it to 1. If the search reaches
  // the global scope and no variable is found it will declare and initialize
  // a global variable.
  x = 1;

  // Declares a local variable named add to a function that reassigns the value of x.
  var add = function () {
    x = 5;
  };

  // Declares a local variable named result to a function that logs the value of x.
  var result = function () {
    console.log(x);
  };

  // Returns an object containing each function.
  return {
    add: add,
    result: result
  };
};

// Calls f1 and the returned add function.
f1().add();

// Calls f1 again (which reassigns x) and calls the returned result function.
f1().result();


// Creates a variable named f2 and assigns to the result of applying an anonymous
// function. f2 now references the returned object.
var f2 = (function () {
  // Reassigns x, does not create a new variable.
  x = 1;

  var add = function () {
    x = 5;
  };

  var result = function () {
    console.log(x);
  };

  return {
    add: add,
    result: result
  };
})();

// The difference now is that the function that contains add and result is only
// called once, during the initialization of f2. Had you written var g = f1();
// g.add(); g.result(); you would have gotten the exact same results.
f2.add();
f2.result();

2 Comments

Thank you for the detailed explanation. Am I right that the returned object contains only references to the functions?
@user1870482 Yes, when you called f1 you returned two completely different references (or objects) and called add on one and then result on the other. When you called f2 you used the same reference to call add and result on.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.