Продолжаем тему операторов, на этот раз вас ждет рассказ об операторе запятая.
Начнем с забавного твита:

'c' в конце — это оператор запятая. Последняя в списке значимых операторов, мало документированная, но очень полезная. Она не так распространена, но она мне очень нравится. Она проста, элегантна, и с ней лучше быть в хороших отношениях.
Оператор запятая выполняет оба операнда (слева направо) и возвращает значение второго оператора. (MDC)
Из-за приоритета операторов. Выражение JavaScript может содержать несколько различных операторов. Следующее выражение содержит три оператора (* + и ,):
Приоритет операторов определяет, в каком порядке будут выполнены операнды внутри выражения.
Полный список операторов тут. Оператор запятая имеет наименьший приоритет из всех операторов. Давайте посмотрим на примере:
Сейчас давайте посмотрим что будет если мы уберем круглые скобки:
Обрамляя выражение круглыми скобками, мы создаем группу, которая имеет наивысший приоритет.
Это гарантирует, что оператор запятая будет применен в первую очередь.
На практике, благодаря своему низкому приоритету, запятая — мощное средство. Фактически, она говорит интерпретатору: сначала посмотри, что же делают все остальные операторы вокруг меня, а потом позволь мне украсить собой результат.
Каждый оператор в цепочке обрабатывается последовательно слева направо.
Это эквивалентно:
Эти разделители на самом деле не операторы запятая. Назначение разделителя-запятая — разделение членов в списке. К примеру:
Затем, что она позволяет вам выполнить несколько выражений в том месте, где JavaScript ожидает только одно. Выражения с оператором запятая не такие распространенные, редко важные, но очень элегантные:
Точка с запятой — это разделитель объявлений, а запятая — это разделитель выражений внутри объявлений.
Оператор запятая очень близка к оператору && и ||. Все эти операторы возвращают последнее выражение, которое они выполнили. Вот в чем их различие:
LHE — левое выражение
RHE — правое выражение
LHE && RHE
1. Всегда выполняет LHE
2. если LHE — true, выполняет RHE
LHE || RHE
1. Всегда выполняет LHE
2. Если LHE — false, выполняет RHE
LHE, RHE
1. Всегда выполняет LHE
2. Всегда выполняет RHE
Вам следует выбрать запятую, если оба выражения должны быть выполнены.
Как я отмечал ранее, оператор запятая позволяет вам выполнить несколько выражений в том месте, где JavaScript ожидает только одно.
Вот альтернативная версия генератора чисел Фибоначчи, которая также использует оператор запятая:
Для другого примера рассмотрим утилиту, которая помогает продавцу выбирать купюры и монеты, составляющие сдачу покупателя:
Та же самая утилита, но с форматированием:
Следующая функция использует запятую для одновременного увеличения и уменьшения двух переменных внутри цикла. На выходе получаем кривую:
Вы можете использовать оператор запятая для создания кратких версий циклов do-while.
Эта функция ищет предка из списка элементов с именем tagName (аналог jQuery parent).
Тернарный оператор позволяет выполнять только одно выражение. Если вам необходимо выполнить несколько выражений, то вам приходится переходить на if else. Оператор запятая более читаемый в тех случаях когда он используется для комбинации коротких выражений:
Оператор запятая позволяет вам вставлять console.log в любое место без изменения кода:
@wavded опубликовал один способ применения запятой.
eval1 использует тот контекст в котором был вызван. Поэтому нет гарантий, что вызов eval в цикле даст тот же самый результат.
kangax написал, что мы можем использовать оператор запятая для косвенного вызова eval, который будет всегда вызываться в глобальном контексте2:
1. Пожалуйста без холиваров, все знают, что eval — evil
2. В стандарте ES5 написано, что любой не прямой вызов eval использует глобальный контекст,
однако не все браузеры поддерживают это правило (IE<=8)
Вы можете писать отличный код и без использования оператора запятая. Значит ли это, что я потратил ваше время? Я надеюсь, что нет. Обширный словарный запас делает писателей и ораторов более профессиональными так и доступ к широком возможностям языка может сделать из нас лучших кодеров. Чем больше методов мы знаем тем более красивый, аккуратный и читаемый код мы можем написать. Удачи с оператором запятая, поделитесь своими примерами использования!
ECMA-262 5th Edition
11.14 The comma operator
10.4.2 Entering eval code
15.1.2.1.1 Direct Call to Eval
Mozilla Developer Center
comma operator
operator precedence
Juriy Zaytsev ( kangax): global eval, what are the options
Mark Harter ( @wavded): cycling through an array using the comma operator
UPD Принял во внимание и исправил недочеты в переводе
Начнем с забавного твита:

