What's a better way to swap two argument values? - javascript

So given a function
function foo( a, b ) {
}
Now, if I wanted to swap the values of the arguments a and b, I could write this:
var t = a;
a = b;
b = t;
However, this is an ugly pattern - it requires three statements (three lines of code), plus a local variable. Now, I could bear three statements, but having to declare that annoying helper variable? I would like to avoid that.
So, what would be a better way to do this? (Better as in fewer lines of code (possibly one-liner), or not declaring a local variable.)
I came up with this:
(function ( t ) { a = b; b = t; })( a ); // swap a and b
Live demo: http://jsfiddle.net/J9T22/
So, what can you come up with?

Using a function for it? Seriously?
The easiest is often the best:
var t = a;
a = b;
b = t;
If you use it e.g. for server-side JS (i.e. you only need to support one JavaScript engine) you might also be able to use the destructuring assignment syntax:
[a, b] = [b, a]

This is a fun little exercise.
You could do this: a=[b][b=a,0]
var a='a';
var b='b';
a=[b][b=a,0];
alert(a + ', ' + b); // "b, a"
Also +1 from me, ignore the haters ;)
...Oh wait! Is this not a fun little exercise, but actually for real-world use? Then you'd better not do it this way, because it's less readable than var t=a;a=b;b=t!
a=[b][b=a,0]; // wth?
var t=a; a=b; b=t; // ahhh so readable!
But no, seriously, doing it this way actually gives you neat benefits over having to create another variable, because you can do it in line. Var declarations can't usually be part of normal statements, so attempting to do something like (var t=a; a=b; b=t) will just throw a SyntaxError, but (a=[b][b=a,0]) evaluates to a, which could be useful.
It's interesting to discuss things like this because, while doing things in unconventional ways may not be welcome in our production code, it is a great way to learn about the language. And that (I think) is what SO is all about. I rest my case.

In Mozilla's Javascript 1.7 you could do [a, b] = [b, a].

