Understanding the 'necessity' of arguments of a forEach method - javascript

Documentation seems to suggest that in a forEach method, a callback function is a mandatory parameter and currentValue is a mandatory parameter of the callback function:
However this code - without a parameter of the callback function - works fine:
a = [1, 2, 3, 4, 5];
a.forEach(function () {
console.log(5);
})
How am I to understand when MDN positions 'optional' around some parameters and not around others?

There is no way to enforce that a function accepts mandatory parameters. However, without using the currentValue parameter, there is really no point of forEach; you do not necessarily need to use any of the other parameters, though. All of the arguments are still passed to the function, which you can see if you print out the arguments.
a = [1, 2, 3, 4, 5];
a.forEach(function () {
console.log("Number of arguments:", arguments.length);
console.log("Current value:", arguments[0]);
console.log("Index:", arguments[1]);
console.log("Original array:", arguments[2]);
})

In this case you don't use any elements of array, you just print 5. For main task any interaction of array you need the currentValue for do some manipulations with array
a = [1, 2, 3, 4, 5];
a.forEach(function (currentValue) {
console.log(currentValue, 5);
})

Related

Remove multiple elements from an array using a function

What I am trying to do is to return the [1, 4] array, however, I do not understand what's the mistake which ends up returning [1]. Any clues? Thank you!
const removeFromArray = function(arr) {
for (let i = arr.length - 1; i >= 0; i--) {
arr.splice(arr[i], 2);
}
return arr;
};
console.log(
removeFromArray([1, 2, 3, 4], 3, 2)
)
It's not exactly clear to me what you want to achieve.
You define a function which only takes one argument:
const removeFromArray = function(arr) {...}
But then you call the function with 3 arguments, an array and two numbers:
removeFromArray([1, 2, 3, 4], 3, 2)
Now your function only takes the first input (the array) and removes all elements instead the first one.
Please consider the syntax: splice(start, deleteCount)
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
Maybe this rm() does what you want?
const rm=(arr, ...rem)=>arr.filter(a=>!rem.includes(a));
console.log(rm([1, 2, 3, 4], 3, 2));
It treats the first argument as the array arr that is to be filtered. The following arguments then make up the array rem, containing all the elements that are to be taken out of array arr.
You should consider using the built in filter method for arrays.
removeFromArray = (array, unwanted, otherUnwanted) => {
const filtered = array.filter((number) => {
return number !== unwanted && number !== otherUnwanted
});
return filtered;
};
console.log(removeFromArray[1,2,3,4], 3, 2]
To make the function more scalable for future use the second parameter could be an array.
betterRemoveFromArray = (array, unwantedNumbers) => {
const filtered = array.filter((number) => {
return !unwantedNumbers.includes(number)
});
return filtered;
};
console.log(removeFromArray3([1, 2, 3, 4], [2, 3]));
You need to write a variadic function which means it accepts a variable number of arguments. To represent it, use the rest parameter syntax which allows the function to accept an indefinite number of arguments as an array.
Then, use the filter method on the 1st argument, like so:
const removeFromArray = function(arr, ...theArgs) {
arr = arr.filter(arg => !theArgs.includes(arg));
return arr;
};
console.log(
removeFromArray([1, 2, 3, 4], 3, 2)
)

Ramda: Confused about pipe

I'm learning functional programming in JS and I'm doing it with Ramda.
I'm trying to make a function that takes parameters and returns a list. Here is the code:
const list = R.unapply(R.identity);
list(1, 2, 3); // => [1, 2, 3]
Now I tried doing this using pipe:
const otherList = R.pipe(R.identity, R.unapply);
otherList(1,2,3);
// => function(){return t(Array.prototype.slice.call(arguments,0))}
Which returns a weird function.
This:
const otherList = R.pipe(R.identity, R.unapply);
otherList(R.identity)(1,2,3); // => [1, 2, 3]
works for some reason.
I know this might be a newbie question, but how would you construct f(g(x)) with pipe, if f is unapply and g is identity?
Read the R.unapply docs. It's a function that gets a function and returns a function, which can take multiple parameters, collect it to a single array, and pass it as the parameter for the wrapped function.
So in the 1st case, it converts R.identity to a function that can receive multiple parameters and return an array.
In the 2nd case, R.unapply gets the result of R.identity - a single value, and not a function. If you pass R.identity as a parameter to the pipe, R.unapply gets a function and return a function, which is similar to the 1st case.
To make R.unapply work with R.pipe, you need to pass R.pipe to R.unapply:
const fn = R.unapply(R.pipe(
R.identity
))
const result = fn(1, 2, 3)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
It looks as though you really are thinking of pipe incorrectly.
When you use unapply(identity), you are passing the function identity to unapply.
But when you try pipe(identity, unapply), you get back a function that passes the results of calling identity to unapply.
That this works is mostly a coincidence: pipe(identity, unapply)(identity). Think of it as (...args) => unapply(identity(identity))(...args). Since identity(identity) is just identity, this turns into (...args) => unapply(identity)(...args), which can be simplified to unapply(identity). This only means something important because of the nature of identity.
You would use unapply to transform a function that would normally take its arguments as an array into a function that can take any number of positional arguments:
sum([1, 2, 3]); //=> 6
unapply(sum)(1, 2, 3) //=> 6
This allows you to, among many other things, map over any number of positional arguments:
unapply(map(inc))(1, 2) //=> [2, 3]
unapply(map(inc))(1, 2, 3) //=> [2, 3, 4]
unapply(map(inc))(1, 2, 3, 4) //=> [2, 3, 4, 5]
identity will always return its first argument. So unapply(identity)(1,2) is the same as identity([1,2]).
If your end goal was to create a function that returns a list of its arguments, I don't think you needed pipe in the first place. unapply(identity) was already doing that.
However, if what you need to do is to make sure that your pipe gets its parameters as a list, then you simply need to wrap pipe with unapply:
const sumplusplus = unapply(pipe(sum, inc, inc));
sumplusplus(1, 2, 3); //=> 8

