Alex
Alex

Reputation: 1250

javascript: Assign function to a variable fills variable with undefined

It's kinda basic, but its giving me some headaches:

I'm assigning a function to a variable, then I call a function inside the first function from the variable.

When I assign the function to the variable its filled with undefined, so when I call the inner function I get the error:

Uncaught TypeError: Cannot read property 'add' of undefined

This is the code I'm working on:

(function () {

  function Sum() {

    this.result = 0;

    this.getCurrentSum = function getCurrentSum() {
      return this.result;
    }

    this.add = function add(add_number) {
      this.result += add_number;
    }

  }

  var s1 = Sum();  // here s1 is undefined
  var s2 = Sum();  // here s2 is undefined

  s1.add(10);  // here cannot execute add of undefined crash
  s1.add(20);

  s2.add(30);
  s2.add(5);

  // must print 30
  console.log(s1.getCurrentSum());

  // must print 35
  console.log(s2.getCurrentSum());

}());

I can change the code in the Sum function, but I can't change the rest of the code

Upvotes: 0

Views: 1125

Answers (2)

T.J. Crowder
T.J. Crowder

Reputation: 1075815

It looks like you want Sum to be a constructor function. You call constructor functions via new, not directly. So:

var s1 = new Sum();
var s2 = new Sum();

The reason you were getting undefined in s1 and s2 without new is that Sum doesn't do return x anywhere, so the result of calling it is the value undefined. But when you use new, the result of the new expression is the object that was created.

FWIW, there's another problem with Sum: You're missing out this. in a couple of places (also a couple of semicolons, though Automatic Semicolon Insertion will add them for you):

function Sum() {
  this.result = 0;

  this.getCurrentSum = function getCurrentSum() {
    return this.result;
// −−−−−−−−^^^^^
  };

  this.add = function add(add_number) {
    this.result += add_number;
// −^^^^^
  };
}

JavaScript isn't like Java or C#, this. isn't optional.


In a comment you've asked:

wat if I can change the Sum function or anything inside the function but I can't change the var s1 = Sum();calling?

In that case, you'd make Sum a builder function and have it return an object, like this:

function Sum() {
  return {
    result: 0,
    getCurrentSum: function getCurrentSum() {
      return this.result;
    },
    add: function add(add_number) {
      this.result += add_number;
    }
  };
}

Live Example:

(function () {

  function Sum() {
    return {
      result: 0,
      getCurrentSum: function getCurrentSum() {
        return this.result;
      },
      add: function add(add_number) {
        this.result += add_number;
      }
    };
  }

  var s1 = Sum();  // here s1 is undefined
  var s2 = Sum();  // here s2 is undefined

  s1.add(10);  // here cannot execute add of undefined crash
  s1.add(20);

  s2.add(30);
  s2.add(5);

  // must print 30
  console.log(s1.getCurrentSum());

  // must print 35
  console.log(s2.getCurrentSum());
})();

Normally a builder function wouldn't start with a capital letter (that's essentially reserved for constructor functions), so it would have a name like createSum or buildSum or similar.

That version of Sum is written with ES5-level syntax (actually it's even ES3-level). In ES2015+ it could be a bit more concise:

// ES2015+ using method syntax
function Sum() {
  return {
    result: 0,
    getCurrentSum() {
      return this.result;
    },
    add(add_number) {
      this.result += add_number;
    }
  };
}

Live Example:

(function () {

  // ES2015+ using method syntax
  function Sum() {
    return {
      result: 0,
      getCurrentSum() {
        return this.result;
      },
      add(add_number) {
        this.result += add_number;
      }
    };
  }

  var s1 = Sum();  // here s1 is undefined
  var s2 = Sum();  // here s2 is undefined

  s1.add(10);  // here cannot execute add of undefined crash
  s1.add(20);

  s2.add(30);
  s2.add(5);

  // must print 30
  console.log(s1.getCurrentSum());

  // must print 35
  console.log(s2.getCurrentSum());
})();

Upvotes: 4

Scott Marcus
Scott Marcus

Reputation: 65873

Because you are using this within the Sum function, you need to have an instance of that Object constructed. Using the new operator to use Sum as a "constructor function" will accomplish that.

But, then in Sum you declare this.result as an instance variable, so you must also refer to it as this.result in the other spots in the function as well.

Take a look at another post of mine that talks about this and what it does.

(function () {
  function Sum() {
    this.result = 0;
    this.getCurrentSum = function getCurrentSum() {
      return this.result;
    }
    this.add = function add(add_number) {
      this.result += add_number;
    }
  }

  var s1 = new Sum();
  var s2 = new Sum();

  s1.add(10);
  s1.add(20);

  s2.add(30);
  s2.add(5);

  console.log(s1.getCurrentSum());  // 30
  console.log(s2.getCurrentSum());  // 35
}());

Upvotes: 1

Related Questions