4

I used to have something like the following ...

var setFoo = function (value1) {
    window.localStorage.setItem('foo1', value1);
}

var setFoo2 = function (value2) {
    window.localStorage.setItem('foo2', value2);
}

.. however, I found that I was constantly doing ...

window.localStorage.setItem('something', value);

... so I decided to turn it into a function ...

function genericSetFoo(name, value) {
    window.localStorage.setItem(name, value);
}

... and have the following instead ...

var setFoo = genericSetFoo('foo1', value1);
var setFoo2 = genericSetFoo('foo2', value2);

... however, now when I try to call setFoo1(value1) or setFoo2(value2), the application complains of value1 and value2 being undefined. What am I doing wrong? I mean I could still do ...

var setFoo = function(value1) { genericSetFoo('foo1', value1) };
var setFoo2 = function(value2) { genericSetFoo('foo2', value2) };

... and it works too... but it defeats the whole point if I have to redefine the function in any case. So how do I tackle this?

3 Answers 3

2

You can use .bind() in this situation. This technique is known as "partial function evaluation":

var setFoo = genericSetFoo.bind(null, 'foo1');
var setFoo2 = genericSetFoo.bind(null, 'foo2');

setFoo(value1);

If you're using lodash or underscore, you can use _.partial() which is different from .bind in that it doesn't require that first argument and doesn't rebind the this value:

var setFoo = _.partial(genericSetFoo, 'foo1');
var setFoo2 = _.partial(genericSetFoo, 'foo2');
Sign up to request clarification or add additional context in comments.

Comments

1

What am I doing wrong?

You're calling window.localStorage.setItem() instead of returning a function that calls window.localStorage.setItem(). Remember, when you call a function and assign it to a variable you are assigning the return value of that function, not the function itself.

For example, when you do:

function a () { return 2 };

var two = a();

.. do you expect the variable two to be 2 or a function? Another example, if you do:

var x = document.getElementById('foo');

.. do you expect the variable x to contain a DOM element or a function?

So, you need to return a function instead of calling a function:

function genericSetFoo(name) {
    return function (value) {
        window.localStorage.setItem(name, value);
    }
}

So now you can do:

var setFoo1 = genericSetFoo('foo1');

4 Comments

Oh, thank you. That is really interesting. This seems like the most comprehensible solution for my current understanding. However, some of the other users have mentioned something about "currying" or "partial application"... what do you say about that in comparison to this? Appreciated.
Okay, I just realised that your method was, in fact, an example of currying as well. But how does this defer from the .bind technique?
@Grateful: This does not require additional language features (like ES5 .bind()) and works all the way back to the original Netscape release of javascript and IE's original release of jscript. Also, once you understand how functions and closures work you can implement additional language features like .bind() yourself.
Perfect! Through this, I have learned something very useful today. Thanks.
1

What I am doing wrong?

When you do:

var setFoo = genericSetFoo('foo1', value1);

you are invoking genericSetFoo() and assigning the value returned from it to setFoo. However since value1 is undefined at the time of initializing setFoo (and thereby invoking genericSetFoo()) you get an undefined error when window.localStorage.setItem(name, value) tries to use the argument passed to its value parameter.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.