LeDoc
LeDoc

Reputation: 945

Using this.property in local function does not make changes to the property

I'm trying to write a basic function in order to produce a cash machine. Whenever I run the below code, I get the total staying at 0. Can anyone help me out or explain to me why?

function VirtualCashMachine(){

    //object storing food
    this.food = {egg: 0.98, milk: 1.23, magazine: 4.99,chocolate: 0.45};

    //total bill
    this.total = 0;
    //record of last transaction
    this.lastTransactionAmount = 0;

    //assign public methods
    this.scan = scan;
    this.voidLastTransaction = voidLastTransaction;       

    //define public methods    

    //add amount to total property
    function scan(/*string*/item,/*integer*/ quantity){

        //if food item exists in food object, find price and calculate total
        if(this.food.hasOwnProperty(item)){

            cost = this.food[item] * quantity;
            add(cost);
            this.lastTransactionAmount = cost;

        }
    };

    function voidLastTransaction(){
        this.total -= lastTransactionAmount; 
    };

    //define private method

    //add item price to total
    function add(itemCost){
         this.total = this.total + itemCost; 
    };
}

var VCM = new VirtualCashMachine();
VCM.scan("egg", 3);


console.log(VCM.total);

The problem seems to arise when I implemented the add function. My reasoning is that once I find the total costs for 3 eggs in this example, I add the amount to the this.total and can repeat this for other sorts of food.

Upvotes: 0

Views: 134

Answers (2)

Alexei Levenkov
Alexei Levenkov

Reputation: 100547

"this" is often not what you think it is... I.e. when you call function without context (add instead of VCM.scan) the context will be set to global object. There are many articles on the subject - i.e. Understanding JavaScript Context.

There are several options to deal with it.

One is to call it with context by making it "public member" as suggested by tomca32 (Note that it will expose private methods which may not be desirable in many cases):

this.add = function(itemCost) { this.total += itemCost;} this.add(cost);

Another option is to save this into local variable so you know what exactly you are using:

function VirtualCashMachine(){
   var self = this;
   ....
   function add(itemCost){
     self.total = self.total + itemCost; 
};

Or you can explicitly pass context with function.call:

function add(itemCost) { this.total += itemCost;}
add.call(this, cost);

or you can avoid this in local functions altogether, but you'll need to expose properties with get/set methods. In this case since function will sees all local variables in parent's scope it can correctly modify total:

var total = 0;
this.getTotal() { return total;} 
function add(itemCost) { total += itemCost;}

Second approach (with copying this to local variable) is quite common and easiest to follow in my opinion: simply use self (or other commonly used me or that) everywhere inside your class where you would use this..

Upvotes: 3

tomca32
tomca32

Reputation: 1140

Re-write add to be a property of this:

this.add = function (itemCost) {
  this.total = this.total + itemCost; 
}

Upvotes: 3

Related Questions