What's the correct way to pass a function as a parameter in liveScript?
For instance, lets say I Want to use the array reduce function, in convectional javascript I would write it as the following
myArray.reduce(function (a,b) {return a + b});
This translates to liveScript quite nicely as:
myArray.reduce (a,b) -> a + b
Now, I want to set the initial value by providing a second parameter:
myArray.reduce(function (a,b) {return a + b},5);
How would I translate this to liveScript? It seems that the first function overrides any ability to pass additional parameters to reduce.
Apologies if I have missed something obvious, but I can't seem to find anything pertaining to this scenario in the docs
For more complex functions I'd recommend you to use this style
[1, 2, 3].reduce do
(a, b) ->
# your code here
0
You can use ~ to bind the this argument, then call flip on it to swap the first and second parameters:
flip [1, 2, 3]~reduce, 0, (a, b) -> a + b
This may be more readable if the callback body is very long.
You have to wrap the closure in ()
[1,2,3].reduce ((a,b) -> a + b), 0
Compiles to
[1, 2, 3].reduce(function(a, b){
return a + b;
}, 0);
Just to complement the other answer, LiveScript offers binops, just put parentheses around the operator.
[1 2 3].reduce (+), 0
Related
I know how call and apply methods works, but coming to this question, it's some what tricky for me to understand the flow. Can someone help me to understand this.
console.log.call.call.call.call.call.apply(a => a, [1, 2]);
First off, note that in JavaScript, functions are objects, and can have their own properties (which you can access with the . notation just like any other object). Of the properties that exist on all functions are .apply and .call, which are themselves functions.
Second, both .call and .apply provide a mechanism to invoke a function with a specified this value. To understand that, this normally refers to whatever is on the left-hand side of the . when you call a function as a method of an object, e.g. when you call foo.bar(1, 2, 3), within the context of bar, this will refer to foo. So it's also possible to use bar.call(foo, 1, 2, 3) or bar.apply(foo, [1, 2, 3]) to achieve a similar effect; in both cases the first argument becomes this.
So basically, the console.log and all the .call's except the last one don't actually matter. The initial part of the code is just trying to apply .call on some function, and could just as easily be replaced with Function.prototype.call.apply
Skipping ahead a bit, a => a is an arrow function, short-hand for function(a) { return a; }. It creates an anonymous function that accepts one argument and returns that same argument as result. Note that this function doesn't actually refer to this so all the previous calls to .call and .apply are pretty much irrelevant.
Last [1, 2] is just an array literal containing two items, 1 and 2 which be unrolled as arguments by .apply.
So breaking it down:
console.log.call.call.call.call.call.apply(a => a, [1, 2]);
Can be reduced to:
Function.prototype.call.apply(a => a, [1, 2]);
Can be reduced to:
var fn = a => a;
fn.call(1, 2);
.call will use its first argument as the this value of the function and pass subsequent values as parameters, and since fn doesn't use this, we can further reduce it to:
var fn = a => a;
fn(2);
Since fn is just a simple identity function, the result is just:
2;
It doesn't do anything, apply will return 1 and 2 as separate values which call won't do anything with since it's not a function. Even if you were to do console.log.call.call(a => a, [1,2]) you wouldn't get anything since the first call returns just the array [1,2] which isn't a function the second call can do anything with...
console.log.call.call./*and so on*/call./*returns nothing eval({1, 2}) =
undefined*/call./*returns {1, 2} up the chain*/apply(a => a, [1,2]);
//You can try this which also won't return anything:
console.log.call([1,2]);
Although oddly enough I was expecting this sort of code to throw an error, which it didn't, it just didn't log or throw an error. So it really doesn't return anything...
I just saw a code snippet in MDN about destructuring rest parameters like so:
function f(...[a, b, c]) {
return a + b + c;
}
f(1) // NaN (b and c are undefined)
f(1, 2, 3) // 6
f(1, 2, 3, 4) // 6 (the fourth parameter is not destructured)
the code snippet is in this page: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters
Although the common use case for rest parameters is very clear to me (function foo(...params){/*code*/}) I could not think about a real world use case to use rest parameters like the way presented in that code snippet. Instead, I think that in that case, I should just use a common function definition:
function f(a, b, c) {
return a + b + c;
}
f(1) // NaN (b and c are undefined)
f(1, 2, 3) // 6
f(1, 2, 3, 4) // 6 (the fourth parameter is not defined)
Your function f(a, b, c) { … } is indeed the proper way to write this. The only difference between that and the rest+destructuring syntax is that rest parameters do not add to number of parameters, i.e. f.length == 0.
There really is no good use case for putting an array destructuring pattern as the target of a rest parameter. Just because the syntax allows it doesn't mean that it's useful somewhere. The MDN example probably should've made that more clear.
The example illustrates that rest and destructuring syntaxes are flexible enough to be combined even in such a way.
It is known that neither TypeScript nor Babel stable versions currently support this syntax, primarily because it's of no practical use.
let's say that we have a function that returns an object such like that:
function getCustomer(id) {
return fetch(`http://myapi.com/customer/${id}`);
}
and let's say I have a response like that:
{
"customer": {
"id": 1234,
"name": "John Doe",
"latestBadges": [
"Platinum Customer",
"100 Buys",
"Reviewer"
]
}
}
In a more traditional approach I could write a function to show the latest 3 badges like so:
function showLatestBadges(a, b, c) {
console.log(a, b, c);
}
and to use that function, I would need to to:
getCustomer(1234).then((customer) => {
showLatestBadges(
customer.latestBadges[0],
customer.latestBadges[1],
customer.latestBadges[2]
);
});
With this new spread operator, I could do this instead:
getCustomer(1234).then((customer) => {
showLatestBadges(...customer.latestBadges);
});
So, using the spread operator in the function definition may look like it's a little useless. But, in fact, it CAN be useful in a VERY specific situation:
Let's say we have a legacy system, and let's say that the call to the showLatestBadges function is being made in hundreds of places without using the spread operator, just like the old days. Let's also assume that we are using a linting tool that prevents unused variables, and let's also assume that we are running a build process that do cares about the linting results, and if the linting says that something is not right, the build fails.
Let's ALSO ASSUME that for some weird business rule, we now have to show only the first and third badges.
Now, assuming this function call being made in hundreds of places in the legacy system, and we do not have much time available to deliver the implementation of this new business rule, we do not have time to refactor the code for ALL those hundreds of calls.
So, we will now change the function as so:
function showLatestBadges(a, b, c) {
console.log(a, c);
}
But now we have a problem: the build fails because of the unused b variable, and we have to deliver this change for YESTERDAY!!! We have no time to refactor all the hundreds of calls to this function, and we cannot just do a simple find and replace in all the spots, because we have such a messy code, and there are evals all over the place, and unpredictable behavior can happen.
So, one solution is: change the function signature using the spread operator, so the build succeeds, and create a task on the board to do the refactoring.
So, we can change the function as so:
function showLatestBadges(...[a,,c]) {
console.log(a, c);
}
Ok, I know this is a VERY specific situation and that this is very unlike to happen, but, who knows? ¯\_(ツ)_/¯
Actually the ... operator is two ways. It's both called rest and spread depending on your use case. They are both very powerful operators especially for functional approaches. You may always use spread operator as,
var a = [1,2,3],
b = [4,5,6];
a.push(...b);
which would yield a to be [1,2,3,4,5,6] all at once. At this moment one could say that .concat() could do the same. Yes concat has a built in spread functionality but a.concat(b) wouldn't effect a. I just creates and returns a new array. In fact in proper functional languages treating a as an immutable object is nice for the sake of purity. Yet JS is a weird language. It's believed to be functional but at the same time deeply embraces reference types. So long story short if you want to keep the references to a intact while mutating it then you can not use a.concat(b) but a.push(...b). Here i have to mention that .push() is not perfectly designed because it returns a stupid length property which is totally useless. It should have returned a. So I end up using the comma operator like (a.push(...b),a) most of the times.
OK apart from simple use cases you may stretch ... further for a little more complicated but cool looking implementations. Such as you may do an Haskellesque pattern matching to split head and tail of an array and recurse accordingly.
Here is a useful case of spread and rest operators working hand to hand to flatten an arbitrary nested array.
var flat = (x,...xs) => x ? [...Array.isArray(x) ? flat(...x) : [x], ...flat(...xs)] : [];
var na = [[1,2],[3,[4,5]],[6,7,[[[8],9]]],10];
fa = flat(na);
console.log(fa);
This is one of the use-cases I got to use this
const tail = function([, ...xs]) {
return xs;
}
tail([1,2]); // [2]
const head = ([a]) => a
head([1,2,3,4]) // 1
The task (actually the problem) I'm facing is the following. I have an array (let’s call it arr). The first element of the array is a function and the rest are arguments. For example:
arr = [(a, b) => a + b, 5, 7];
So, I need to call function (a, b) => a + b with arguments 5 and 7. However, I don't want to use arr[0](...arr.slice(1)), instead I want to do it using Function.prototype.apply and Function.prototype.call (I can also use Function.prototype.bind if needed). So basically, I am allowed to access arr only once and no other variables may be used. Also, I'm not allowed to modify arr or it's properties, or to store any other data somewhere (like as property of some global object, etc). Is that even possible?
My attempt
I tried to figure it out, and this is what I came up with (it doesn't work):
Function.prototype.apply.call(this, ...arr);
However, it throws an error saying:
Uncaught TypeError: Function.prototype.apply was called on #Global, which is an object and not a function
Question
What is the correct way to do this?
instead I want to do it using Function.prototype.apply and Function.prototype.call. Is that even possible?
Sure, but we have to repeat arr:
arr[0].call(...arr)
Live Example:
const arr = [(a, b) => a + b, 5, 7];
console.log(arr[0].call(...arr));
That wouldn't work if the function required a specific this, but your function doesn't, for two reasons, either of which would be sufficient: 1. It's an arrow function, so it doesn't care what this we call it with, it closes over the one where it was created; and 2. It doesn't use this anyway.
That said, probably better just to give yourself a helper function that does it instead.
You can use destructuring to get the elements of arr array as variables, then call the function at index 0 with elements at indexes 1-N
let arr = [(a, b) => a + b, 5, 7];
let [fn, a, b] = arr;
console.log(fn(a, b));
For any number of elements at indexes 1-N you can use rest element
let arr = [(a, b) => a + b, 5, 7];
let [fn, ...rest] = arr;
console.log(fn.apply(null, rest));
Alternatively, using Function, template literal to convert array to string, .replace() with RegExp /\s/g with .replace() to remove space characters, .match() with RegExp /(\(.*\)=>[^,]+(?=,))|[^,]{1}[^\1]+/g to capture arrow function, negate first comma of characters that are not arrow function and arrow function captured at first group, we can reference arr once and not create additional variables save for immediately invoked arrow function parameters
let arr = [(a, b) => a + b, 5, 7];
console.log(
(([a, b]) => new Function(`return (${a})(${b.split(/,/)})`)())
(`${arr}`.replace(/\s/g, "").match(/(\(.*\)=>[^,]+(?=,))|[^,]{1}[^\1]+/g))
)
I stumbled upon this relatively simple arrow function:
var x = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
console.log(x());
I know what it does in general. But why does it this thing so complicated? I mean, the same thing can be done much easier and has (imo) a better readability too:
var x = ([a, b] = [1, 2], c = a + b) => a + b + c;
console.log(x());
So could someone tell me the difference of this two notations or show me a better usecase for the first one?
The 2nd argument of your 2nd is example is a simple es6 default initialization, while the 2nd argument of your 1st example is again a simple es6 default initialization with destructuring.
But, I assume you already know that.
Your other part of the question was, show me a better usecase for the first one?
Destructuring is mainly useful when you want to access a key from a huge javascipt object;
Something like this:
aHugeJavascriptObject = {
key1:'value1',
.
.
.
key999:'value999'
}
Now, one way to access the object's key key999 is aHugeJavascriptObject.key999, instead you probably want to do
const { key999 } = aHugeJavascriptObject
I also assume that you already also know that.
But, I am afraid that is what that is there to your question.
The first notation takes an object with a property x as the second argument. It is destructured and x is extracted as c. If it is not defined, a default object with a property x is used instead:
console.log(x([1, 2], {x: 5}));
Whereas the second one takes a simple argument primitive argument (probably a Number in this case):
console.log(x([1, 2], 5));
The only difference thus is the second argument that is fed into the function.
In short, this works:
[1, 2, 3].reduce(function (a, b) { return Math.max(a, b); });
=> 3
But this doesn't:
[1, 2, 3].reduce(Math.max);
=> NaN
Pure puzzlement.
This is in Firefox 3.5.9, which I presume is using the mozilla standard implementation of reduce, FWIW.
Math.max can be used as a higher-order function. The problem is .reduce will call the function with 4 arguments:
Math.max(accumulator, value, index, the_array)
here is the_array is an array, so Math.max returns NaN. I don't think there's simpler way to discard the last 2 arguments.
Math.max.apply(Math, [1, 2, 3]);
//3
Not exactly a higher order use, but this also works:
Math.max(...myArray);