If you're allowing for Mozilla only, or future ES6 stuff, you can use destructuring assignment:
[a,b] = [b,a]
If the biggest concern is variable environment pollution, you could borrow the arguments object.
arguments[arguments.length] = a;
a = b;
b = arguments[arguments.length];
But this gets a bit long.
Or you could assign an object to an existing parameter:
a = {a:a,b:b};
b = a.a;
a = a.b;
function foo( a, b ) {
a = {a:a,b:b};
b = a.a;
a = a.b;
console.log(a,b); 'baz' 'bar'
}
foo('bar','baz');
Or eliminate a like like this:
a = {b:b,a:(b=a)};
a = a.b;
Or down to one line:
a = {b:b,a:(b=a)}.b;
Currently in "strict mode" supported implementations, you can do this (if you're actually running in "strict mode"):
a = b; b = arguments[0];
This is because changes to formal parameters has no effect on the arguments object, and vice versa.

I've read that you should never do this but...
a=5;
b = 7
//add parenthesis to make this do what it should in one line
a ^= b;
b ^= a;
a ^= b;
They should now have each other's values.
[edit] as per pointedears' description this doesn't work as stated, but here's the description of how it DOES work... however, as already stated (by others) stick to what's simplest. there's no reason to do this, you will NOT notice any performance gains, and your code will simply become less readable.
http://en.wikipedia.org/wiki/XOR_swap_algorithm
and here it is in action...
http://jsfiddle.net/nHdwH/

What's a better way to swap two argument values?
There is no "better" way, only a number of progressively more obscure and confusing ways.
Some people might view those other methods as "clever", and I guess some of them are, but I wouldn't want to work with anybody who thinks they're actually "better" because I would not want to see such methods cropping up in real project code.
The "clever" maths methods only work if you assume integer values, so in my opinion they're wrong since you didn't specify types.
If you find the three statements ugly you could do this:
var t;
t = a, a = b, b = t;
Yes it's virtually the same thing, but at least it puts the swap code all on the same line.
(Having said all that, I think [a, b] = [b, a]; would be "better" if not for the lack of browser support for it.)

If the values are integers, then you can use arithmetic to do the work:
function foo( a, b ) {
a = -(b = (a += b) - b) + a;
console.log(a);
console.log(b);
}
foo(1,2);
See http://www.greywyvern.com/?post=265

a=[a,b];
b=a[0];
a=a[1];
this uses only the variables a and b, but it creates an array,
which is more significant than a temporary variable.
Use the temporary variable.
var t=a;
a=b;
b=t;
Another upvote for sanity.

I slightly disagree with other people, it can be useful. However, defining it inline is bad, bad, bad, bad, bad. If you are going to do it, it should be a higher order function:
function flip(fn) {
return function(a, b) {
return fn.call(null, b, a);
};
}
For example:
function log() {
console.log.apply(console, arguments);
}
flip(log)(1, 2); // 2 1
Now this might seem silly, but this kind of stuff happens quite often when you're mapping/reducing/iterating etc. Say you have some function:
function doSomeStuff(index, value) {
// complex stuff happening here
}
And an array:
var arr = ["foo", "bar", "etc"];
If you were to use, for example, map on this array and needed to call doSomeStuff you'd have to hand roll this function:
arr.map(function(value, index) {
return doSomeStuff(index, value);
});
Whilst you could say this isn't bad, it is distracting from what you're trying to do (just call the damn function!). With this higher order function it can be reduced to:
arr.map(flip(doSomeStuff));
If you wanted a more complete flip function you could:
function flip(fn) {
return function() {
var args = Array.prototype.slice.call(arguments);
return fn.apply(null, args.reverse());
};
}
And now:
flip(log)(1,2,3,4,5); // 5 4 3 2 1

I assume in the real world one would want this swap to be conditional.
[a,b] = c? [a,b] : [b,a]
You could also replace all instances of a with [a,b][+c] and all b's with [b,a][+c] like:
arr.sort( (a,b) => [a,b][+c] - [b,a][+c] )
or just have a function to call the function:
swapMyFunction = (a,b) => myFunction(b,a)

Related

Is this JavaScript function, taking a mutable reference argument, a pure function?

I have the same question as this one, but in the context of JavaScript.
From Wikipedia:
[a pure function's] return value is the same for the same arguments
It's further claimed there that a pure function is not allowed to have a variation in return value with "mutable reference arguments". In JavaScript, every normal object is passed as a "mutable reference argument". Consider the following example:
const f = (arr) => arr.length
const x = []
console.log( f(x) ) // 0
x.push(1);
console.log( f(x) ) // 1
Is the above proof that f is impure?
Or would you argue that we're not calling f with the "same" argument in the two cases?
I can see how it would make sense to call f impure in a language/environment where other threads could potentially mess with the mutable reference argument while f is executing. But since f is not async, there is no way for this to happen. x is going to stay the same from the moment f is called to when it's done executing. (If I'm understanding correctly, this interpretation seems to be supported by the definition of "same" put forth in § 4.1 of Verifiable Functional Purity in Java.)
Or am I missing something? Is there an example in JavaScript where a function containing no asynchronous code loses the property of referential transparency simply because it's taking a mutable reference, but it would be pure if we used e.g. an Immutable.js data structure instead?
When taking the Wikipedia definition to the letter, a function that takes as argument a reference to a mutable data structure (such as a native Array) is not pure:
Its return value is the same for the same arguments (no variation with local static variables, non-local variables, mutable reference arguments or input streams from I/O devices).
Equivalence
Although this clearly says "no variation with mutable reference arguments", we could maybe say this is open to interpretation and depends on the meaning of "same" and "variation". There are different definitions possible, and so we enter the area of opinion. Quoted from the paper your referred to:
There is not a single obviously right answer to these questions. Determinism is thus a parameterized property: given a definition of what it means for arguments to be equivalent, a method is deterministic if all calls with equivalent arguments return results that are indistinguishable from within the language
The functional purity proposed in the same paper, uses the following definition of equivalence:
Two sets of object references are considered equivalent if they result in identical object graphs
So with that definition, the following two arrays are considered equivalent:
let a = [1];
let b = [1];
But this concept can not really be applied to JavaScript without adding more restrictions. Nor to Java, which is the reason why the authors of the paper refer to a trimmed-down language, called Joe-E:
objects have identity: conceptually, they have an “address”, and we can compare whether two object references point to the same “address” using the == operator. This notion of object identity can expose nondeterminism.
Illustrated in JavaScript:
const compare = (array1, array2) => array1 === array2;
let arr = [1];
let a = compare(arr, arr);
let b = compare(arr, [1]);
console.log(a === b); // false
As the two calls return a different result, even though the arguments had the same shape and content, we should conclude (with this definition of equivalence) that the above function compare is not pure. While in Java you can influence the behaviour of the == operator (Joe-E forbids calling Object.hashCode), and so avoid this from happening, this is not generally possible in JavaScript when comparing objects.
Unintended side effects
Another issue is that JavaScript is not strongly typed, and so a function cannot be certain that the arguments it receives are what they are intended to be. For instance, the following function looks pure:
const add = (a, b) => a + b;
But it can be called in way to give side effects:
const add = (a, b) => a + b;
let i = 0;
let obj = { valueOf() { return i++ } };
let a = add(1, obj);
let b = add(1, obj);
console.log(a === b); // false
The same problem exists with the function in your question:
const f = (arr) => arr.length;
const x = { get length() { return Math.random() } };
let a = f(x);
let b = f(x);
console.log(a === b) // false
In both cases the function unintentionally called an impure function and returned a result that depended on it. While in the first example it is easy to still make the function pure with a typeof check, this is less trivial for your function. We can think of instanceof or Array.isArray, or even some smart deepCompare function, but still, callers can set a strange object's prototype, set its constructor property, replace primitive properties with getters, wrap the object in a proxy, ...etc, etc, and so fool even the smartest equality checkers.
Pragmatism
As in JavaScript there are just too many "loose ends", one has to be pragmatic in order to have a useful definition of "pure", as otherwise almost nothing can be labelled pure.
For example, in practice many will call a function like Array#slice pure, even though it suffers from the problems mentioned above (including related to the special argument this).
Conclusion
In JavaScript, when calling a function pure, you will often have to agree on a contract on how the function should be called. The arguments should be of a certain type, and not have (hidden) methods that could be called but that are impure.
One may argue that this goes against the idea behind "pure", which should only be determined by the function definition itself, not the way it eventually might get called.

javascript es6: use case for destructuring rest parameter

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

Why to use this javascript arrow function or what is the difference?

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.

ES6 Arrow Notation with Loops

Consider the following bit of code:
f=(m,c)=>{m?c()&f(--m,c):0}
(thanks to zzzzBov for this little nugget)
which is a "for"-less loop
and the following:
a=b=>b+1
Given these two snippets, and the fact that:
z = 0; f(10,a(z));
which I would expect would result in z equating to 10, but instead returns in the JavaScript console the following "TypeError: c is not a function", how would one go about altering this code to ensure that the loop goes ahead, without having to resort to a while or for loop?
I'm asking this as a matter of education purposes... Hopefully I can get some insight into what can be done...
The function f is taking 2 arguments: m, the number to iterate, and c, the function to be called m times. This means that the second argument, c should be a function. For example:
f=(m,c)=>{m?c()&f(--m,c):0}
f(15, function() {
console.log("Hello")
})
This will iterate through the c function 15 times, calling console.log 15 times.
Of course, to achieve what you wanted in the second bit, you could use this:
z=0, f(10,()=>z++)
This would be a regular arrow function to increase z by 1
Take a look at the code on babel
Hope I could help!
It sounds you are looking for a folding function (like array reduce), not a simple "looping" function that only executes side effects. With that current function, which desugars f(5, c) to effectively c(); c(); c(); c(); c(); you would need to do
let z = 0;
f(10,()=>{ z = a(z) });
If however you want to make a function that repeatedly applies a function, like a(a(a(a(a(…))))), you would need to write
let times = (n, f, s) => n>0 ? times(n-1, f, f(s)) : s;
so that you can do
let a = b=>b+2
times(5, a, 0) // 10

When is the comma operator useful?

I read this question about the "comma operator" in expressions (,) and the MDN docs about it, but I can't think of a scenario where it is useful.
So, when is the comma operator useful?
The following is probably not very useful as you don't write it yourself, but a minifier can shrink code using the comma operator. For example:
if(x){foo();return bar()}else{return 1}
would become:
return x?(foo(),bar()):1
The ? : operator can be used now, since the comma operator (to a certain extent) allows for two statements to be written as one statement.
This is useful in that it allows for some neat compression (39 -> 24 bytes here).
I'd like to stress the fact that the comma in var a, b is not the comma operator because it doesn't exist within an expression. The comma has a special meaning in var statements. a, b in an expression would be referring to the two variables and evaluate to b, which is not the case for var a, b.
The comma operator allows you to put multiple expressions in a place where one expression is expected. The resulting value of multiple expressions separate by a comma will be the value of the last comma separated expression.
I don't personally use it very often because there aren't that many situations where more than one expression is expected and there isn't a less confusing way to write the code than using the comma operator. One interesting possibility is at the end of a for loop when you want more than one variable to be incremented:
// j is initialized to some other value
// as the for loop executes both i and j are incremented
// because the comma operator allows two statements to be put in place of one
for (var i = 0; i < items.len; i++, j++) {
// loop code here that operates on items[i]
// and sometimes uses j to access a different array
}
Here you see that i++, j++ can be put in a place where one expression is allowed. In this particular case, the multiple expressions are used for side affects so it does not matter that the compound expressions takes on the value of the last one, but there are other cases where that might actually matter.
The Comma Operator is frequently useful when writing functional code in Javascript.
Consider this code I wrote for a SPA a while back which had something like the following
const actions = _.chain(options)
.pairs() // 1
.filter(selectActions) // 2
.map(createActionPromise) // 3
.reduce((state, pair) => (state[pair[0]] = pair[1], state), {}) // 4
.value();
This was a fairly complex, but real-world scenario. Bear with me while I explain what is happening, and in the process make the case for the Comma Operator.
This uses Underscore's chaining to
Take apart all of the options passed to this function using pairs
which will turn { a: 1, b: 2} into [['a', 1], ['b', 2]]
This array of property pairs is filtered by which ones are deemed to be 'actions' in the system.
Then the second index in the array is replaced with a function that returns a promise representing that action (using map)
Finally the call to reduce will merge each "property array" (['a', 1]) back into a final object.
The end result is a transformed version of the options argument, which contains only the appropriate keys and whose values are consumable by the calling function.
Looking at just
.reduce((state, pair) => (state[pair[0]] = pair[1], state), {})
You can see the reduce function starts with an empty state object, state, and for each pair representing a key and value, the function returns the same state object after adding a property to the object corresponding to the key/value pair. Because of ECMAScript 2015's arrow function syntax, the function body is an expression, and as a result, the Comma Operator allows a concise and useful "iteratee" function.
Personally I have come across numerous cases while writing Javascript in a more functional style with ECMAScript 2015 + Arrow Functions. Having said that, before encountering arrow functions (such as at the time of the writing of the question), I'd never used the comma operator in any deliberate way.
Another use for the comma operator is to hide results you don't care about in the repl or console, purely as a convenience.
For example, if you evaluate myVariable = aWholeLotOfText in the repl or console, it will print all the data you just assigned. This might be pages and pages, and if you'd prefer not to see it, you can instead evaluate myVariable = aWholeLotOfText, 'done', and the repl/console will just print 'done'.
Oriel correctly points out† that customized toString() or get() functions might even make this useful.
Comma operator is not specific to JavaScript, it is available in other languages like C and C++. As a binary operator this is useful when the first operand, which is generally an expression, has desired side effect required by second operand. One example from wikipedia:
i = a += 2, a + b;
Obviously you can write two different lines of codes, but using comma is another option and sometimes more readable.
I'd disagree with Flanagan, and say, that comma is really useful and allows to write more readable and elegant code, especially when you know what you're doing:
Here's the greatly detailed article on comma usage:
Several examples from out from there for the proof of demonstration:
function renderCurve() {
for(var a = 1, b = 10; a*b; a++, b--) {
console.log(new Array(a*b).join('*'));
}
}
A fibonacci generator:
for (
var i=2, r=[0,1];
i<15;
r.push(r[i-1] + r[i-2]), i++
);
// 0,1,1,2,3,5,8,13,21,34,55,89,144,233,377
Find first parent element, analogue of jQuery .parent() function:
function firstAncestor(el, tagName) {
while(el = el.parentNode, el && (el.tagName != tagName.toUpperCase()));
return el;
}
//element in http://ecma262-5.com/ELS5_HTML.htm
var a = $('Section_15.1.1.2');
firstAncestor(a, 'div'); //<div class="page">
I haven't found practical use of it other than that but here is one scenario in which James Padolsey nicely uses this technique for IE detection in a while loop:
var ie = (function(){
var undef,
v = 3,
div = document.createElement('div'),
all = div.getElementsByTagName('i');
while ( // <-- notice no while body here
div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
all[0]
);
return v > 4 ? v : undef;
}());
These two lines must to execute :
div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
all[0]
And inside comma operator, both are evaluated though one could have made them separate statements somehow.
There is something "odd" that can be done in JavaScript calling a function indirectly by using the comma operator.
There is a long description here:
Indirect function call in JavaScript
By using this syntax:
(function() {
"use strict";
var global = (function () { return this || (1,eval)("this"); })();
console.log('Global === window should be true: ', global === window);
var not_global = (function () { return this })();
console.log('not_global === window should be false: ', not_global === window);
}());
You can get access to the global variable because eval works differently when called directly vs called indirectly.
I've found the comma operator most useful when writing helpers like this.
const stopPropagation = event => (event.stopPropagation(), event);
const preventDefault = event => (event.preventDefault(), event);
const both = compose(stopPropagation, preventDefault);
You could replace the comma with either an || or &&, but then you'd need to know what the function returns.
More important than that, the comma separator communicates intent -- the code doesn't care what the left-operand evaluates to, whereas the alternatives may have another reason for being there. This in turn makes it easier to understand and refactor. If the function return type ever changes, the code above would not be affected.
Naturally you can achieve the same thing in other ways, but not as succinctly. If || and && found a place in common usage, so too can the comma operator.
One typical case I end up using it is during optional argument parsing. I think it makes it both more readable and more concise so that the argument parsing doesn't dominate the function body.
/**
* #param {string} [str]
* #param {object} [obj]
* #param {Date} [date]
*/
function f(str, obj, date) {
// handle optional arguments
if (typeof str !== "string") date = obj, obj = str, str = "default";
if (obj instanceof Date) date = obj, obj = {};
if (!(date instanceof Date)) date = new Date();
// ...
}
Let's say you have an array:
arr = [];
When you push onto that array, you are rarely interested in push's return value, namely the new length of the array, but rather the array itself:
arr.push('foo') // ['foo'] seems more interesting than 1
Using the comma operator, we can push onto the array, specify the array as the last operand to comma, and then use the result -- the array itself -- for a subsequent array method call, a sort of chaining:
(arr.push('bar'), arr.push('baz'), arr).sort(); // [ 'bar', 'baz', 'foo' ]
It saves you from using return in nested conditionals and it's very handy especially with the ternary operator. Such as;
function insert(v){
return this.node > v ? this.left.size < this.right.size ? ( this.left.insert(v)
, this
)
: ( this.left.insert(this.node)
, this.node = this.right.popmin()
, this.insert(v)
, this
)
: this.left.size < this.right.size ? ( this.right.insert(this.node)
, this.node = this.left.popmax()
, this.insert(v)
, this
)
: ( this.right.insert(v)
, this
)
}
I just came across this today looking at the proposals for pipeline operator proposal and partial application...
(https://github.com/tc39/proposal-pipeline-operator
(https://github.com/tc39/proposal-partial-application#hack-style-pipelines)
Also, Hack-style pipelines are already feasible without introducing new syntax today:
let $; // Hack-style topic variable
let result = (
$= books,
$= filter($, _ => _.title = "..."),
$= map($, _ => _.author),
$);
The use of comma expressions here can kind of fake the pipeline operator that isn't in the language yet.
Eliminating the space between $= simulates the feeling of a proper pipe token, |>. Note that the "topic" variable, $, can be anything here and that it's just shorthand for repeatedly overwriting the variable. So something more akin to ...
// blocking inside an IIFE
let result = (() => {
let $;
$ = books;
$ = filter($, _ => _.title = "..."),
$ = map($, _ => _.author),
return $;
})()
The "comma" version successfully cuts out some of the noise, getting you closer to what the proposal would be:
let result = books
|> filter($, _ => _.title = "..."
|> map($, _ => _.author)
Here's another example using it to compose functions:
const double = (x) => 2 * x;
const add = (x, y) => x + y;
const boundScore = (min, max, score) => Math.max(min, Math.min(max, score));
const calculateScore = ($) => (
$= double($),
$= add($, 20),
$= boundScore(0, 100, $),
(console.log($), $)
)
const score = calculateScore(28)
The comma operator (,) evaluates each of its operands (from left to right) and returns the value of the last operand. This lets you create a compound expression in which multiple expressions are evaluated, with the compound expression's final value being the value of the rightmost of its member expressions. This is commonly used to provide multiple parameters to a for loop.
let x = 1;
x = (x++, x);
console.log(x);
// expected output: 2
x = (2, 3);
console.log(x);
// expected output: 3
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator
Another area where comma operator can be used is Code Obfuscation.
Let's say a developper writes some code like this:
var foo = 'bar';
Now, she decides to obfuscate the code. The tool used may changed the code like this:
var Z0b=(45,87)>(195,3)?'bar':(54,65)>(1,0)?'':'baz';// Z0b == 'bar'
Demo: http://jsfiddle.net/uvDuE/

Categories

Resources