This question already has an answer here:
What are Closures and Callbacks?
(1 answer)
Closed 4 months ago.
Where do arguments like element, index and array come from, for e.g. the filter method like below:
const arr = [ "Laurence", "Mike", "Larry", "Kim", "Joanne", "Laurence", "Mike", "Laurence", "Mike", "Laurence", "Mike" ];
const arr2 = arr.filter((value, index, array) => {
console.log(value, index, array.indexOf(value));
return array.indexOf(value) === index;
});
console.log(arr2);
In some built-in methods we use them, I know what they do, but I don’t understand if they are like built-in parameters.
For example, when one defines a function one would add parameters like value, index and array.
But when one calls the function one doesn’t add any arguments.
Are these kind of parameters like built-in parameters or why we don’t have to specify what they are?
I wrote a custom filter function to show you that these parameters aren't built-in, they are just passed to your callback by the Array.prototype.filter function when the internal loop is executed.
const result = filter([1, 2, 3, 4, 5], item => item % 2 === 0)
console.log(result)
function filter(array, callback) {
const newArray = []
for (let i = 0; i < array.length; i += 1) {
// pass value index and array
if (callback(array[i], i, array)) {
newArray.push(array[i])
}
}
return newArray
}
forEach example:
forEach([1, 2, 3, 4, 5], (value, index) => console.log(value, index))
function forEach(array, callback) {
for (let i = 0; i < array.length; i += 1) {
callback(array[i], i, array)
}
}
The answer is very simple, No there aren't
In JavaScript, functions are objects like any other -- you can pass functions to functions. This is how the Array.prototype.filter function (the filter method you'd call on an array like arr.filter(...)) works -- it takes a function as a parameter. It filters by calling the function you pass to filter, for every element, with the element [of the array] as value, the index of the element [in the array] as index, and the array itself as array. If your function returns true, the element is contained in the array returned by filter, otherwise the element isn't contained in the returned array.
So yes, the filter function is what calls the function you pass to filter, binding parameters to values -- something that makes parameters arguments.
In JavaScript, if you do not pass an argument to a function that expects an argument, the argument is undefined -- you can say that the parameter isn't bound:
function f(a) {
return a;
}
console.assert(f() === undefined); /// Yields true
JavaScript will not warn you that an argument is missing.
That is all there is to it, really.
Answering this question largely involves the difference between the terms "parameter" and "argument", also known as "formal parameters" and "actual arguments".
This canonical question, What's the difference between an argument and a parameter? covers the subject with external links.
Summary
A (formal) parameter is the name used when coding or documenting a function to identify an argument that will be passed to it.
An (actual) argument is the value of a (formal) parameter passed to a function when called.
Code that calls a function can supply arguments using literal values, or values held in variables or object properties. Calling code may choose to name variables after documented parameter names of a called function - but is not required to do so.
Posted code
arr.filter((value, index, array) => {
console.log(value, index, array.indexOf(value));
return array.indexOf(value) === index;
});
Here the array method Array.prototype.filter is called with a callback function argument, being the in-lined anonymous function, (value, index, array)=>{ /* code */}.
value, index and array are the call back function's parameter names, chosen by the person who wrote the code to be readable in English. If they wanted the code to be readable in French, say, they might have used elementCourant instead of value.
"value", "index" and "array" are the terms used in (MDN) English documentation of arguments passed to the callback by the filter method.
TL:DR
In general look up the documentation for standard JavaScript methods to find out what arguments are passed to callbacks they make. You can use callback argument names from the documentation as formal parameter names in callback functions you write - if you want to and it suits your purpose.
Related
Can anybody explain the flow of the code? I need to know how the function 'isEven' gets the 'x' value
$(document).ready(function(){
var array = [1,2,3,4,5];
function isEven(x){ //checks if a value is even
console.log(x)
return x % 2 == 0;
}
var newArray = array.filter(isEven); //uses a callback to check if an element is even
console.log(newArray);
});
As stated in the comment in your code, you are passing a callback, so here the current item processed in .filter() will be automatically passed to this callback function, or in other words isEven function will be called with the current item from .find() call.
As you can see in the MDN Reference for .find():
callback
Function to execute on each value in the array, taking three
arguments:
element The current element being processed in the array.
So writing:
array.filter(isEven);
Is equivalent to writing:
array.filter(function(item){
isEven(item);
});
The solution is in this line
var newArray = array.filter(isEven); //uses a callback to check if an element is even
Here you are calling the method "filter" on the array. Filter takes a method that returns true or false, and calls it on each of the array element, passing the element itself. That line could be implemented like this
let newArray;
for(let x: array){
if(isEven(x)){
newArray.push(x);
}
}
The filter() function on an array takes a function as it's input. In this case that input function is the isEven function. The filter function then iterates over the array and runs the isEven function over each of the elements. It then filters out any elements in the array for which the function returned false.
Note that in the parentheses of the filter function you do not specify any arguments to the isEven function. That is because filter does this for you.
Your code is equivalent to:
var newArray = [1, 2, 3, 4, 5].filter(x => x % 2 == 0);
The x value is taken in your first array. See the doc.
filter is a function defined in the Array API, it receives as a parameter a "this" which in your case is the variable "array" and a callback that would be "isEven", inside that "this" is the values of your array, it just need to go through it and call each one to your function.
Read this
array.filter will automatically take this as its argument if not passed, when it is getting looped. Check here for more details.
So, in case of your array this values corresponds to the elements 1,2,3,4,5
If a thisArg parameter is provided to filter, it will be used as the
callback's this value. Otherwise, the value undefined will be used as
its this value. The this value ultimately observable by callback is
determined according to the usual rules for determining the this seen
by a function.
This question already has answers here:
Understanding Javascript callback parameters
(3 answers)
Closed 5 years ago.
var animals = ["cat","dog","fish"];
var lengths = animals.map(function(c) {
return c.length;
});
console.log(lengths);//[3, 3, 4]
Here is the code. I don't understand where this 'c' argument comes from.
I tried to change this argument to another one (any word, actually, in both places), and the console.log result is always the same!
But this 'c' is not defined anywhere! Where does 'the engine' get the value of this 'c'?
You've asked two slightly different questions. First to the question body:
I don't understand where this 'c' argument comes from. I tried to change this argument to another (any word, actually, in both places), and the console.log result is always the same!
But this 'c' is not defined anywhere!
Where does 'the engine' gets the value of this 'c'?
You define the parameter name (as you've noticed, you can choose any name for it you like). The value comes from the array, because map calls your callback and determines what argument to pass for that parameter.
Here's a conceptual implementaton of Array.prototype.map, which make make this clearer:
// CONCEPTUAL ONLY, NOT AN ACTUAL VERSION OF IT
function maplike(array, callback) {
var result = [];
for (var i = 0; i < array.length; ++i) {
result[i] = callback(array[i]);
// ^^^^^^^^--- where 'c' comes from
}
return result;
}
var animals = ["cat","dog","fish"];
var lengths = maplike(animals, function(c) {
return c.length;
});
console.log(lengths);//[3, 3, 4]
Do array elements have names by default in JavaScript?
Sort of, but not in the way you're thinking. The name of the element is its index, 0, 1, etc. In fact, JavaScript arrays aren't really arrays at all* and those indexes are converted to string property names (in theory; in practice, JavaScript engines optimize it).
* (disclosure: that's a post on my anemic little blog)
You're telling the interpreter how the parameter is called, here:
function(c) {
^
Array.prototype.map() requires a callback that accepts up to 3 parameters. The first parameter is always the "current item", which you happen to have named c.
For a more in-depth explanation, have a look at T.J. Crowders answer, as well.
In javascript, functions are first class object, which means they can be assigned to variables, passed as function parameters and returned from values. The Array.prototype.map function takes a function with it's first parameter denoting an item of the array. When invoked, the map function executes the given function for each of the items and creates a new array from the outputs of the given function.
In your case, you are defining the input function on the fly, inside the map function.
You can actually define the function outside and pass the function by reference inside map like below.
function getLength(item) {
return item.length;
}
var animals = ["cat","dog","fish"];
var lengths = animals.map(getLength);
console.log(lengths);//[3, 3, 4]
Here, you can see it outputs the same result.
The code does not know what is the parameter named. You map an array. map function creates a new array in the lengths variable (variable being assigned to). How? It provides to the function parameter inside it, each element in the current array one-by-one by value.
Here the value is actual string name ("cat" or "dog" or "fish").
In javascript, parameters can be optional. This map function can take three parameters, currentValue, index, array. In your case, c provides currentvalue.
If you would add one more parameter c,idx. Map function will get currentvalue and index inside it.
var animals = ["cat","dog","fish"];
var lengths = animals.map(function(c, idx, arr, test) {
console.log(c); // currentvalue being processed in the array.
console.log(idx); // index of currentvalue in the array
console.log(arr); // original array being operated on.
console.log(test); // undefined always. not available in map.
return c.length;
});
console.log(lengths);//[3, 3, 4]
var curryIt = function(uncurried) {
var parameters = Array.prototype.slice.call(arguments, 1);
return function() {
return uncurried.apply(this, parameters.concat(
Array.prototype.slice.call(arguments, 0)
));
};
};
var greeter = function(greeting, separator, emphasis, name) {
console.log(greeting + separator + name + emphasis);
};
var greetHello = curryIt(greeter, "Hello", ", ", ".");
greetHello("Heidi"); //"Hello, Heidi."
greetHello("Eddie"); //"Hello, Eddie."
I get the overall picture of what is happening but I do not understand what is being carried out in the curryIt function.
Every function has an object called arguments, which contains in an array like data structure the arguments which the caller of the function uses.
For example, let that we have the following function:
function sum(a,b){
return a+b;
}
If we call sum as below:
sum(3,4)
the arguments would contain two items 3 and 4. (Actually, you could call sum with 3, 4 or more arguments. All these values would be contained in the arguments).
The key word in the above statement is the array like data structure. arguments is not an array. So you can't have available the Array's methods (push, shift, slice, etc.)
What does slice?
The slice() method returns a shallow copy of a portion of an array
into a new array object selected from begin to end (end not included).
The original array will not be modified.
For further info please have a look here.
So if you want to apply slice on arguments would could you do?
Since arguments is not an array, (arguments instanceof Array returns false), you can't do so like below:
var a = ["zero", "one", "two", "three"];
var sliced = a.slice(1,3);
But you can't do it like below:
Array.prototype.slice.call(arguments, 1);
What does call?
The call() method calls a function with a given this value and
arguments provided individually.
For further info please have a look here.
So, essentially, the following line of code
Array.prototype.slice.call(arguments, 1);
calls the function called slice on the arguments objects passing 1 as it's argument. So you get an array with all the arguments except the first.
This is all about a functional programming paradigm called Currying. It's all about saving one or more arguments into a returned function to be re used at a later time. It's highly related with the closures topic of JavaScript.
Let's refactor the code in a more functional manner.
var curryIt = (uncurried,...args) => name => uncurried(...args,name),
greeter = (greeting, separator, emphasis, name) => console.log(greeting + separator + name + emphasis),
greetHello = curryIt(greeter, "Hello", ", ", ".");
greetHello("Heidi"); //"Hello, Heidi."
greetHello("Eddie"); //"Hello, Eddie."
curryIt function takes several argument of which the first one is a function called uncurried the rest of the argument are collected in the args array by the help of the rest operator (...) of ES6.
Then we return a function which takes a single argument called name and makes use of the parameters passed to it's parent function by args array. So, right now the args array and it's elements are under closure. The returned function will invoke the passed uncurried function by providing the available arguments in a proper order.
I am trying to understand what this javascript does and I am looking at foreach and okay, I am guessing name variable is coming from the array. I can verify that from console.log. I can also verify, although I have no idea where it's coming from, that i is 0,1,2.
Can someone please point me to right direction of where this variable 'i' is coming from and how forEach works?
function getNames() {
var length = 0
, names = "";
['John', 'Susan', 'Joe'].forEach(function (name,i) {
length = i + 1;
names += name + ' '
})
return {
length: length,
names: names
}
}
undefined
console.log(getNames());
Object {length: 3, names: "John Susan Joe "}
undefined
If you look the docs properly it tells
The forEach() method executes a provided function once per array element.
ForEach takes a callback function which can take 3 parameters.
1) Current Value
2) Index of current value // which is 0,1,2
3) Array Itself.
So in following passes value of variables will be as bellow
1) name ==> 'john', i ==> index of 'john' which is 0
2) name ==> 'Susan', i ==> index of 'Susan' which is 1
3) name ==> 'Joe', i ==> index of 'Joe' which is 2
Any time in JS you see a function that you don't understand, google it on Mozilla Developer Network, like this "mdn forEach". If the function has a $ in it, you might look google it adding "jquery". In this case, though, it is a builtin and so we look it up with mdn. MDN is not the ultimate authority on Javascript, but it is a very good resource as it is maintained by Mozilla, known for their Firefox web browser.
From MDN Array.prototype.forEach
Summary The forEach() method executes a provided function once per array element.
Syntax arr.forEach(callback[, thisArg])
Parameters
callback Function to execute for each element, taking three arguments:
currentValue The current element being processed in the array.
index
The index of the current element being processed in the array.
array
The array that forEach is being applied to.
thisArg Optional. Value to
use as this when executing callback.
You have ['John', 'Susan', 'Joe'].forEach(function (name,i) so you will see that forEach is being called as a method on the Array ['John', 'Susan', 'Joe']. Here the argument to forEach( ) is an anonymous function with two parameters function(name,i){...}. This function is supplying the callback function mentioned in the docs. That supplied function will get called by forEach as many times as there are elements in the array. The docs say we will get 3 parameters, and in JS the 3rd parameter in this case (the array being modified) is being ignored as the function is written to only take two parameters.
So, matching up the parameters in the provided function with the specification, in this case name is going to be the current value from the array, and i the index number.
Note, though, that what to call the parameters in a function(param1,param2) is completely up to the developer. When reading someone else's code, you have to match up what they called param1 and param2 with what the specification or documentation for that feature says.
How foreach works is it takes a function as its argument. That function is then called for each element of the array with the following arguments function(current_value,current_index,original_array) for example you can do this.
var sumVal = 0,
sumInd = 0,
myArray = [2,4,6];
function sumValues(current){
sumVal += current;
}
function sumIndexes(notGonnaUse,index,o_array){
sumInd += index;
}
// the following is equivalent to calling sumValues three times
// sumValues(myArray[0], 0, myArray);
// sumValues(myArray[1], 1, myArray);
// sumValues(myArray[2], 2, myArray);
myArray.foreach(sumValues);
// sumVal is now equal to 2+4+6=12
// the following is equivalent to calling sumIndexes three times
// sumIndexes(myArray[0], 0, myArray);
// sumIndexes(myArray[1], 1, myArray);
// sumIndexes(myArray[2], 2, myArray);
myArray.foreach(sumIndexes);
// sumIndex is now equal to 0+1+2=2
In each case the function is passed all three arguments even though sumValues is defined to take only one argument. The remaining arguments can still be accessed using the arguments object.
Internally the function is free to call the arguments whatever it wants.
In the previous example we used named functions to pass to foreach, but in your example an anonymous function was passed
function (name,i) {
length = i + 1;
names += name + ' '
}
This function sets
name = current value
i = current index
it was also passed in the original array ['John', 'Susan', 'Joe'] as the third argument. Since it wasn't used the programmer didn't bother naming this argument. It can still be accessed however using arguments[2].
I know this is a silly question so please go easy.
I'm having trouble understanding documentation in general such as this page:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
Can someone explain the terms 'callback' 'currentValue' 'index' 'array' (in that context) and 'thisArg' in very basic layman's? I'm sure it's something simple but it's just not clicking in my brain, and it's making learning the language on my own very difficult so I would greatly appreciate the help.
I'll try to make it very simple and understandable.
A callback function is passed as an argument to a function (like age is passed to foo in the example below) and is executed after a certain event. It is called callback because it is executed not before the parent function (to which the callback function was passed to as an argument) itself is executed.
For example:
function foo(age, function callBack()) {
print("I am " + age + " years old");
}
function gender() {
print(" and male");
}
function certainEvent() {
foo(99, gender);
}
If you now call certainEvent(), the result would be:
I am 99 years old and male
callback is a function that you pass to map. It will be called with the arguments currentValue, index and array.
For instance using a callback that logs:
[1, 2, 3].map(function(currentValue, index, array) {
console.log("currentValue", currentValue);
console.log("index", index);
console.log("array", array);
});
Logs:
currentValue 1
index 0
array [1, 2, 3]
currentValue 2
index 1
array [1, 2, 3]
currentValue 3
index 2
array [1, 2, 3]
Note that the function doesn't have to inline, this is equal:
function mapper(currentValue, index, array) {
console.log("currentValue", currentValue);
console.log("index", index);
console.log("array", array);
}
[1, 2, 3].map(mapper);
.map is a function. Function usually accept arguments. The part you are referring to describes the arguments and their purpose in more detail. Lets have a look at the signature of the function:
arr.map(callback[, thisArg])
This tells you that the function takes two arguments, where the second argument is optional (indicated by the [...]).
The documentation chose to name the first argument "callback" and the second argument "thisArg". It could have chosen different names ore no names at all and simply referred to the "first" and "second" argument.
Of course the chosen names carry some meaning, but this is only secondary. Naming them at all is done to be able to easily refer to those arguments later in the documentation. Whenever you see callback (i.e. formatted as code) in the documentation for .map, such as
Value to use as this when executing callback.
you know that it refers to the first argument.
Similarly "currentValue", "index" and "array" are labels for the arguments that are passed to the first argument of .map ("callback"), since that argument is supposed to be a function as well.
currentValue by itself doesn't really mean anything. However, in the context of .map it refers to the first argument that is passes to the first argument of .map. It's meaning is described in the documentation:
The current element being processed in the array.
This follows the typical way we write functions. When you declare a function, you usually give the parameters names. For example:
function first(arr) {
return arr[0];
}
Here I am giving the first parameter the name arr so I can refer to it more easily later. The same happens in the documentation: The parameter/argument gets a name so it can easily be referred to later.
The map method has two arguments. The callback and the scoping parameter.
The callback is the function that you set that does the processing. It has three arguments that give you the state of the current iteration as map loops over the array.
var myArray = [1,2,3,4,5];
function callback ( currentValue, index, array) {
console.group("callback called");
console.log("currentValue:", currentValue); //Current value of the index aka `array[index]`
console.log("index:", index); //current index of the loop (think of it as a for loop (var i=0; i<array.lenght; i++) It would be i.
console.log("array:", array); //The array you are looping over..aka a reference to myArray
console.groupEnd("callback called");
return currentValue * 2;
}
var result = myArray.map(callback);
console.log(result);
And the [] in the method declaration [, thisArg] states that that parameter/argument is optional.