'c' в конце — это оператор запятая. Последняя в списке значимых операторов, мало документированная, но очень полезная. Она не так распространена, но она мне очень нравится. Она проста, элегантна, и с ней лучше быть в хороших отношениях.
Что она делает?
Оператор запятая выполняет оба операнда (слева направо) и возвращает значение второго оператора. (MDC)
var a = (7, 5);
a; //5
var x, y, z
x = (y=1, z=4);
x; //4
y; //1
z; //4
Почему в вашем примере присваивания переменных окружены круглыми скобками?
Из-за приоритета операторов. Выражение JavaScript может содержать несколько различных операторов. Следующее выражение содержит три оператора (* + и ,):
return 5 * 2 + 3, 22;
Приоритет операторов определяет, в каком порядке будут выполнены операнды внутри выражения.
Полный список операторов тут. Оператор запятая имеет наименьший приоритет из всех операторов. Давайте посмотрим на примере:
//original
return 5 * 2 + 3, 22;
//apply * operator
return 10 + 3, 22;
//apply + operator
return 13, 22;
//apply , operator
return 22;
Сейчас давайте посмотрим что будет если мы уберем круглые скобки:
//original
var a = 7, 5;
//apply = operator
var a, 5; //a is now 7
//SyntaxError: missing variable name
Обрамляя выражение круглыми скобками, мы создаем группу, которая имеет наивысший приоритет.
Это гарантирует, что оператор запятая будет применен в первую очередь.
//original
var a = (7, 5);
//apply group
var a = 5;
На практике, благодаря своему низкому приоритету, запятая — мощное средство. Фактически, она говорит интерпретатору: сначала посмотри, что же делают все остальные операторы вокруг меня, а потом позволь мне украсить собой результат.
Некоторые выражения содержат несколько запятых. Как это работает?
Каждый оператор в цепочке обрабатывается последовательно слева направо.
var a = (1, 2, 3, 4);
a; //4
Это эквивалентно:
var a = (((1, 2), 3), 4);
a; //4
Что насчет запятых, использующихся в литералах типа и в объявлениях?
Эти разделители на самом деле не операторы запятая. Назначение разделителя-запятая — разделение членов в списке. К примеру:
// создает массив из 4 элементов
var arr = [1, 2, 3, 4];
//создает объект с двумя свойствами
var obj = {
a: 22,
f: function() {return this.a*this.a}
}
//определяет три переменные
var a = 1, b = 2, c = 3;
//вызывает функцию, передавая 2 параметра
Math.max(4, 7);
Зачем использовать оператор запятая?
Затем, что она позволяет вам выполнить несколько выражений в том месте, где JavaScript ожидает только одно. Выражения с оператором запятая не такие распространенные, редко важные, но очень элегантные:
var r = [], n = 0, a = 0, b = 1, next;
function nextFibonacci() {
next = a + b;
return b = (a = b, next); // <<< Вот тут
}
while(n++ < 10) {
r.push(nextFibonacci());
}
r; //[1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
function getRandomPrime() {
while(n = Math.round(Math.random()*1000000000), !isPrime(n)); // <<< Вот тут
return n;
}
var isPrime = function(n) {
d = Math.ceil(Math.sqrt(n));
while(n%(d--) && d);
return !d;
}
getRandomPrime(); //425593109
getRandomPrime(); //268274719
Разве точка с запятой — не замаскированная запятая?
Точка с запятой — это разделитель объявлений, а запятая — это разделитель выражений внутри объявлений.
Почему бы не использовать оператор && для выполнения нескольких выражений последовательно?
Оператор запятая очень близка к оператору && и ||. Все эти операторы возвращают последнее выражение, которое они выполнили. Вот в чем их различие:
LHE — левое выражение
RHE — правое выражение
LHE && RHE
1. Всегда выполняет LHE
2. если LHE — true, выполняет RHE
LHE || RHE
1. Всегда выполняет LHE
2. Если LHE — false, выполняет RHE
LHE, RHE
1. Всегда выполняет LHE
2. Всегда выполняет RHE
Вам следует выбрать запятую, если оба выражения должны быть выполнены.
Как насчет примеров?
Как я отмечал ранее, оператор запятая позволяет вам выполнить несколько выражений в том месте, где JavaScript ожидает только одно.
Циклы for
Вот альтернативная версия генератора чисел Фибоначчи, которая также использует оператор запятая:
for (
var i=2, r=[0,1];
i<15;
r.push(r[i-1] + r[i-2]), i++
);
r //"0,1,1,2,3,5,8,13,21,34,55,89,144,233,377"
Для другого примера рассмотрим утилиту, которая помогает продавцу выбирать купюры и монеты, составляющие сдачу покупателя:
function toCurrency(total, values) {
total *= 100;
for(
var i=0,counts=[];
counts[i]=total/values[i], total=total%values[i]; // Вот тут
i++
);
return counts.map(Math.floor);
}
toCurrency(32.47, [500, 100, 25, 10, 5, 1]); //[6, 2, 1, 2, 0, 2]
Та же самая утилита, но с форматированием:
function toCurrency(total, values, sym) {
total *= 100;
//do the calc
for(
var i=0,counts=[];
counts[i]=total/values[i], total=total%values[i]; // Вот тут
i++
);
//format
var results = counts.map(function(s,i) {
return s>=1 && [Math.floor(s),"x",(sym || '$') +
(values[i]/100).toFixed(2)].join(' ');
});
return results.filter(Boolean).join(', ');
}
toCurrency(19.77, [500,100,25,10,5,1]);
//"3 x $5.00, 4 x $1.00, 3 x $0.25, 2 x $0.01"
toCurrency(19.77, [500,100,50,20,10,5,1], '£');
//"3 x £5.00, 4 x £1.00, 1 x £0.50, 1 x £0.20, 1 x £0.05, 2 x £0.01"
toCurrency(19.77, [500,100,50,20,10,5,2,1], '€');
//"3 x €5.00, 4 x €1.00, 1 x €0.50, 1 x €0.20, 1 x €0.05, 1 x €0.02"
Следующая функция использует запятую для одновременного увеличения и уменьшения двух переменных внутри цикла. На выходе получаем кривую:
function renderCurve() {
for(var a = 1, b = 10; a*b; a++, b--) // Вот тут
console.log(new Array(a*b).join('*'));
}
renderCurve();
/*
*********
*****************
***********************
***************************
*****************************
*****************************
***************************
***********************
*****************
*********
*/
Циклы while
Вы можете использовать оператор запятая для создания кратких версий циклов do-while.
Эта функция ищет предка из списка элементов с именем tagName (аналог jQuery parent).
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">
Тернарный оператор
Тернарный оператор позволяет выполнять только одно выражение. Если вам необходимо выполнить несколько выражений, то вам приходится переходить на if else. Оператор запятая более читаемый в тех случаях когда он используется для комбинации коротких выражений:
//player loses
lives ? (gameOver(), exit()) : (lives--, go());
Дебаг
Оператор запятая позволяет вам вставлять console.log в любое место без изменения кода:
//складывает products пока i > n
var i=10, n=0, total=0;
while(console.log(i,n), i-- > n++); {
total += i*n
}
//складывает элементы массива
var arr = [1,2,3];
for (
var i=0, total=0;
i<arr.length;
console.log(i,total), total += arr[i++]);
)
//добавляет 4 к каждому элементу массива и складывает их
var testArray = [3, 5, 8, 4], total = 0;
var plusFour = testArray.map(function(e) {e + 4})
plusFour.forEach(function(n) {console.log(n), isNaN(n) || (total += n)});
Связывание с итераторами
@wavded опубликовал один способ применения запятой.
var colorIndex = 0,
colors = ["FF0000", "008000", "FF0086", "A2FF00", "0000FF", "800080"];
function selectNextColor(){
return colors[colorIndex++] || colors[colorIndex = 0, colorIndex++];
}
Косвенный вызов eval
eval1 использует тот контекст в котором был вызван. Поэтому нет гарантий, что вызов eval в цикле даст тот же самый результат.
kangax написал, что мы можем использовать оператор запятая для косвенного вызова eval, который будет всегда вызываться в глобальном контексте2:
var a = {};
(function() {
eval("this.alert('If you can read this I must be global!')");
}).call(a);
//TypeError: this.alert is not a function
(function() {
(0,eval)("this.alert('If you can read this I must be global!')");
}).call(a);
//alerts: 'If you can read this I must be global!'
1. Пожалуйста без холиваров, все знают, что eval — evil
2. В стандарте ES5 написано, что любой не прямой вызов eval использует глобальный контекст,
однако не все браузеры поддерживают это правило (IE<=8)
Заключение
Вы можете писать отличный код и без использования оператора запятая. Значит ли это, что я потратил ваше время? Я надеюсь, что нет. Обширный словарный запас делает писателей и ораторов более профессиональными так и доступ к широком возможностям языка может сделать из нас лучших кодеров. Чем больше методов мы знаем тем более красивый, аккуратный и читаемый код мы можем написать. Удачи с оператором запятая, поделитесь своими примерами использования!
Почитать
ECMA-262 5th Edition
11.14 The comma operator
10.4.2 Entering eval code
15.1.2.1.1 Direct Call to Eval
Mozilla Developer Center
comma operator
operator precedence
Juriy Zaytsev ( kangax): global eval, what are the options
Mark Harter ( @wavded): cycling through an array using the comma operator
UPD Принял во внимание и исправил недочеты в переводе