How to navigate and pull from an object in JavaScript

I am being given the function call destroyer([1, 2, 3, 1, 2, 3], 2, 3);. I want to be able to pull from the last 2, 3 part after the initial object, but I do not know how to go about this.
return arr[6]; and return arr[1][0] both return nothing. I am expecting to see 2 or 2, 3 (Last two numbers)
I tried researching Property Accessors, but I think I was looking in the wrong place for my answer.
Here's my full code:
function destroyer(arr) {
return arr;
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
Instead of getting the first array [1,2,3,1,2,3]
I want to get the parts after the array:
[1,2,3,1,2,3],2,3
You're destroyer function is only taking one argument, but you're passing it 3.
You have two options:
Use arguments to get an array-like of all the passed arguments, you'll then need to combine that with a method like slice to get only the second and third arguments. Additionaly since arguments isn't technically an array, you need to convert it to one before you can call a method like slice. My example uses Array.from however that is only available on newer browsers.
function destroyer(arr) {
return Array.from(arguments).slice(1,3);
}
console.log('Result: ', destroyer([1, 2, 3, 1, 2, 3],2,3));
Add additional parameters to your function definition. This is probably easier if you know you'll have exactly 3 arguments. And there are far fewer gotchas compared to using the magic arguments variable.
function destroyer(a, b, c) {
return [b, c];
}
console.log('Result: ', destroyer([1, 2, 3, 1, 2, 3], 2, 3));
try use arguments
example
function destroyer(){var arr = []; arr.push(arguments[1]);arr.push(arguments[2]); return arr};

Someone please explain the Function.apply.bind(Math.max, null) algorithm

suppose we have this code
function largestOfFour(arr) {
return arr.map(Function.apply.bind(Math.max, null));
}
where arr is an array of arrays.
first,why must i use apply()?
I understand that when using the method Math.max() to operate on an array i must add the apply() method also. So i'll have something like this Math.max.apply(null, arr) why? what does apply() do?
In this code arr.map(Function.apply.bind(Math.max, null)) what does bind() really do?
Please give an explanation i can understand,i really appreciate this.
Looking at the entire expression:
arr.map(Function.apply.bind(Math.max, null));
map expects its first argument to be a function, which is returned by:
Function.apply.bind(Math.max, null);
Function.apply is a shorter version of Function.prototype.apply.
Calling bind on it returns a special version of apply whose this is set to Math.max and when called, will have as it's first parameter (i.e. the value that would normally be used as this) set to null, since it's not going to be used.
So each element in arr will effectively be called using:
Math.max.apply(null, member);
The use of apply means the values in member are passed as parameters, as if:
Math.max(member[0],member[1] ... member[n]);
So the expression returns the maximum value in each array. Those values are returned to map, which puts them into a new array.
var arr = [[1,2,3],[4,5,6]];
console.log(
arr.map(Function.apply.bind(Math.max, null)) //[3, 6]
);
and is effectively the same as:
var arr = [[1, 2, 3],[4, 5, 6]];
console.log(
arr.map(function(a) {return Math.max.apply(null, a)}) //[3, 6]
);
Though using recent features you might use destructing with rest parameter syntax:
var arr = [[1, 2, 3],[4, 5, 6]];
console.log(
arr.map(a => Math.max(...a)) // [3, 6]
);
Simply put, .apply calls a function with the set of arguments(array-like) passed to it.
EG:
const add = (...args) => args.reduce((acc, next) => acc + next);
I can call the add function with any number of arguments using the .apply method like this.
add.apply(null, [4, 2, 6, 76, 9]) // => 97.
You call also use .call but instead of passing in array-like arguments, you simply pass in the values
add.call(null, 4, 2, 6, 76, 9) // => 97.
With .bind, the difference is that it creates a new function with call be called later.
const addFunc = add.bind(null, 4, 2, 6, 76, 9);
addFunc() // -> 97.
So, as it applies to the function we defined, it also applies to inbuild functions like Math.max, Math.min, etc.
Hope this helps!
The Function.apply.bind(Math.max, null) creates a function definition when invoked takes null as the first parameter by default and any provided parameters will come second. So as a callback to arr.map this function (due to bind statement) will be bound to Math.max however the Function.apply's first parameter will be null and second is going the be the sub array item of the main array (of which the items are to be passed as arguments to Math.max function).
This is an old trick and in ES6 terms arr.map(s => Math.max(...s)); would do the same job much more clearly.

Typescript supplied parameters do not match any signature of call target

So I have a function like this:
function foo(a, b, c, d, e) {
// something creative
}
When I call it like this:
foo(1, 2, 3, 4, 5);
It works fine.
...But when I call it like this:
const lastTwo = [4, 5];
foo(1, 2, 3, ...lastTwo);
Typescript screams that:
error TS2346: Supplied parameters do not match any signature of call target.
How can I overcome it?
You'll need to use the apply function, but you'll also need to have all the params in the array:
const args = [1, 2, 3, 4, 5];
foo.apply(null, args);
The reason is that your method signature has a a specific number of arguments, yet you are calling it with a variable number of arguments. You can solve this by changing the signature.
function foo(a, b, c, ...remaining) {
// something creative
}
const lastTwo = [4, 5];
foo(1, 2, 3, ...lastTwo);

Categories

Resources