Search code examples
javascriptamd

Why does this Javascript function not work if called twice?


The Jasmine (unit?) tests I'm running works for all test with my code below, but the last test calls Gigasecond.date() twice, then validates the second one, which fails.

var Gigasecond = function(date) {
    this.startDate = date;
};

Gigasecond.prototype.date = function() {
    var x = this.startDate;
    x.setSeconds(x.getSeconds() + 1000000000);
    return x;
    }

module.exports = Gigasecond; 

I guess I don't know why this fails. When I log to the console I see the date gets incremented twice, but thought that x is its own separate variable that gets created/destroyed each time the function is called.. but it seems not. Is x just a reference to the actual .startDate field on the object? Is there any reference material for how this works? I looked around but couldn't find anything that applies to what's happening in this code.


Solution

  • You state that you

    thought that x is its own separate variable that gets created/destroyed each time the function is called.. but it seems not. Is x just a reference to the actual .startDate field on the object?

    That is correct. Dates are objects, and in JavaScript, objects are assigned to variables by reference, not copy. If you intend to work with a copy, you need to return a clone of the Date object with new Date(dateToBeCopied.getTime()) first.

    In your code, if you want to work on a copy of the date, you need to replace the line

    var x = this.startDate; //assignment by reference
    

    with this line

    var x = new Date(this.startDate.getTime()); //assignment by copy
    

    The example code below demonstrates how this works. The Date Object dateA is assigned to the variable refA by reference and to the variable copyA by copy. When modifying refA, this affects dateA, whereas copyA is unaffected.

    var dateA = new Date();
    
    //assign a reference to dateA
    var refA = dateA;
    
    //assign a copy of dateA
    var copyA = new Date(dateA.getTime());
    
    //modify refA, increment with one year
    refA.setFullYear(refA.getFullYear() + 1);
    
    //variable refA points to dateA,
    //both show the date incremented with one year
    console.log('+1 year: ', dateA);
    console.log('+1 year: ', refA);
    
    //variable copyA returns an unmodified copy,
    //not incremented
    console.log('unmodified copy: ', copyA);