Explanation of what is actually happening in ES6 Rest paramter - javascript

Please explain the following example.I am not able to understand what is actually happening here.Thank you in advance
function f (x, y, ...a) {
return (x + y) * a.length
}
f(1, 2, "hello", true, 7) === 9

Rest takes the 'rest' of the arguments and puts in them in an array which is assigned to a.
Your return statement turns into (1+2) * 3, which equals 9.
A simpler example:
[x, y, ...a] = [1, 2, 3, 4, 5, 6]
console.log(x)
// 1
console.log(y)
// 2
console.log(a)
// [ 3, 4, 5, 6 ]

If you think of arguments being passed as a simple array, then the following
function f(a,b,...c){...}
Can be converted to:
function f(args){
var a = args[0],
b = args[1],
c = args.slice(2);
//...
}

//function is getting defined here.
function f (x, y, ...a) {
return (x + y) * a.length
}
//function is getting called here.
f(1, 2, "hello", true, 7) === 9
When your function f is called, Inside the function f, your code takes x as 1, y as 2, and a as an array containing ["hello", true, 7]. So, array a has length 3.
Your result of the function is (1 + 2) * 3, which is 9.
So, your comparison of function result to 9, is true.

Related

How to select the middle of an array?

I thought I could use
$ [1,2,3,4,5].splice((this.length / 2), 1)[0]
but it gives me
$ 1
I tried
$ [1,2,3,4,5].splice(function() { return this[this.length / 2, 1]})
but it gives me
[ 1, 2, 3, 4, 5 ]
I'm looking for a solution that gives me an integer and for even arrays is the lower of the two, e.g.
[1,2,3,4] givees 2
[1,2,3,4,5] gives 3
[1,2,3,4,5,6] gives 3
[1,2,3,4,5,6,7] gives 4
The issue is with this reference. Try this:
console.log(getMiddle([1,2,3,4]));
console.log(getMiddle([1,2,3,4,5]));
console.log(getMiddle([1,2,3,4,5,6]));
console.log(getMiddle([1,2,3,4,5,6,7]));
function getMiddle(arr){
return arr.splice(Math.floor((arr.length-1) / 2), 1)[0]
}
However, As #jonrsharpe 's comment states, splicing a single-element array from an index to the same index plus one then getting the first value in the result creates a redundant array. A better way to get the middle element would be the following:
console.log(getMiddle([1,2,3,4]));
console.log(getMiddle([1,2,3,4,5]));
console.log(getMiddle([1,2,3,4,5,6]));
console.log(getMiddle([1,2,3,4,5,6,7]));
function getMiddle(arr){
return arr[Math.floor((arr.length - 1) / 2)];
}
You should use something like that.
var data, remaining, hold, result;
data = ["1","2","3","4","5","6","7","8", "9"];
remaining = data.length % 2;
hold = Math.floor(data.length / 2);
result = data[(remaining + hold - 1)];
document.write(result);
You could create a prototype for getting the middle element/s.
Array.prototype.middle = function () {
const
half = this.length >> 1,
offset = 1 - this.length % 2;
return this.slice(half - offset, half + 1);
};
console.log([1, 2, 3, 4, 5].middle()); // [3]
console.log([1, 2, 3, 4, 5, 6].middle()); // [3, 4]
console.log([1, 2, 3, 4].middle()); // [2, 3]
.as-console-wrapper { max-height: 100% !important; top: 0; }
You cannot use this as a parameter because this is supposed to be called inside functions, whereas splice accept as parameters integers. If you really want to use this you may use a prototype. Use Math.floor function since arrays indexes only accept integers, and Math.floor rounds up to the lowest integer (ex: Math.floor(2.5) === 2).
Array.prototype.getMiddle = function () {
return this[Math.floor(this.length/2)]
}
console.log([1,2,3,4,5].getMiddle()) // 3
The above function only works when the length of the array is an odd number, since arrays whose length is an even number do not have "middle" element.
If you want to check if the array has a middle
Array.prototype.getMiddle = function () {
return (this.length % 2) ? this[Math.floor(this.length/2)] : null
}
console.log([1,2,3,4,5].getMiddle()) // 3
console.log([1,2,4,5].getMiddle()) // null
Alternative solutions:
var arr = [1,2,3,4,5]
var middleEl = arr[Math.floor(arr.length/2)]
console.log(middleEl) // 3
If you want to use splice
var arr = [1,2,3,4,5]
var middleEl = arr.splice((arr.length / 2), 1)[0]
console.log(middleEl)
If you want a function
console.log(middleEl([1,2,3,4,5])) //3
console.log(middleEl([1,2,4,5])) //null
function middleEl (arr) {
return (arr.length % 2) ? arr[Math.floor(arr.length/2)] : null
}
let arr = [ 1, 2, 3, 4, 5 ]
let len = arr.length;
let mid = Math.floor(len / 2);
console.log(arr[mid]);
// or
console.log(arr.slice(mid, mid + 1));
or if you want the middle two, you can do mid + 2 using a var that tests to see if the length is even.
Why not simply, assuming a.length > 0:
const a = [1, 2, 3, 4, 5]
console.log(a[(a.length - 1) >> 1])
const b = [1, 2, 3, 4, 5, 6]
console.log(b[(b.length - 1) >> 1])
I think this should be a fairly fast way of doing it. The >> operator is an integer shift, which divides the number by two - ignoring decimals.

