0

I came across David Walsh's once function here:

function once(fn, context) { 
    var result;

    return function() { 
        if(fn) {
            result = fn.apply(context || this, arguments);
            fn = null;
        }

        return result;
    };
}

// Usage
var canOnlyFireOnce = once(function() {
    console.log('Fired!');
});

canOnlyFireOnce(); // "Fired!"
canOnlyFireOnce(); // nada

My question is what is the tracker variable here? Doesn't result become null each time canOnlyFireOnce() is fired? What is the purpose of setting the fn to null?

epascarello
  • 204,599
  • 20
  • 195
  • 236
  • 2
    what `tracker` variable? – epascarello Mar 15 '21 at 17:06
  • What is the purpose of setting the fn to null? So you do not call it again.... – epascarello Mar 15 '21 at 17:07
  • https://stackoverflow.com/questions/36636/what-is-a-closure – epascarello Mar 15 '21 at 17:10
  • 1) He mentioned a tracker variable here: https://davidwalsh.name/javascript-once . I think what he meant is a flag that keeps track of if the function has been called but I cannot locate where that is. 2) So if setting the fn to null means that you cannot call it again, the first time you call it, isn't the function also set to `null` there? How was it called the first time? – Heymanyoulookkindacool Mar 15 '21 at 17:18
  • @Heymanyoulookkindacool -- it is a parameter -- it is part of the context – Hogan Mar 15 '21 at 17:19
  • You pass in the function into fn as the first parameter. It is defined. When you call the function for the first time, it is the function. You use it. When you are done using it, you remove it. Now it is null. Next time you call the function is is not defined. Add some console.log() lines into the function. See when it gets triggered. Read the link I posted that explains closure. – epascarello Mar 15 '21 at 17:20
  • @epascarello probably should set it to null for the edge case where it gets called again before it is set to null – Hogan Mar 15 '21 at 17:22
  • @Hogan Not sure how in the world that would be possible since JavaScript is single threaded. – epascarello Mar 15 '21 at 17:23
  • @Heymanyoulookkindacool You need to understand what a closure is. Once you understand that, you will understand how the variables are being used to keep track of state. – epascarello Mar 15 '21 at 17:25
  • @epascarello if the function you put in there does a context switch -- say disk io – Hogan Mar 15 '21 at 17:27
  • @Hogan Again JavaScript is single threaded....And I am not sure what your comments towards me have to do with the question the OP is asking. – epascarello Mar 15 '21 at 17:28

2 Answers2

2

The fn is the tracker variable here. The fn variable holds the anonymous function. After calling the canOnlyFireOnce function once, the fn variable gets a new value "null". Now the fn(the anonymous function) is no longer available for execution, that's why you won't see the "Fired!" message again.

sakib 1212
  • 60
  • 6
  • return function() { if(fn) { result = fn.apply(context || this, arguments); fn = null; } return result; }; Actually this part is a Closure – sakib 1212 Mar 15 '21 at 17:33
  • Thanks! I normally would also use a flag to switch off from false to true so I was a little confused when the author mentioned a tracker variable. So in this case, the author didn't use the flag, but the passed in function itself to be its own flag right? – Heymanyoulookkindacool Mar 15 '21 at 17:47
  • " So in this case, the author didn't use the flag, but the passed in function itself to be its own flag right?" --> You are right. – sakib 1212 Mar 15 '21 at 17:56
1

fn is the variable which tracks whether it's been called. You could write it this way with a more explicit extra variable:

function once(fn, context) { 
    var result;
    var called = false;

    return function() { 
        if (!called) {
            result = fn.apply(context || this, arguments);
            called = true;
        }

        return result;
    };
}

I guess that setting fn = null can free some memory, so he wants to do that after the call too. So why not also use that to remember the call.

Ben West
  • 4,398
  • 1
  • 16
  • 16