Когда полезен оператор запятой?

Я читаю этот вопрос о "запятом" в выражениях (,) и MDN docs об этом, но я не могу придумать сценарий, где это полезно.

Итак, когда полезен оператор запятой?

Ответ 1

Ниже, вероятно, не очень полезно, поскольку вы не пишете его самостоятельно, но minifier может сжимать код с помощью оператора запятой. Например:

if(x){foo();return bar()}else{return 1}

станет:

return x?(foo(),bar()):1

Теперь можно использовать оператор ? :, так как оператор запятой (в определенной степени) допускает запись двух операторов как одно утверждение.

Это полезно в том, что он позволяет использовать некоторое аккуратное сжатие (39 → 24 байта).


Я хотел бы подчеркнуть тот факт, что запятая в var a, b является не оператором запятой, потому что она не существует в выражении. В выражениях var запятая имеет особое значение. a, b в выражении будет ссылаться на две переменные и оценивать до b, что не относится к var a, b.

Ответ 2

Оператор запятой позволяет вам помещать несколько выражений в место, где ожидается одно выражение. Результирующее значение нескольких выражений, разделенных запятой, будет значением последнего выражения, разделенного запятыми.

Я не часто использую его очень часто, потому что не так много ситуаций, когда ожидается более одного выражения, и не менее сложный способ написать код, чем использование оператора запятой. Одна интересная возможность заключается в конце цикла for, когда вы хотите увеличить несколько переменных:

// 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
}

Здесь вы видите, что i++, j++ можно помещать в место, где разрешено одно выражение. В этом конкретном случае множественные выражения используются для побочных воздействий, поэтому не имеет значения, что составные выражения принимают значение последнего, но есть и другие случаи, когда это может иметь значение.

Ответ 3

Оператор Comma Operator часто полезен при написании функционального кода в Javascript.

Рассмотрите этот код, который я написал для SPA, а затем назад, у которого было что-то вроде следующего

const actions = _.chain(options)
                 .pairs() // 1
                 .filter(selectActions) // 2
                 .map(createActionPromise) // 3
                 .reduce((state, pair) => (state[pair[0]] = pair[1], state), {}) // 4
                 .value();

Это был довольно сложный, но реальный сценарий. Потерпите меня, пока я объясню, что происходит, и в этом случае сделайте дело для Comma Operator.


Это использует Underscore цепочку для
  • Разделите все параметры, переданные этой функции, используя pairs который превратит { a: 1, b: 2} в [['a', 1], ['b', 2]]

  • Этот массив пар свойств фильтруется, посредством которого они считаются "действиями" в системе.

  • Затем второй индекс в массиве заменяется функцией, которая возвращает обещание, представляющее это действие (используя map)

  • Наконец, вызов reduce объединит каждый "массив свойств" (['a', 1]) обратно в конечный объект.

Конечным результатом является преобразованная версия аргумента options, которая содержит только соответствующие ключи и значения которых могут быть использованы вызывающей функцией.


Глядя только на

.reduce((state, pair) => (state[pair[0]] = pair[1], state), {})

Вы можете увидеть, что функция уменьшения начинается с пустого объекта состояния, state и для каждой пары, представляющей ключ и значение, функция возвращает тот же объект state после добавления свойства к объекту, соответствующему ключу/значение. Из-за синтаксиса функциональных возможностей стрелки ECMAScript 2015 тело функции является выражением, и, как результат, Comma Operator допускает краткий и полезный "iteratee" функция.

Лично я сталкивался с многочисленными случаями при написании Javascript в более функциональном стиле с помощью ECMAScript 2015 + Arrow Functions. Сказав это, перед тем как встретить функции стрелок (например, во время написания вопроса), я никогда не использовал запятую каким-либо образом.

Ответ 4

Другое использование для оператора запятой - это скрыть результаты, которые вам не нужны в реплике или консоли, просто как удобство.

Например, если вы оцениваете myVariable = aWholeLotOfText в реплике или консоли, он распечатает все данные, которые вы только что назначили. Это могут быть страницы и страницы, и если вы предпочитаете не видеть его, вы можете оценить myVariable = aWholeLotOfText, 'done', а repl/console просто напечатает "done".

Ориэл правильно указывает , настроенный toString() или get() функции могут даже сделать это полезным.

Ответ 5

Comma-оператор не относится к JavaScript, он доступен на других языках, таких как C и С++. В качестве двоичного оператора это полезно, когда первый операнд, который обычно является выражением, имеет желаемый побочный эффект, требуемый вторым операндом. Один пример из Википедии:

i = a += 2, a + b;

Очевидно, вы можете написать две разные строки кодов, но использование запятой - это еще один вариант, а иногда и более читаемый.

Ответ 6

Я бы не согласился с Flanagan и сказал, что запятая действительно полезна и позволяет писать более читаемый и элегантный код, особенно когда вы знаете, что делаете:

Здесь значительно подробная статья по использованию запятой:

Несколько примеров оттуда для доказательства демонстрации:

function renderCurve() {
  for(var a = 1, b = 10; a*b; a++, b--) {
    console.log(new Array(a*b).join('*'));
  }
}

Генератор фибоначчи:

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

Найти первый родительский элемент, аналог функции 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">

Ответ 7

Я не нашел практического использования, кроме этого, но вот один из сценариев, в которых Джеймс Падолси прекрасно использует эту технику для обнаружения IE в цикле while:

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;

}());

Эти две строки должны выполняться:

div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
all[0]

И внутри оператора запятой оба оцениваются, хотя можно было каким-то образом сделать их отдельными утверждениями.

Ответ 8

Есть что-то "нечетное", которое может быть сделано в JavaScript, вызывающем функцию косвенно с помощью оператора запятой.

Здесь есть длинное описание: Непрямой вызов функции в JavaScript

Используя этот синтаксис:

(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);
  
  }());

Ответ 9

Один типичный случай, когда я заканчиваю его использование во время необязательного разбора аргументов. Я думаю, что это делает его более читабельным и более сжатым, так что разбор аргументов не доминирует над телом функции.

/**
 * @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();

  // ...
}

Ответ 10

Я нашел оператора запятой наиболее полезным при написании таких помощников.

const stopPropagation = event => (event.stopPropagation(), event);
const preventDefault = event => (event.preventDefault(), event);
const both = compose(stopPropagation, preventDefault);

Вы можете заменить запятую либо || или &&, но тогда вам нужно будет узнать, что возвращает функция.

Что более важно, разделитель запятой передает намерение - код не заботится о том, что оценивает левый операнд, тогда как альтернативы могут иметь еще одну причину присутствия. Это, в свою очередь, упрощает понимание и рефакторинг. Если тип возвращаемой функции когда-либо изменяется, код, указанный выше, не будет затронут.

Естественно, вы можете добиться того же самого и другими способами, но не так лаконично. Если || и && нашел место в общем использовании, так же может и оператор запятой.

Ответ 11

Другая область, в которой может использоваться оператор запятой, Обтекание кода.

Скажем, разработчик пишет такой код:

var foo = 'bar';

Теперь она решает обфускать код. Используемый инструмент может изменить код следующим образом:

var Z0b=(45,87)>(195,3)?'bar':(54,65)>(1,0)?'':'baz';// Z0b == 'bar'

Демо: http://jsfiddle.net/uvDuE/