Currying a flipped function using lodash - Are there limitations?

I'm new to lodash and just playing around with it to become familiar.
I'm trying to curry a flipped function and I'm getting a TypeError.
Currying the same 'unflipped' function works as expected.
const curriedMap = _.curry(_.map);
const squares1 = curriedMap([ 1, 2, 3, 4 ]);
console.log(squares1(x => x * x)); // [ 1, 4, 9, 16 ]
const flippedMap = _.flip(_.map);
console.log(flippedMap(x => x * x, [1, 2, 3, 4])); // [ 1, 4, 9, 16 ]
const curriedFlippedMap = _.curry(flippedMap);
const makeSquares = curriedFlippedMap(x => x * x);
console.log(makeSquares([1, 2, 3, 4])); // TypeError: makeSquares is not a function
I'm expecting the last line to produce [ 1, 4, 9, 16 ], but instead I get 'TypeError'. What am I doing wrong?
_.map has a length property (number of parameters) that _.curry can use to curry it automatically, but _.flip(_.map) can’t easily produce a new function with the same length as its input (it reverses the entire argument list, it’s not just f => (a, b) => f(b, a)).
> _.map.length
2
> _.flip(_.map).length
0
_.curry lets you specify the number of parameters to work around that:
const curriedFlippedMap = _.curry(flippedMap, 2);

Default value for object argument

I want to create a function with an object as parameter
The object can have for exemple three keys : x, y, z
All this keys must have default value assignment
I tried this :
function f({x:x, y:y, z: z} = {x:1,y:2,z:3}) {
return x + y + z;
}
But I have a problem
f() // return 6 => OK!
f({x: 2, y: 3, z: 4}) // return 9 => OK!
f({x: 2, y:3}) // return NaN (because z === undefined), I expect 8
How can I do this?
You can assign individual defaults when destructuring objects:
function f({ x = 1, y = 2, z = 3 } = {}) {
return x + y + z
}
console.log(f())
console.log(f({ x: 2, y: 3, z: 4 }))
console.log(f({ x: 2, y:3 }))
See the docs here, which describes array destructuring, but the same applies to objects.
What does destructuring mean? It’s a JavaScript expression that allows us to extract data from arrays, objects, maps and sets into their own variable. It allows us to extract properties from an object or items from an array, multiple at a time.
Short form: The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.
Please have a look at this simple code example:
function yourFunction({
x = 1,
y = 2,
z = 3
} = {}) {
return x + y + z
}
out.innerHTML+="<br>" + yourFunction()
out.innerHTML+="<br>" + yourFunction({ x: 3, y: 3, z: 4 })
out.innerHTML+="<br>" + yourFunction({ x: 7, y: 1})
<p id="out">Results: </p>
Have a look at the docs: click

