0

The following function once (problem 13) will take func and return a function that allows func to be called only once.

function add(a, b) {
    return a + b;
}

function once(func) {
    return function () {
        var f = func;
        func = null;
        return f.apply(this, arguments);
    };
}

add_once = once(add);
add_once(3, 4)   // 7
add_once(3, 4)   // throws

There are two things that I don't get about this.

  1. Why does writing func = null stop us from calling the function a second time? After saving the pointer to the function (it's all right to use the C lingo; isn't it?) in var f = func, I'd expect that assigning null to the function pointer func (func is just a function pointer; isn't it?) is irrelevant—because the (pointer to the) function is already stored in f. What am I missing?
  2. I get that it's necessary to write f.apply(this, arguments); rather than simply f(arguments); because it's one of JavaScript's idiosyncrasies. The latter would send an array, not a list of arguments, to the function. But I don't get what this refers to. Does it refer to the anonymous function on the second line or to once? And if assigning func = null is meant to stop the second invocation because the closure will lead to a func that has been nulled, why does it work the first time it's called?

I am using too many questions to give you the chance of identifying what I'm missing, not with the expectation that you'd type a long answer addressing each sub-question independently.

Community
  • 1
  • 1
Calaf
  • 8,037
  • 8
  • 46
  • 96

2 Answers2

1

Remember, you aren't calling once again a second time so that when you see func used inside the returned function, it is no longer a pointer to whatever was passed into once because the returned function has modified the value (because the returned function was already called previously) referred to by the variable named func inside the closure provided by once, by saying func = null. After being called the first time, the value returned inside the return function when you ask for the value of func has changed from the original value passed into once to null.

EDIT

After reading what I just wrote, although it makes sense to me, I can't blame you if it doesn't help you :S

EDIT #2

The second part of your question - what is this referring to. It completely depends on how you call the function returned by once. See this* question

*pun intended

Community
  • 1
  • 1
Adam
  • 41,349
  • 10
  • 58
  • 78
  • 1
    You nailed it (my misunderstanding) with the first few words, but then you confused the heck out of me with the rest. I only figured out what was going on after reading Dillon's answer, so I'll check-mark his answer and +1 yours. – Calaf Jun 12 '16 at 02:59
1

"Why does writing func = null stop us from calling the function a second time?"

  • when add_once is ran the first time these are the steps that are taken......

    var f = func; step1 - the variable f now has reference to the add function that was passed in as a parameter. func still has reference to the add function as well, so now both func and f are pointing to the same add function.

    func = null; step2 - now the func points to null and no longer references the add function. But the vairable f still has reference to the add function.

    return f.apply(this,arguments); step3 - since f still references the add function we can pass that function the arguments array and call it immediately. apply immediately calls the add function with the arguments given. We then return the result. 'this' is binded to whatever f is referencing, in this case it is the add function. A good trick to remember is that 'this' is going to be binded to whatever is to the left of the '.' at the call site aka where the function is called. Doesn't really matter in this case though. You could also put null in its place and it would work just fine.

  • when add_once is ran a second time these are the new steps taken....

    var f = func; step1 - we now point f to whatever value func is referencing. func is still referencing null since we pointed func to null the first time the function was ran. Now f and func are both pointing at null.

    func = null; step2 - we point the func variable/parameter to null again. func already was pointing to null, so now func is definitely pointing to null.

    return f.apply(this,arguments); step3 - here f is still pointing to null. you obviously can not call null, as null is not a function. Here is where the error is thrown.

Hope this helps. A thing I like to remember is that a variable does not store anything, it references a value. I like to think of a variable as pointing to a value. You can have many variables pointing to the same value. Reassigning a variable just points that variable to a new value.