I am making a reduce function that uses another function, which takes multiple arguments, as a callback. My question is, if I wish to test the callback function for whether an argument exists, what syntax would I need to use.
var result = _.reduce([1,2,3], function(memo) {
return memo;
});
_.reduce = function(arr, fun, opt){
//if(arguments[1][1] == undefined) return arr[0];
The last line is my best attempt. What I am trying to say is that, if the function in the result line has no second argument, return arr[0].
If I understand your question correctly, you are trying to access the arguments inside a function call. You can use the arguments object for this.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/length
It allows you to iterate through the arguments of a function and do something with them. For example -
function yourCustomReduceFunction() {
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
Hope this helps :)
Related
This question already has answers here:
Create a custom callback in JavaScript
(11 answers)
Closed 10 months ago.
I dont understand what is callback in this example, espicially line
newArray.push(callback(this[i]));
as i got it (this[i]) is item from Array, but how does CALLBACK refer to code;
const s = [23, 65, 98, 5];
Array.prototype.myMap = function(callback) {
const newArray = [];
for(let i=0;i<this.length;i++){
newArray.push(callback(this[i]));
}
return newArray;
};
const new_s = s.myMap(function(item) {
return item * 2;
});
console.log(new_s);
1. Background concepts
Firstly, this top part is just a function definition where 'callback' is just a parameter that myMap is able to accept. The word 'callback' isn't special and you can use in fact any name, but 'callback' does signal that in your function definition you are asking the caller to supply a function instead of an integer or a string. That is, you could also write something like this:
Array.prototype.myMap = function(param) {
// you can console.log(param) and you would see the parameter in log.
}
And in theory you could then call this function by doing:
s.myMap(1) // the log will show 1
s.myMap("hello") // the log will show "hello"
s.myMap(function() {}) // the log will show [Parameter is a Function]
Secondly, if you name your parameter 'callback', it signals to the caller that they could in fact pass a function into this myMap not just an integer or a string -- so when you write something like this:
Array.prototype.myMap = function(callback_f) {
callback_f(); // <----- call the incoming function passed as a param
}
Then the caller has an idea that they have to supply a function into myMap, either in this way:
s.MyMap(function() {
// do some stuff
})
Or in this way:
function doStuff() {}
s.MyMap(doStuff)
Either way, the parameter callback_f is expected to be a function in this case, and myMap will call and execute this function, regardless of what you pass into it.
2. Answering your question
As you may already know, this is a special function definition because, by doing Array.prototype.myMap you're modifying how all arrays work and all arrays will now gain this function definition myMap.
Secondly, you can call this function by doing s.myMap() if s is any array.
So in your case, the line:
newArray.push(callback(this[i]))
could also be written as:
let result_of_executing_the_callback = callback(this[i])
newArray.push(result_of_executing_the_callback)
which means: first, execute the incoming callback function on this (= current array) at the index i. And what is the incoming callback function? It is the function f that you are passing in when you do s.MyMap(f):
In your case f is this:
function(item) {
return item * 2;
}
picture of f being passed into your function as the parameter 'callback'
(If this is helpful please mark as accepted!)
I just wondering to find a keyword or a solution so that I can further find and fix my own problem, so basically, I wanted to call a function but from a function argument, like this.
var arg = function() {/*do something*/};
function do(arg) {
arg();
}
do(arg);
But I want to put multiple functions on it, but not constant, it sometimes can be 1 function, or sometimes 2 functions or more, is there any solution that I can take? or a keyword to I start searching with? I already searched the internet but I could not find what I want.
You could use some really cool new feature called rest parameters. Here is an example.
function callMultiple(...fn) {
fn.forEach(fn => fn());
}
function FnOne() {
console.log('function one called');
}
function FnTwo() {
console.log('function two called');
}
callMultiple(FnOne, FnTwo);
Now callMultiple can take any number of functions.
MDN reference
function doFn(){
for(var i = 0; i < arguments.length; i++) arguments[i]();
}
One line ES6:
var doFn = (...args) => args.forEach(fn => fn());
PD: ´do´ is a reserved word, you should use diffetent variable name.
What you need to do to your do() function is this:
function do(args) {
for (var i = 1; i <= args.length; i += 1) {
args[i]();
}
}
This would fix your problem. However, you should know that do is a JavaScript keyword, so you should avoid using it as a variable or function of your own.
EDIT: You must include anything you're passing to your function, so you need to add the args parameter.
I am using a function as a parameter to build a reduce method. If the function that is passed in has no arguments, then I want to return 0.
_.reduce = function(arr, fun){
if(fun[0] == undefined){
return 0;
}
.
.
The issue is that the if statement executes even if an argument is passed into fun. Am I trying to access the arguments incorrectly?
If you want to know how many arguments a function takes you should check it's length.
_.reduce = function(arr, fun) {
if (!fun || !fun.length) {
return 0;
}
...
};
Considering your function "fun" is always defined, you can use the .length according to this link :
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/length
_.reduce = function(arr, fun){
if(fun.length == 0){
return 0;
}
Currently I'm reading JavaScript book. There is a code snippet in it which I can't understand. What's happening in the line repeat(3, function(n) {? Why we can pass parameter n to the second argument of the function repeat, because in its declaration there is nothing about passing parameters? How does repeat understand that it should pass parameter n to the unless function?
function unless(test, then) {
if (!test) then();
}
function repeat(times, body) {
for (var i = 0; i < times; i++) body(i);
}
repeat(3, function(n) {
unless(n % 2, function() {
console.log(n, "is even");
});
});
// → 0 is even
// → 2 is even
Why we can pass parameter n to the second argument of the function repeat, because in its declaration there is nothing about passing parameters
You are not passing n as the second argument to repeat(), you are passing an anonymous function that takes a single parameter and you chose to name its parameter n (so parameter of the function that is passed in)
Functions in JavaScript are, in simple words, just objects that can also be executed. This means you can pass functions around as parameters to other functions, or add properties to them like you would to objects, etc.
Here's an illustration of what is happening in your example:
Function repeat is defined with two arguments:
repeat(times, body)
So, all you are doing is passing a function as the body argument.
Writing it like this is equivalent:
var times = 3;
var body = function(n) {
unless(n % 2, function() {
console.log(n, "is even");
});
};
repeat(time, body);
How does repeat understand that it should pass parameter n to the unless function?
As you can see above, repeat is not passing anything to unless().
It is your anonymous function (stored in body in my example above) that is actually passing n to unless.
You're not passing a parameter n at all.
In reality, you're passing an entire anonymous function as a parameter (functions are first-class citizens in JavaScript and can be passed around just like other variables).
If you look, the function is passed as the body parameter to the method repeat. repeat then calls the function body with the parameter of i...which is the parameter n in the anonymous function.
If you simply want to write a function to repeat x number of times, and check if it's even, you'd probably want to do it like this:
function repeat(times) {
for (var i = 0; i < times; i++) {
output.innerHTML+= is_even(i)+"\n";
}
}
function is_even(n) {
if ( n % 2 ) return n+" is even";
return n+" is odd";
}
var output = document.getElementById('output');
repeat(6); // Output variable wasn't passed to this function, we're using it globally
<pre id='output'></pre>
I need to define a callback, which is to be called by a external library. This callback is called with 1 parameter:
function(item) {};
In my case I need to include a second parameter which I currently solve by using the 'bind' method.
function(item) {
var value = this.value
}.bind({'value': value});
I dont want to write this every time I need to define shuch a callback function. Instead I would like to write something like this:
function(item, value) {};
Which then would be transformed into the bind method in order to satisfy the external library.
Is that possible? Or is there some other way to do this?
Thanks
You want to use closures. Here's the basic pattern, though not quite as easy as what georg suggested. But performance-wise, not nearly as much of a hit (near minimal).
Define a function:
myValueFunction(value, fn){
return fn;
}
Since it seems you're saying your plugin is providing item and you are providing the value, you will set myValueFunction(yourvalue, function(item){}) as the callback function for your plugin (with your actual value as the parameter). It'll "return" another function with your value enclosed that takes one argument (item).
So for example if you have a plugin:
var myValue= "x";
plugin.doSomething("Plugin Argument", myValueFunction(myValue, function(item){
console.log(item, value);
}));
This is basically what georg's answer is doing (his is in a somewhat more versatile way), but his method will will be much slower performance-wise than if you define these functions directly, particularly if you start adding many arguments.
You can use the function.partial implementation from here:
Function.prototype.partial = function(){
var fn = this, args = Array.prototype.slice.call(arguments);
return function(){
var arg = 0;
for ( var i = 0; i < args.length && arg < arguments.length; i++ )
if ( args[i] === undefined )
args[i] = arguments[arg++];
return fn.apply(this, args);
};
};
Define the callback like this:
callback = function(item, value) { console.log(item + value) }.partial(undefined, "myValue")
Now when you call callback('myItem'), it correctly displays "myItem myValue"