Why in this example in "applyAll" function , parameter after argument setted 1, not 0 ?

function sum() {
return [].reduce.call(arguments, function(a, b) {
return a + b;
});
}
function mul() {
return [].reduce.call(arguments, function(a, b) {
return a * b;
});
}
why there is a second parameter is 1? If we want shift all array or argumentsm, it`s like we need to to set start parameter 1 , not 0. Cause if we used 1 , we will lost argument with key 0.
function applyAll(func) {
return func.apply(this, [].slice.call(arguments, 1));
}
console.log( applyAll(sum, 1, 2, 3) ); // 6
console.log( applyAll(mul, 2, 3, 4) ); // 24
console.log( applyAll(Math.max, 2, -2, 3) ); // 3
console.log( applyAll(Math.min, 2, -2, 3) ); // -2
This is how used [].slice.call(context, arg).
var obj= [1,2,3];
console.log([].slice.call(obj,0));
(function() {
return [].slice.call(arguments,0)
}(1,2,3))
The first argument to .call() is the context (as in, what this will be inside the function). Second argument and over are the arguments sent into the function.
For the function applyAll, the first argument is always func.
So in your code example applyAll(sum, 1, 2, 3), the arguments is [sum, 1, 2, 3]. What you are supposed to do is passing 1, 2, 3 as arguments to sum. That is why you need to get a sub array from index = 1 from the original arguments which is [sum, 1, 2, 3].
Answer to your comments:
I thought you should have the clue:
[sum, 1, 2, 3].slice(1) = [1, 2, 3]
see? You should pass 1 to slice. That is the answer. Don't confuse the context with the arguments pseudo-array itself.

JavaScript's bind() with currying. How does these code work?

These code was posted on CodeReview two days ago:
function curry(f, self) {
return function () {
if (arguments.length == f.length) {
return f.apply(self, arguments);
}
arguments = Array.prototype.slice.call(arguments);
return curry(f.bind.apply(f, [self].concat(arguments)));
}
}
function f(a, b, c, d) {
return this + a + b + c + d;
}
document.write("f(1, 2, 3, 4) = ", curry(f, 0)(1, 2, 3, 4), "<br>");
document.write("f(1, 2, 3)(4) = ", curry(f, 0)(1, 2, 3)(4), "<br>");
document.write("f(1)(2, 3, 4) = ", curry(f, 0)(1)(2, 3, 4), "<br>");
document.write("f(1)(2)(3)(4) = ", curry(f, 0)(1)(2)(3)(4), "<br>");
What I'm not able to understand is:
There is made a new copy of f by using bind(). The parameter already provided are assigned to the copy but what is with the variable "self"?
I've tried to "sketch" what I mean:
// Second parenthesis (marked with =>): There are three of four
// expected parameter provided:
document.write("f(1, 2, 3)(4) = ", curry(f, 0) => (1, 2, 3) <= (4), "<br>");
// Makes an array-literal with "self" (== 0) as only element in it.
// Then adds the parameter already provided to these array by
// using concat(). => Results in an array [ 0, 1, 2, 3 ].
// Then makes a new copy of f with these values bind to it as parameter.
// These new instance of the function is then passed to the curry-function.
return curry(f.bind.apply(f, [self].concat(arguments)));
The copy of f should have it's four parameter. It should be executed and resulting "return 0 + 0 + 1 + 2 + 3;" and return 6.
Why isn't that the case?
Perhaps someone can answer that. I would appreciate it.
What is with the variable "self"? It is used to overwrite the this-keyword AND it has been added to the array given to the function.
No, it's not:
f.bind.apply(f, [self].concat(arguments))
≡ f.bind.apply(f, [self].concat([1, 2, 3]))
≡ f.bind.apply(f, [0, 1, 2, 3])
≡ f.bind(0, 1, 2, 3)
self/0 is bound as the this argument, 1, 2 and 3 are bound as three partially applied parameters. Nothing is duplicated here. The result is a function
function bound_f(x, ...args)
return f.call(0, 1, 2, 3, x, ...args);
}
that is then again curried and can be invoked with 4 as the argument.

Categories