What I want is to load multiple files. These files all use the same function to be loaded, only thing different is the file name. This function should return an object. Something like this:
var files = [ loadFile("file1.txt"), loadFile("file2.txt"), loadFile("file3.txt") ];
// Example function
function loadFile( file_name ) {
return "loaded file " + file_name;
}
But when I run this it loads it directly.
var files = [ loadFile, loadFile, loadFile ];
// now please
for (var i = 0; i < files.length; i++) {
files[i]();
}
But this way I can't give it arguments. Now I can create a filler function like this, but I there is probably a better way to do this...
function loadFile1() {
return loadFile( "file1.txt" );
}
If it is possible, how can I load Javascript functions as Arguments with Arguments?
*done some testing. I am going with bind() for the answers, as that is what I was looking for. But I want to mention Stuart's answer that I definitely will keep in mind for the future use. MoeSattler & vlaz thank you guys for showing other good ways of doing this!
5 Answers 5
Cant you do:
// Example function
function loadFile( file_name ) {
return "loaded file " + file_name;
}
var files = ["file1.txt", "file2.txt", "file3.txt"];
for (i = 0; i < files.length; i++) {
loadFile(files[i]);
}
5 Comments
bind is perfectly acceptable (as in my and Nina's answers) this is a FAR better solution. The only case in which bind is preferable to this is if the function being applied to each entry in files is different.files.map(loadFile). for (i.... is not how to write idiomatic javascript, especially without var which makes your i global.How about map?
function loadFile( file_name ) {
return "loaded file " + file_name;
}
const fileNames = ['file1.txt', 'file2.txt', 'file3.txt']
const files = fileNames.map(loadFile)
console.log(files)
1 Comment
You could use Function#bind for binding the parameter to the function and call later without parameter.
The
bind()method creates a new function that, when called, has itsthiskeyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
function loadFile( file_name ) {
return "loaded file " + file_name;
}
var files = [ loadFile.bind(null, "file1.txt"), loadFile.bind(null, "file2.txt"), loadFile.bind(null, "file3.txt") ];
files.forEach(function (a) {
console.log(a());
});
1 Comment
Option 1 is to use what is called a thunk - it's simply a function that does not take any arguments and returns a value when executed. It's useful for returning something at a later point. You actually do have an example of that with loadFile1 but you can generalise it.
function loadFileLater(fileName) {
return function() {
loadFile( fileName );
}
}
Or using Function.prototype.bind()
function loadFileLater(fileName) {
return loadFile.bind(null, fileName);
}
Alternatively, you can flip it around and instead of having an array of functions that need values, you can have an array of values where you execute a function against each
function loadFile( file_name ) {
return "loaded file " + file_name;
}
var filesNames = [
"file1.txt",
"file2.txt",
"file3.txt",
"file4.txt"
]
var files = filesNames.map(loadFile)
console.log(files);
In your case, you are most likely going to use .forEach rather than .map but it's the exact same principle.
Comments
bind is going to be your best friend here.
Typically bind is used to assign a context to a function (ie: var myBoundFunc = myFunc.bind(myObj) will make sure that any references to this in MyFunc when called via myBoundFunc will point to myObj), but bind has the added bonus of also being able to store parameters to call myFunc with.
So in your case:
var files = [ loadFile.bind(this, "file1.txt"), loadFile.bind(this, "file2.txt"), loadFile.bind(this, "file3.txt") ];
Where this can be any context, and every argument after is used when the resulting function (ie files[0]()) is called.
bind()or make another function or lambda..bindto be a better way, then yes. Otherwise, no.