How these inner function parameters are getting a value? [duplicate] - javascript

This question already has answers here:
Where do the parameters in a javascript callback function come from?
(3 answers)
Closed 1 year ago.
I saw that function and tried to understand it, but I don't get what are the (a, i) arguments of that function. How they're getting a value assigned to them?
function ftRotations() {
let str = 'abc';
let arr = ['a', 'b', 'c'];
return arr.map(function (a,i) {
return str.slice(i)+str.slice(0,i)
});
}

The map method provides arguments when calling the callback, which are received by the callback in the a and i parameters it declares. (The callback doesn't use a for anything, but uses i. The callback also uses str, which it closes over because the function was created in a context where str exists.)
It may help to see a rough idea of what map does internally:
// Note: VERY ROUGH approximation, leaving out all kinds of details (like `thisArg`)
map(callback) {
// Note: `this` is the array you called `map` on
const result = [];
for (let index = 0; index< this.length; ++index) {
result[index] = callback(this[index], index, this);
// In the callback, ^^^^^^^^^^^ ^^^^^
// becomes `a` −−−−−−−−−−−−−−/ \−−−−−−−becomes `i`
}
return result;
}

Related

Javascript - Higher order functions, callbacks, returning, scope chain - I could use some assistance, see example pleas

I really could use some help in understanding how this all works. Please bare with since I am a disabled learner who sometimes can not grasp basic concepts like other people. I have tried looking it up, searching Google, and Chatgpt for answers, but I seem to have a problem with closure I believe it called.
function eitherCallback(callback1, callback2) {
return num => callback1(num) || callback2(num)
}
function filterArray(array, callback) {
const newArray = [];
for (let i = 0; i < array.length; i += 1) {
if (callback(array[i],i, array)) newArray.push(array[i]);
}
return newArray;
}
const arrOfNums = [10, 35, 105, 9];
const integerSquareRoot = n => Math.sqrt(n) % 1 === 0;
const over100 = n => n > 100;
const intSqRtOrOver100 = eitherCallback(integerSquareRoot, over100);
console.log(filterArray(arrOfNums, intSqRtOrOver100)); // should log: [105, 9]
So, what I do not understand is the value/values being sent to eitherCallback and how the arguments work.
So first filterArray has 2 parameters, arrOfNums and intSqRtOrOver100
So I was able to figure out a lot of problems like that intSqRtOrOver100 is a function just a variable, a function expression, however, that is not hoisted so filterArray would go first.
arrOfNums would be the array, and intSqRtOrOver100 would invoke intSqRtOrOver100 the function,
First Question/Issue: intSqRtOrOver100 is the function calling eitherCallback(integerSquareRoot, over100);? So intSqRtOrOver100 would take not arguments, however, filterArray is passing it iteration of referenced index in the array passing the value to the callback which is intSqRtOrOver100. So it would be 10 passed to intSqRtOrOver100?
Yet, there are 3 arguments being sent to intSqRtOrOver100?
Second Question/Issue: When intSqRtOrOver100 is invoked by the callback, intSqRtOrOver100 is calling eitherCallback with two parameters, so the two parameters are functions passed in as arguments which I understand, however, when intSqRtOrOver100 is invoked, those two parameters are not being passed arguments since they are functions yet, somehow it is being sent an element from the array?
Third Question/Issue: So eitherCallback has two functions and is created by intSqRtOrOver100 invoked, I am passing an element from the array and somehow 3 things from filterArray? Also, no arguments are being sent since they are functions, then inside of the function I am using a return function I guess the name if "num", however, how can Callback1(num) exist? Nothing is declared as num except itself. Changing the parameter name defaults to an error. I understand the about it being true and condition of it but, not how Callback1 is being called with "num" itself and how come the index, plus two others are being passed into it yet, I can not access the newArray, i or the array inside of eitherCallback, yet shouldn't filterArray be the higher order function and since it's the parent, should I be able to access it values?
Please, I have really tried for over 8 hours to understand this. I do understand some of it, but, since this is my first time asking for help, I was nervous about asking and hope I got it to come out right. If you could explain it to me simply and slowly because I am not quite understanding and I really want to learn this concept if possible. Thank you so much for your time.
Searched:
Google
Stackoverflow
Videos
ChatGPT
Chegg
Various Websites
Digital Ocean
Youtube
I'll give a little try to explain. The core that you are missing is the thing that is happening here:
function eitherCallback(callback1, callback2) {
return num => callback1(num) || callback2(num);
}
This function takes 2 parameters, callback1 and callback2, which supposed to be a functions. And returns a function which takes 1 argument named (num) and executes 2 closure captured functions (callback1 and callback2) with that num. Basically, it is an alternative to this:
function eitherCallback(callback1, callback2) {
function fn(num) {
return callback1(num) || callback2(num);
}
return fn;
}
Now about this section:
const integerSquareRoot = n => Math.sqrt(n) % 1 === 0;
const over100 = n => n > 100;
const intSqRtOrOver100 = eitherCallback(integerSquareRoot, over100);
Here you are declaring 2 arrow functions, integerSquareRoot and over100. They both are functions that take 1 argument. Equivalent:
function integerSquareRoot(n) {
return Math.sqrt(n) % 1 === 0;
}
function over100(n) {
return n > 100;
}
const intSqRtOrOver100 = eitherCallback(integerSquareRoot, over100);
Here you are calling eitherCallback with 2 arguments. Basically you are passing the references to those functions, and they are "wired" now, closure captured.
So, now, intSqRtOrOver100 is the fn returned from eitherCallback, which has integerSquareRoot as callback1 and over100 as callback2. And it does take 1 argument, which is (num).
Now about this section:
function filterArray(array, callback) {
const newArray = [];
for (let i = 0; i < array.length; i += 1) {
if (callback(array[i],i, array)) newArray.push(array[i]);
}
return newArray;
}
Especially the callback(array[i], i, array) - why it is called with 3 parameters - just conventionally, I guess, inspired by Array.filter(), for example, which also accept a callback function with 3 parameters. But still, you can pass a callback function that takes 1 parameter only and it is absolutelly normal. You can easilly check what is passed to your callback by:
function eitherCallback(callback1, callback2) {
return (num) => {
console.log(num);
return callback1(num) || callback2(num);
};
}
or
function eitherCallback(callback1, callback2) {
return (num, index, array) => {
console.log(num, index, array);
return callback1(num) || callback2(num);
};
}
So, to summarize:
Q1 and Q2 - intSqRtOrOver100 is the function that takes 1 parameter (num) and is internally wired to integerSquareRoot and over100 via closure.
Q3 You are passing 3 parameters to intSqRtOrOver100 hovewer intSqRtOrOver100 utilizes only 1st parameter, rest ones are ignored.

Getting Function Arguments Using (...args) [duplicate]

It was really confusing for me to read this syntax in Javascript:
router.route('/:id')
.put((...args) => controller.update(...args))
.get((...args) => controller.findById(...args));
What does ...args mean?
With respect to (...args) =>, ...args is a rest parameter. It always has to be the last entry in the parameter list and it will be assigned an array that contains all arguments that haven't been assigned to previous parameters.
It's basically the replacement for the arguments object. Instead of writing
function max() {
var values = Array.prototype.slice.call(arguments, 0);
// ...
}
max(1,2,3);
you can write
function max(...value) {
// ...
}
max(1,2,3);
Also, since arrow functions don't have an arguments object, this is the only way to create variadic (arrow) functions.
As controller.update(...args), see What is the meaning of "foo(...arg)" (three dots in a function call)? .
Essentially, what's being done is this:
.put((a, b, c) => controller.update(a, b, c))
Of course, what if we want 4 parameters, or 5, or 6? We don't want to write a new version of the function for all possible quantities of parameters.
The spread operator (...) allows us to accept a variable number of arguments and store them in an array. We then use the spread operator again to pass them to the update function:
.put((...args) => controller.update(...args))
This is transparent to the update function, who receives them as normal arguments.
The meaning of “…args” (three dots) is Javascript spread operator.
function sum(x, y, z) {
return x + y + z;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers));
// expected output: 6
If you know some Python syntaxes, it is exactly the same as *args. Since *args (Python) is tuple object and Javascript has no tuple like Python, ..args is an Array object.
means pass all values (useful if have unknown# of items)
sample code
console.log(sum(1, 2, 3, 4)); // expected output: 10
function sum(...allItems) {
let total = 0;
for (const item of allItems) {
total += item;
}
return total;
}
It's called 'rest parameter', you can use rest parameter to pass unspecified number of arguments as an array, And a function can have only one rest parameter and it have to be the last parameter for the function
function sum(...args){
let output = 0;
for(const num of args){
output += num;
}
return output;
}
console.log(sum(2,4,8));
here it takes the argument that passed on sum as an array and sum the output and return it

Checking for collisions using filter()?

Normally I don't have too much trouble figuring out a problem in JS but this time I really need some help understanding this block of code. Mary Rose Cook used this logic in her space invaders game to filter through the bodies array to find collisions with other bodies.
var bodies = [];
...
update: function () {
// bodies is an array of all bodies in the game
var bodies = this.bodies;
var notCollidingWithAnything = function (b1) {
return bodies.filter(function(b2) { return colliding(b1, b2); }).length === 0;
};
this.bodies = this.bodies.filter(notCollidingWithAnything)
// ...insert function to draw the bodies that are in the new bodies array...
}
Can someone please explain how this.bodies.filter(notCollidingWIthAnything) works without passing in any parameters to the argument function? How does the the compiler know to check each element of the array against each other element of the array? Please guide me through what exactly happens in the compiler so that I can understand this.
Can someone please explain how this.bodies.filter(notCollidingWIthAnything) works without passing in any parameters to the argument function? How does the the compiler know to check each element of the array against each other element of the array?
The compiler (well, the JavaScript engine) doesn't know how to call notCollidingWIthAnything with the elements; Array#filter does.
notCollidingWIthAnything is a reference to the function. (Functions are proper objects in JavaScript, so we have references to them just like we have references to other objects.) The code passes that reference into Array#filter, and then Array#filter calls that function once for each element in the array, passing in the element value (and index, and array; it passes three args although we usually only use the first). Then it uses the return value of the callback to decide whether to include the element in the new array it builds.
Here's simplified code for Array#filter so you can see what's going on:
function arrayFilter(callback) {
// Remember this is called with `this` referring to an array-like object
// Create a new, empty array for the result
var result = [];
// Loop through the items
for (var index = 0; index < this.length; ++index) {
// Get the value for this entry
var value = this[index];
// Call the callback
if (callback(value, index, this)) {
// Got a truthy return value, include the value in the result
result.push(value);
}
}
// Return the new array
return result;
}
Again, that's simplified, not perfectly correct; for the perfectly correct steps, see the algorithm in the spec.
Here's an example with logging showing exactly who's doing what:
function arrayFilter(callback) {
console.log("Starting arrayFilter");
var result = [];
for (var index = 0; index < this.length; ++index) {
var value = this[index];
console.log("arrayFilter calling callback with value " + value);
if (callback(value, index, this)) {
console.log("arrayFilter got truthy result, include the value");
result.push(value);
} else {
console.log("arrayFilter got falsy result, don't include the value");
}
}
console.log("arrayFilter done");
return result;
}
function isOdd(value) {
var retval = value % 2 == 1;
console.log("isOdd called with " + value + ", returning " + retval);
return retval;
}
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log("calling `arrayFilter` with `a` as `this`, using `isOdd` callback");
var odds = arrayFilter.call(a, isOdd);
console.log("Resulting array: ", odds);

How a function got passed to another function?

I came across a weird code which I didn't understood. It would be great if I get explanation.
function forEach(array, action) {
for (var i = 0; i < array.length; i++) {
action(array[i]);
}
}
var numbers = [1, 2, 3, 4, 5], sum = 0;
forEach(numbers, function (number) {
sum += number;
});
console.log(sum);
How the function got passed as parameter ? and how the inner function is getting that number.
In JavaScript, functions are what's called first class citizens (that's not necessarily true for other languages), that means that functions can be treated as data, you can pass functions as arguments, return functions from other functions, and create functions and assign them to variables.
Here's a very simple example:
function callWithoutParams(fn) {
return fn(); // fn is the passed function.
}
let rand = callWithoutParams(Math.random); // Passing Math.random as a function.
callWithoutParams(() => console.log(42)); // Passing anonymous function
Array.prototype.forEach() accepts a function as an argument, and runs it on each element in the array. So a simpler example is:
[1,2,3,4,5].forEach((element) => console.log(element)); // outputs 1-5 in order.
In javascript, everything is an object, including function.
For simplicity, check this example:
var func = function(number){
console.log(number);
}
var arr = [1,2,3,4,5];
function foreach(data, callback){
for(var i = 0; i<data.length; i++){
callback(data[i]);
}
}
foreach(arr, func);
In JS, you can assign function to a variable. This is called as Function Expression. So it acts as a normal variable, just that its type is object.
This allows us to pass function as a parameter.
Now your second question, how the inner function is getting that number.
in your code, action(array[i]); is passing value as a parameter, so
function (number) {
sum += number;
}
here number is array[i].

