Я читаю этот вопрос о "запятом" в выражениях (,
) и MDN docs об этом, но я не могу придумать сценарий, где это полезно.
Итак, когда полезен оператор запятой?
Я читаю этот вопрос о "запятом" в выражениях (,
) и MDN docs об этом, но я не могу придумать сценарий, где это полезно.
Итак, когда полезен оператор запятой?
Ниже, вероятно, не очень полезно, поскольку вы не пишете его самостоятельно, но 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
.
Оператор запятой позволяет вам помещать несколько выражений в место, где ожидается одно выражение. Результирующее значение нескольких выражений, разделенных запятой, будет значением последнего выражения, разделенного запятыми.
Я не часто использую его очень часто, потому что не так много ситуаций, когда ожидается более одного выражения, и не менее сложный способ написать код, чем использование оператора запятой. Одна интересная возможность заключается в конце цикла 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++
можно помещать в место, где разрешено одно выражение. В этом конкретном случае множественные выражения используются для побочных воздействий, поэтому не имеет значения, что составные выражения принимают значение последнего, но есть и другие случаи, когда это может иметь значение.
Оператор 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.
Разделите все параметры, переданные этой функции, используя 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. Сказав это, перед тем как встретить функции стрелок (например, во время написания вопроса), я никогда не использовал запятую каким-либо образом.
Другое использование для оператора запятой - это скрыть результаты, которые вам не нужны в реплике или консоли, просто как удобство.
Например, если вы оцениваете myVariable = aWholeLotOfText
в реплике или консоли, он распечатает все данные, которые вы только что назначили. Это могут быть страницы и страницы, и если вы предпочитаете не видеть его, вы можете оценить myVariable = aWholeLotOfText, 'done'
, а repl/console просто напечатает "done".
Ориэл правильно указывает †, настроенный toString()
или get()
функции могут даже сделать это полезным.
Comma-оператор не относится к JavaScript, он доступен на других языках, таких как C и С++. В качестве двоичного оператора это полезно, когда первый операнд, который обычно является выражением, имеет желаемый побочный эффект, требуемый вторым операндом. Один пример из Википедии:
i = a += 2, a + b;
Очевидно, вы можете написать две разные строки кодов, но использование запятой - это еще один вариант, а иногда и более читаемый.
Я бы не согласился с 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">
Я не нашел практического использования, кроме этого, но вот один из сценариев, в которых Джеймс Падолси прекрасно использует эту технику для обнаружения 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]
И внутри оператора запятой оба оцениваются, хотя можно было каким-то образом сделать их отдельными утверждениями.
Есть что-то "нечетное", которое может быть сделано в 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);
}());
Один типичный случай, когда я заканчиваю его использование во время необязательного разбора аргументов. Я думаю, что это делает его более читабельным и более сжатым, так что разбор аргументов не доминирует над телом функции.
/**
* @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();
// ...
}
Я нашел оператора запятой наиболее полезным при написании таких помощников.
const stopPropagation = event => (event.stopPropagation(), event);
const preventDefault = event => (event.preventDefault(), event);
const both = compose(stopPropagation, preventDefault);
Вы можете заменить запятую либо || или &&, но тогда вам нужно будет узнать, что возвращает функция.
Что более важно, разделитель запятой передает намерение - код не заботится о том, что оценивает левый операнд, тогда как альтернативы могут иметь еще одну причину присутствия. Это, в свою очередь, упрощает понимание и рефакторинг. Если тип возвращаемой функции когда-либо изменяется, код, указанный выше, не будет затронут.
Естественно, вы можете добиться того же самого и другими способами, но не так лаконично. Если || и && нашел место в общем использовании, так же может и оператор запятой.
Другая область, в которой может использоваться оператор запятой, Обтекание кода.
Скажем, разработчик пишет такой код:
var foo = 'bar';
Теперь она решает обфускать код. Используемый инструмент может изменить код следующим образом:
var Z0b=(45,87)>(195,3)?'bar':(54,65)>(1,0)?'':'baz';// Z0b == 'bar'