Когда полезен оператор запятой? - PullRequest
73 голосов
/ 06 марта 2012

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

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

Ответы [ 12 ]

111 голосов
/ 06 марта 2012

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

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.

32 голосов
/ 06 марта 2012

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

Лично я не использую его очень часто, потому что не так много ситуаций, когда ожидается более одного выражения, и нет менее запутанного способа написания кода, чем использование оператора запятой.Одна интересная возможность - в конце цикла 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++ может быть помещено в место, где одно выражениепозволил.В этом конкретном случае множественные выражения используются для побочных эффектов, поэтому не имеет значения, что составные выражения принимают значение последнего, но в других случаях это может иметь значение.

31 голосов
/ 10 октября 2015

Оператор запятой часто полезен при написании функционального кода в 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();

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


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

  2. Этот массив пар свойств фильтруется по тому, какие из них считаются «действиями» в системе.

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

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

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


Рассматривая только

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

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

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

17 голосов
/ 12 февраля 2016

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

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

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

12 голосов
/ 06 марта 2012

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

i = a += 2, a + b;

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

6 голосов
/ 30 сентября 2013

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

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

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

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">
5 голосов
/ 06 марта 2012

Я не нашел практического использования, кроме этого, но вот один сценарий, в котором Джеймс Падолси прекрасно использует эту технику для обнаружения 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]

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

4 голосов
/ 24 сентября 2016

Есть что-то "странное", что можно сделать в 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);
  
  }());

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

3 голосов
/ 08 октября 2018

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

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

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

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

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

1 голос
/ 13 февраля 2019

Допустим, у вас есть массив:

arr = [];

Когда вы push обращаетесь к этому массиву, вас редко интересует возвращаемое значение push, а именно новая длина массива, а скорее сам массив:

arr.push('foo')  // ['foo'] seems more interesting than 1

Используя оператор запятой, мы можем нажать на массив, указать массив в качестве последнего операнда для запятой, а затем использовать результат - сам массив - для последующего вызова метода массива, своего рода цепочки:

(arr.push('bar'), arr.push('baz'), arr).sort(); // [ 'bar', 'baz', 'foo' ]
...