javascript mystery - how functions get access to outside variables [duplicate]

This question already has answers here:
How do JavaScript closures work?
(86 answers)
Closed 7 years ago.
I am kind of new to javascript and trying to understand some non trivial - at least so i hope :) things.
my question is general, but i have a specific example which can help me ask my question and help you understand what i mean.
the example:
function updateBookmark(bookmark){
var index = _.findIndex($scope.bookmarks, function(b){
return b.id == bookmark.id;
});
return index;
}
obviously the findIndex function is declared somewhere (in our case - lodash.js)
and it gets two parameters (at least two visible parameters: a data set, and a function)
first question:
in this example, what is b? how does b gets its value? i understand b is each of the data set's objects, but i mean - what is going behind the scenes here so b will be what it is??
second question:
the author chose to pass an anonymous function which equals b.id with bookmark.id,
i understand that he can use bookmark.id where he is using it, but how does findIndex has access to this bookmark?!
this function as i concluded earlier is declared somewhere else, does it get all the variables in the scope some how?
what is going on here?
Thanks in advance to responders and sorry for the messy question...
Jim.
If you rewrite some things, it becomes easier to understand.
Starting with the last portion:
// Q: "How does `findIndex`have access to `bookmark`"
_.findIndex(bookmarks, function (b) { });
// A: "It doesn't."
var bookmark = { id: 1 };
var bookmarks = [ /* ... */ ];
function compareWithBookmark( test ) {
return test.id === bookmark.id;
}
_.findIndex(bookmarks, compareWithBookmark);
As you can see, findIndex doesn't actually have any access to bookmark.
Rather, it has access to a function which it can pass a value to test, and that function will return whether that test passed or failed.
Under the covers of .findIndex or [].map or [].filter, they're all just taking a function, making a loop, passing each element into the function one at a time, and doing something with the return value.
function findIndex (array, test) {
var index = -1;
var i = 0;
var l = array.length;
var el;
var result;
for (; i < l; i += 1) {
el = array[i]; // <-- how `b` got its value
result = test(el, i, array); // <-- test(b)
if (!!result) {
index = i;
break;
}
}
return index;
}
The different functions would do different things with the results (map returns a new array which contains each result, filter returns an array where only !!result tests passed, et cetera), but all of them do this inner-looping.
This is also a pretty gross simplification of the looping structure and considerations, but it's exactly what's driving your expected behaviour.
Edit
Here is a full usage of the function I just defined, plus the array, plus the object I'm checking.
var bookmarks = [
{ id: 2 },
{ id: 3 },
{ id: 6 },
{ id: 14 }
];
var bookmark = { id: 3 };
function compareBookmarkIdTest (el) {
return el.id === bookmark.id;
}
var index = findIndex(bookmarks, compareBookmarkIdTest);
index; // 1
Hope that helps.

Categories