Коли корисний оператор коми?


88

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

Отже, коли корисний оператор коми?


2
var i, j, k;проти var i; var j, var k?
Сальман А

15
@SalmanA. Я не впевнений, що це має щось спільне з ,оператором. Цей рядок також діє C#, але ,оператор там не існує.
gdoron підтримує Моніку

2
@SalmanA. Я зробив. Не знайшов, порадуй мене ...
gdoron підтримує Моніку

5
@SalmanA a ,не завжди є ,оператором (і ніколи не є ,оператором на C #). Отже, C # може не мати ,оператора, водночас використовуючи його ,як частину синтаксису.
Сет Карнегі,

8
Я думаю, що відповіді тут підсумовують той факт, що ,не широко використовується (і не кожен випадок a ,є оператором коми) . Але ви можете позичити його та масив, щоб зробити заміну змінної вбудованим, не створюючи тимчасової змінної. Враховуючи, що ви хочете поміняти місцями значення aі b, ви можете це зробити a = [b][b = a,0]. Це поміщає струм bу масив. Другий []- це позначення доступу до власності. Індекс, до якого здійснюється доступ, є 0, але не раніше, ніж присвоювати aйому b, що зараз безпечно, оскільки bзберігається в масиві. ,дозволяє нам зробити кілька виразів в [].

Відповіді:


128

Наведене нижче, мабуть, не дуже корисне, оскільки ви не пишете його самостійно, але мініфікатор може стиснути код за допомогою оператора коми. Наприклад:

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.


3
Як ти про це думав? Ви десь це читали? Чи справді він використовується?
gdoron підтримує Моніку

16
Днями я просто базікав із компілятором закриття, щоб побачити, що він робить насправді, і я помітив цю заміну.
pimvdb

2
Подібне використання, яке, на мою думку, є корисним у вашому коді, було б для призначення кількох змінних у вбудованому операторі if. Наприклад: if (condition) var1 = val1, var2 = val2;Я особисто думаю, що уникання дужок, де це можливо, робить код більш читабельним.
Айдіякапі

2
Приблизно єдиний раз, коли я використовую оператор коми, це коли я додаю оператори журналу до виразів (foo => (console.log ('foo', foo), foo)), або якщо я занадто розумний із зменшенням кількості ітерацій . (pair.reduce ((acc, [k, v]) => (acc [k] = v, acc), {}))
Джозеф Сікорський

38

Оператор кома дозволяє розмістити кілька виразів у місці, де очікується один вираз. Отримане значення кількох виразів, відокремлених комами, буде значенням останнього відокремленого комами виразу.

Я особисто не використовую його дуже часто, тому що не так багато ситуацій, коли очікується більше одного виразу, і немає менш заплутаного способу написання коду, ніж використання оператора коми. Цікавою є можливість в кінці 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++їх можна поставити там, де дозволено один вираз. У цьому конкретному випадку множинні вирази використовуються для побічних ефектів, тому не має значення, що складені вирази набувають значення останнього, але є й інші випадки, коли це насправді може мати значення.


38

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

Це був досить складний, але реальний сценарій. Потерпіть зі мною, поки я поясню, що відбувається, і в процесі обговорюю справу з командним оператором.


Для цього використовується ланцюжок Підкреслення

  1. Розберіть все опції , передані в цю функцію з допомогою pairs якої перетвориться { a: 1, b: 2}в[['a', 1], ['b', 2]]

  2. Цей масив пар властивостей фільтрується за допомогою того, які з них вважаються "діями" в системі.

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

  4. Нарешті, виклик to reduceоб'єднає кожен "масив властивостей" ( ['a', 1]) назад у кінцевий об'єкт.

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


Дивлячись просто

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

Ви можете бачити, що функція зменшення починається з порожнього об'єкта стану state, і для кожної пари, що представляє ключ і значення, функція повертає той самий stateоб'єкт після додавання властивості до об'єкта, що відповідає парі ключ / значення. Через синтаксис функції стрілки ECMAScript 2015 тіло функції є виразом, і в результаті оператор Comma дозволяє короткий та корисний "ітератор" .

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


2
Це єдина дійсно корисна відповідь щодо того, як / коли програміст може використовувати оператор кома. Дуже корисно, особливо вreduce
hgoebl

1
Що стосується ES6 +, це має бути прийнятою відповіддю.
Арді Арам

Хороший відповідь, але якщо я можу запропонувати що - то трохи - трохи більш читабельним: .reduce((state, [key, value]) => (state[key] = value, state), {}). І я усвідомлюю, що це .reduce((state, [key, value]) => Object.assign(state, { [key]: value }), {})перешкоджає меті відповіді, але повністю виключає потребу в операторі коми.
Патрік Робертс,

Хоча Object.assign сьогодні, мабуть, більш ідіоматичний, а то й просто оператор поширення, я не впевнений, що на той час вони широко використовувались. Я також хотів би зазначити, що, хоча оператор-кома трохи більш незрозумілий, це може генерувати набагато менше сміття в ситуаціях, коли набір даних дуже великий. Деструктуризація, безумовно, допомогла б прочитати!
Syynth

18

Ще одне використання оператора коми - приховування результатів, які вас не турбують, у repl чи консолі, лише для зручності.

Наприклад, якщо ви оцінюєте myVariable = aWholeLotOfTextв repl або консолі, він надрукує всі дані, які ви щойно призначили. Це можуть бути сторінки та сторінки, і якщо ви бажаєте не бачити їх, ви можете замість цього оцінитиmyVariable = aWholeLotOfText, 'done' , і repl / консоль просто надрукує "готово".

Oriel правильно зазначає †, що персоналізовані функції toString()або get()функції можуть навіть зробити це корисним.


1
Ха, дуже приємна ідея! (Нарешті відповідь, яка насправді відповідає на запитання, на відміну від майже всіх відповідей {та 3 видалених відповідей, для перегляду яких вам потрібна репутація 20
тисяч

1
Якщо призначене значення є об'єктом, консоль може спробувати відобразити його красиво. Для цього це може, наприклад, викликати отримувачі, які можуть змінити стан об’єкта. Використання коми може запобігти цьому.
Oriol

@Oriol - Приємно! Ви абсолютно праві. Якось це потенційно корисне відчуття трохи розчаровує :)
Джуліан де Баль

13

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

i = a += 2, a + b;

Очевидно, що ви можете писати два різні рядки кодів, але використання коми - це інший варіант, який іноді є більш читабельним.


1
Подумайте про це як про альтернативу, хоча визначення добра може відрізнятися від людей до людей. Однак я не можу знайти жодного прикладу, коли ви ПОВИННІ використовувати кому. Ще одна подібна річ - тернар?: Operator. Це завжди можна замінити на if-else, але іноді?: Робить більш читабельний код, ніж if-else. Те саме поняття стосується і коми.
taskinoor

До речі, я не розглядаю використання коми у оголошенні змінних чи ініціалізації кількох змінних у циклі. У цих випадках кома переважно краща.
taskinoor

2
це виглядає заплутано з погляду ... wtf.
Тіммерц

6

Я б не погодився з Фланаганом і сказав би, що кома дійсно корисна і дозволяє писати більш читабельний та елегантний код, особливо коли ти знаєш, що робиш:

Ось дуже докладна стаття про використання коми:

Кілька прикладів звідти для підтвердження демонстрації:

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

Знайти перший батьківський елемент, аналог .parent()функції jQuery :

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
Я не впевнений, чи хотів би я сказати, що щось з цього є більш читабельним, але це, звичайно, досить пишно, тому +1
Кріс Марісіч

1
Вам не потрібна кома в циклі while в останньому прикладі, це while ((el = el.parentNode) && (el.tagName != tagName.toUpperCase()))було б чудово в цьому контексті.
PitaJ

5

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

І всередині оператора коми, обидва обчислюються, хоча можна було б зробити їм окремі твердження якось.


3
Це могло б бути do- whileпетля.
Кейсі Чу

5

Існує щось «дивне», що можна зробити в 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працює по-різному при прямому виклику проти непрямого виклику.


4

Я знайшов оператор коми найбільш корисним при написанні таких помічників.

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

Кому можна замінити на || або &&, але тоді вам потрібно буде знати, що повертає функція.

Важливіше за те, що розділювач комами повідомляє про намір - коду все одно, що оцінює лівий операнд, тоді як альтернативи можуть мати іншу причину перебування там. Це, в свою чергу, полегшує розуміння та рефакторинг. Якщо тип повернення функції коли-небудь зміниться, наведений вище код це не вплине.

Звичайно, ви можете досягти того самого іншого, але не так лаконічно. Якщо || та && знайшли місце у загальному користуванні, так само може і оператор-кома.


Подібно до того, що робить Ramda \ Lodash tap( ramdajs.com/docs/#tap ). По суті, ви виконуєте побічний ефект, а потім повертаєте початкове значення; дуже корисно в функціональному програмуванні :)
avalanche1

1

Одним із типових випадків, коли я в кінцевому підсумку використовую його, є необов’язковий аналіз аргументів. Я думаю, це робить його і більш читабельним, і більш стислим, щоб аналіз аргументів не домінував у тілі функції.

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

  // ...
}

Незважаючи на те, що я сам не виступаю за це, це єдиний приклад, який, на мою думку, людина може сказати, що це краще для читабельності, ніж еквівалентний перелік окремих висловлювань, не думаючи, що вони абсолютно божевільні.
крапка з комою

1

Скажімо, у вас є масив:

arr = [];

Коли ви pushпотрапляєте в цей масив, вас рідко цікавить pushповернене значення, а саме нова довжина масиву, а саме масив:

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

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

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

-2

Ще однією областю, де можна використовувати оператор коми, є Obfuscation Code .

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

var foo = 'bar';

Тепер вона вирішує заплутати код. Використовуваний інструмент може змінити код таким чином:

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

Демонстрація: http://jsfiddle.net/uvDuE/


1
@gdoron Будь ласка, подивіться на цю відповідь stackoverflow.com/a/17903036/363573 про Оператор Коми в C ++. Ви помітите коментар Джеймса Канзе про затуманення.
Stephan
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.