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].
Related
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.
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 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.
If there's anyone who can help me understand this one, I will be impressed. It's #28 from John Resig's advanced JavaScript.
Here's a function for looping, and, if you look at the tutorial, it seems to run 3 times producing the 6 Pass below.
Can you please explain in plain language in as much detail as possible what is happening in this program, explaining along the way:
fn.call(array, array[i], i) Why are there these 3 parameters to the function and how do they all work. Does the function first deal with array, then array[i], and then i? What's happening when all that is going on?
Also, in the function, I understand that i++ goes up every time that it goes through the array.length, but what triggers num++ to increase it's value, and in what way is value == num++
In function(value, i), what is value? Is value alternately 0,1,2 of the loop array? If so, how do those loop array numbers get passed as a parameter in function(value, i)
this instanceof Array what is this trying to show? How?.
Code:
function loop(array, fn){
for ( var i = 0; i < array.length; i++ )
fn.call( array, array[i], i );
}
var num = 0;
loop([0, 1, 2], function(value, i){
assert(value == num++, "Make sure the contents are as we expect it.");
assert(this instanceof Array, "The context should be the full array.");
});
PASS Make sure the contents are as we expect it.
PASS The context should be the full array.
PASS Make sure the contents are as we expect it.
PASS The context should be the full array.
PASS Make sure the contents are as we expect it.
PASS The context should be the full array.
The function is an anonymous function, that is, a function without a name. The full second argument to loop is
function(value, i) {
assert(value == num++, "Make sure the contents are as we expect it.");
assert(this instanceOf Array, "The context should be the full array.");
}
which is a complete anonymous function which takes three arguments: this (the object for which it is a method), the current value, and the loop counter.
loop iterates over the array, and uses fn.call to invoke the anonymous function, passing it three arguments; here, the array object must be explicit, because call can't know what context the function reference it's being invoked on should be invoked in (that is, what to make this in the call).
The anonymous function, as invoked by loop, receives the array as this. The second ASSERT verifies this. It also expects that the array's value is [0, 1, 2] and verifies this by incrementing num on each call and comparing that to the passed array element.
So, following the execution chain:
num is declared and initialized to 0.
loop([0, 1, 2], function ...) is invoked.
loop invokes fn, the anonymous function, with the array (as this), its first element, and i which indicates the element offset. (i is never actually used.)
The anonymous function ASSERTs that it was passed the expected first element, 0, by comparing against num and incrementing num afterward.
The anonymous function ASSERTs that its this is an Array.
loop invokes fn as in #3, but with the second array element.
The anonymous function again performs its ASSERTs, this time comparing the passed second array element, which is expected to be 1, against num (which, because of the post-increment in step 4, is 1).
loop invokes fn as before with the third array element.
The anonymous function does its ASSERTs again, this time comparing the expected array element 2 against num whose value is now 2.
fn is a function pointer to the anonymous function that was created when invoking loop.
a) There are three parameters because the first one is a reference to the object you are going to be acting on, i.e. the array, the 2nd parameter is just current value in the iteration of the array, and the third value is location of that element in that array.
b) when you call num++, it increments the value of num. The post increment returns the value (aka assigns to value) and then increments num.
c) value is the 2nd parameter passed in by fn.call a couple lines up.
d) this refers to the array that you passed into the first parmater in your fn.call() invocation.
I think an easier way to understand what's going on is to remove the usage of call and instead invoke the method directly - the old fashioned way.
function loop(array, fn) {
for(var i = 0; i < array.length; i++)
fn(array[i], i);
}
var num = 0;
loop([0, 1, 2], function(value, i) {
assert(value == num, "Make sure the contents are as we expect it.");
assert(this instanceof Array, "The context should be the full array.");
num++;
});
If you run this code on the source url, you would see the this instanceof Array test fails each time, since this is not pointing to an instance of Array anymore.
To make this point to an instance of Array, we need to invoke the method using call or apply.
fn.call(array, array[i], i);
The first parameter is what this will point to. All other parameters here are passed as arguments to the function being called. Note that we can cheat here to pass the test. Instead of passing the array object that we are looping over, you can pass any Array object to make the second test pass.
fn.call([], array[i], i);
fn.call([1,2,3,4,5], array[i], i);
I don't actually know javascript but I believe I understand whats going on...
The first four lines are defining a function called loop. Loop takes in two variables, an array and a function. The only reason why I believe the second parameter is function is because the coder called call on the variable which probably calls the function. The function loops through the elements of the array and passes them to the function somehow through the call method. You should probably look this part up.
After the definition, num is defined to start at zero.
Then comes the fun part. The function loop is called with the parameters [0, 1, 2] and an anonymous function that was created on the spot. function(value, i) and everything after it is the definition of this anonymous function. It has no name but it just defined for this function call. The function checks to make sure that value equals num and increments num after it and then checks to makes sure the variable is an array.