Closure in Constructor Function | what am I doing wrong🤔?

Hi,

A private method is called to some private parameters. However, they log as “undefined”! The problem area is indicated with a :triangular_flag_on_post: in the code below. Why doesn’t Closure work here? What am I not getting?

(background: am making a simple timer as learning exercise)

Thanks in advance,
Lenn

=======

function Timer() {
    let _startTime , _stopTime, _durationHistory = 0;
    let _startTrigger = false;
    let _stopTrigger = false;

    timerSwitch = function(log, trigger) {
        log = Date.now() * 0.001;
        trigger = true; 
    };

    this.start = function(){
        timerSwitch(_startTime, _startTrigger); //🚩why doesn't closure apply here? 
        console.log("timer started", _startTime); //🚩the console logs _startTime as Undefined
    };

    this.stop = function(){
        timerSwitch(_stopTime,_stopTrigger);
        _durationHistory = _durationHistory + (_stopTime - _startTime);
        console.log(`timer stopped: ${_stopTime}s | _durationHistory: ${_durationHistory}`);
    };

    this.reset = function(){
        _startTime = 0;
        _stopTime = 0;
        _durationHistory = 0;
        console.log('timer reset: start', _startTime, ' | stop ', _stopTime, '| history ', _durationHistory);
    };

    this.duration = function(){
        console.log(_durationHistory);
    };
};

tmr = new Timer();
tmr.start();```
1 Like

_startTime and _stopTime are not initialized, so they are undefined.

This does not initialize all three variables with the value 0.

Thanks for that. I tried initializing to 0 and the console still logged “0”. (It should return a large number)

Is there something else not considered?

Why would it return a large number? You set _startTime to 0 and then you log it.

I’m a bit confused about what this part is supposed to do:

    timerSwitch = function(log, trigger) {
        log = Date.now() * 0.001;
        trigger = true; 
    };

My guess is that you want to overwrite (_startTime, _startTrigger) when you call that function, but that’s not what’s happening. If you’re looking for that large number, you’d have to console.log(log) within your timerSwitch function. But _startTime will still be 0.

1 Like

Hi JSdisco,

You’re right that I want to overwrite it when i call that function. How can I do that?

This isn’t an issue with closure but rather an issue with assignment.

log is a parameter. A parameter is a variable. When you have log = ..., you are assigning a new value to the log parameter/variable.

If your goal is to change the value assigned to _startTime, off the top of my head I can think of two options:

  1. Reassign _startTime directly inside timerSwitch() i.e. don’t pass it as an argument. Since you already have _startTrigger to flag if the timer has started, you can use a simple if statement to decide whether to reassign _startTime or _stopTime.

  2. Initialise _startTime as an array or an object and mutate it inside timerSwitch();
    E.g.

let _startTime = [];

timerSwitch = function(log, trigger) {
  log[0] = Date.now() * 0.001;
  //...
};

// Later when logging:
this.start = function(){
  ...
  console.log("timer started", _startTime[0]); 
};


I feel there should be better solutions but I couldn’t think of any more right now.

Thanks for this! That was all the direction I needed and its solved. :raised_hands:

Sharing the cleaned up code for anyone who may benefit from my same problem.


function Timer() {
    
    // let _isRunning = false; 
    const memory = {
        startT:0,
        stopT:0,
        isRunning:false,
        duration: 0
    };

    timerSwitch = function(log) { //🚩 this portion doesn't work, see the flags below for attempts of what it should do 
        
        //log the time 
        memory[log] = Date.now() * 0.001;

        //check state and switch it
        if (memory.isRunning) {
            memory.isRunning = false;
            memory.duration = memory.duration + (memory.stopT - memory.startT);
        } else {
            memory.isRunning = true;
        };

        //give console feedback
        for (let key in memory) console.log (key, ":", memory[key]);
    };

    this.start = function(){
        if (memory.isRunning) {
            throw new Error(`Timer is already started!`);
        } else {
        timerSwitch('startT'); 

        }
    };

    this.stop = function(){
        if (!memory.isRunning) {
            throw new Error(`Timer is already stopped!`);
        } else { 
            timerSwitch('stopT');
        }
    };

    this.reset = function(){
        _startTime = 0;
        _stopTime = 0;
        memory.duration = 0;
        _isRunning = false;
        console.log('timer reset');
    };
   
    Object.defineProperty(this, 'duration', {
    get: function() {return memory.duration; },
    });
};

tmr = new Timer();
tmr.start();

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.