2

I want to call a function with an argument and store the value so that next time I call that function without arguments it uses the last argument that was set. Is this possible with JavaScript?

Edit: Here's more info on what I'm trying to achieve...

var track = 0;
$.getJSON('songsMetadata.json', function(data){
    appendData(data);
});
player.bind("ended", function(){
    track++
    appendData();
});
function appendData(data){
    /* Here I want to populate 
     the inside 'data' argument 
    only once (in the callback of 
    getJSON) and use that same
    data in the 'player.bind' 
    callback */

    //Some code to append data[track] to an HTML list
}
5
  • yeah, sure it can be done but if you could please give me a bit more information, i could write you an example. what will the argument be? Commented Jun 10, 2017 at 19:48
  • Possible duplicate of Javascript: Creating a function with state Commented Jun 10, 2017 at 20:02
  • You may be interested in iterators and generators Commented Jun 10, 2017 at 20:06
  • @MolikMiah the argument will be an array that I get from an Ajax call to a JSON file. The array contains mp3s metadata from an HTML 5 playlist that I coded. What I want to do is append this data gradually into the HTML (showing the metadata as the playlist plays each song). I'm still a little bit confused about asynchronous code Commented Jun 10, 2017 at 20:41
  • You can use either of the existing answers to accomplish this. Based on my answer for example - you just have to wrap appendData in the wrapper function. var cachedAppend = cacheFn(appendData); then use cacheAppend in all places you would use appendData. This normalizes appendData so it always gets called with some argument, either the one being passed, or the last argument to have been passed (as you specified in your question). Commented Jun 10, 2017 at 23:24

2 Answers 2

4

You need to keep a reference to the last acceptable argument in the enclosing scope. For example:

var ref;

function foo (arg) {
  if (!arg) { // or arg === undefined if you want to be safe
    arg = ref;
  } else {
    ref = arg;
  }

  // actual function behavior here
  console.log(arg);
}

foo(); // undefined
foo(2); // 2
foo(); // 2
foo(3); // 3
foo(); // 3

If you want to repeat this behavior, you might want to consider writing a wrapper function to cache an accepted function's argument. For example:

function cacheFn (fn) {
  var ref;
  
  return function (arg) {
    if (!arg) {
      arg = ref;
    } else {
      ref = arg;
    }
    
    return fn(arg);
  }
}

function foo (arg) {
  console.log(arg);
}

var cachedFoo = cacheFn(foo);

cachedFoo(2);
cachedFoo();
cachedFoo(3);
cachedFoo();

Sign up to request clarification or add additional context in comments.

6 Comments

I'm a bit confused with this code. Could you explain what is doing exactly? For instance what happens when you return a function? And why do you pass the foo function to cacheFn? I know this code works but I'm genuinely interested in why
@medicengonzo think of cachedFn as an attachment you can make to a function such that it performs the same functionality but with an added benefit. The first thing we do is declare a variable ref which will (internally) be used to store the latest argument passed into the function. We then return a function which wraps the function being passed in (in your case appendData). This willl, eventually run your function, but first we do a bit of logic to determine of an argument has been passed. If so we pass that argument straight in and update ref, if not we pass in ref.
The benefit of this pattern is that your function, appendData, or any other function that you want to use this behavior on, is "dumb" to the whole process. It can concern itself only with the logic it needs to accomplish.
Oh yeah I get it now. Thanks a lot! I learned something new today! :)
@medicengonzo glad to hear it! I would consider looking at Jonas's solution as well, mine is restricted to a single argument, his would work for multiple arguments (is more generalized).
|
3

In a more general way:

function enclose(func) {
 let args = [];
 return function (...passed) {
   if(passed.length) args = passed;
   func(...args);
 };
}

Usecase:

const log = enclose(console.log.bind(console));
log(5,1);
log();

2 Comments

Yep this is a more general soln for n args also assuming es6 is available. If not could easily replicate the spread behavior with arguments and apply. +1
@damon +1 for the general idea ;)

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.