Virgül operatörü ne zaman kullanışlıdır?


88

İfadelerde ( ) "virgül operatörü" hakkındaki bu soruyu ,ve bununla ilgili MDN belgelerini okudum , ancak yararlı olduğu bir senaryo düşünemiyorum.

Peki virgül operatörü ne zaman kullanışlıdır?


2
var i, j, k;vs var i; var j, var k?
Salman A

15
@SalmanA. ,Operatörle bir ilgisi olduğundan emin değilim . Bu satır içinde de geçerlidir C#, ancak ,operatör orada mevcut değildir.
gdoron Monica'yı destekliyor

2
@SalmanA. Yaptım.
Bulamadım, aydınlat

5
@SalmanA a ,her zaman ,operatör değildir (ve hiçbir zaman ,C # ' da operatör değildir). Bu nedenle C # , sözdiziminin bir parçası olarak ,özgürce kullanılırken bir işleci ,olmayabilir.
Seth Carnegie

8
Sanırım buradaki yanıtlar ,, yaygın olarak kullanılmadığı gerçeğini özetledi (ve a'nın her oluşumu ,virgül operatörü değildir) . Ancak geçici bir değişken oluşturmadan bir değişken takası satır içi yapmak için onu ve bir Dizi ödünç alabilirsiniz. Eğer değerlerini karşılıklı olarak istediğiniz göz önüne alındığında ave byapabileceğiniz a = [b][b = a,0]. Bu, akımı bDiziye yerleştirir. İkincisi [], mülkiyet erişim gösterimi. Erişilen endeksidir 0, ancak atamadan önce ahiç bberi artık güvenli olan bArray tutulur. içindeki ,çoklu ifadeleri yapmamızı sağlar [].

Yanıtlar:


128

Aşağıdakiler muhtemelen kendiniz yazmadığınız için çok kullanışlı değildir, ancak bir minifier virgül operatörünü kullanarak kodu küçültebilir. Örneğin:

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

olacaktı:

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

? :(Bir ölçüde) virgül operatörü iki ifade bir ifadesi olarak yazılmasına izin verir çünkü operatör, şimdi kullanılabilir.

Bu , bazı düzgün sıkıştırmaya izin vermesi açısından yararlıdır (burada 39 -> 24 bayt).


Ben virgülle gerçeğini vurgulamak istiyorum var a, bolduğunu değil bir dahilinde olmadığından virgül operatörü ifadesi . Virgülün var ifadelerde özel bir anlamı vardır . a, bbir ifadede iki değişkene atıfta bulunur ve bbunun için geçerli değildir var a, b.


3
Bunu nasıl düşündün? Biraz nerede okudun mu? Gerçekten kullanılıyor mu?
gdoron Monica'yı destekliyor

16
Geçen gün Closure Compiler ile gerçekten ne yaptığını görmek için uğraşıyordum ve bu değişikliği fark ettim.
pimvdb

2
Kodunuzda yararlı olduğunu düşündüğüm benzer bir kullanım, bir satır içi if ifadesinde birden çok değişken atamak olabilir. Örneğin: if (condition) var1 = val1, var2 = val2;Ben şahsen mümkün olduğunda parantezlerden kaçınmanın kodu daha okunaklı hale getirdiğini düşünüyorum.
Aidiakapi

2
Virgül operatörünü kullandığım tek zamanlar, ifadelere (foo => (console.log ('foo', foo), foo)) günlük ifadeleri eklediğimde veya yinelemeleri azaltma konusunda çok akıllı olmaya başladığım zamanlar . (pairs.reduce ((acc, [k, v]) => (acc [k] = v, acc), {}))
Joseph Sikorski

38

Virgül operatörü, tek bir ifadenin beklendiği bir yere birden çok ifade koymanıza olanak tanır. Virgülle ayrılmış birden çok ifadenin sonuç değeri, virgülle ayrılmış son ifadenin değeri olacaktır.

Kişisel olarak çok sık kullanmıyorum çünkü birden fazla ifadenin beklendiği pek çok durum yok ve kodu yazmanın virgül operatörünü kullanmaktan daha az kafa karıştırıcı bir yolu yok. forBirden fazla değişkenin artırılmasını istediğinizde , bir döngünün sonunda ilginç bir olasılık vardır :

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

Burada i++, j++, bir ifadeye izin verilen bir yere konulabileceğini görüyorsunuz . Bu özel durumda, çoklu ifadeler yan etkiler için kullanılır, bu nedenle bileşik ifadelerin sonuncunun değerini alması önemli değildir, ancak bunun gerçekten önemli olabileceği başka durumlar da vardır.


38

Virgül İşleci, Javascript'te işlevsel kod yazarken sıklıkla yararlıdır.

Bir süre önce bir SPA için yazdığım ve aşağıdaki gibi bir şeye sahip olan bu kodu düşünün

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

Bu oldukça karmaşık ama gerçek dünya senaryosuydu. Ne olduğunu açıklarken yanımda olun ve bu süreçte Virgül Operatörü için durumu açıklayın.


Bu, Alt Çizgi'nin zincirlemesini kullanır

  1. Kullanarak bu işleve geçirilen tüm seçenekleri ayır pairs dönecek olan { a: 1, b: 2}içine[['a', 1], ['b', 2]]

  2. Bu özellik çiftleri dizisi, sistemdeki 'eylemler' olarak kabul edilenlere göre filtrelenir.

  3. Ardından, dizideki ikinci dizin, o eylemi temsil eden bir promise döndüren bir işlevle değiştirilir (kullanarak map)

  4. Son olarak, çağrısı reduceher "özellik dizisini" ( ['a', 1]) nihai bir nesneye geri birleştirecektir.

Sonuç, optionsargümanın yalnızca uygun anahtarları içeren ve değerleri çağıran işlev tarafından tüketilebilen dönüştürülmüş bir versiyonudur .


Sadece bakıyorum

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

Azaltma işlevinin boş bir durum nesnesiyle başladığını stateve bir anahtar ve değeri temsil eden her çift için işlev state, anahtar / değer çiftine karşılık gelen nesneye bir özellik ekledikten sonra aynı nesneyi döndürür . ECMAScript 2015'in ok işlevi sözdizimi nedeniyle, işlev gövdesi bir ifadedir ve sonuç olarak Virgül Operatörü kısa ve kullanışlı bir "yineleme" işlevine izin verir .

Kişisel olarak, ECMAScript 2015 + Arrow Functions ile daha işlevsel bir tarzda Javascript yazarken çok sayıda vakayla karşılaştım. Ok işlevleriyle karşılaşmadan önce (örneğin sorunun yazılması sırasında olduğu gibi) virgül operatörünü asla kasıtlı bir şekilde kullanmadım.


2
Bu, bir programcının virgül operatörünü nasıl / ne zaman kullanabileceğine ilişkin gerçekten yararlı tek cevaptır. Özelliklereduce
hgoebl

Güzel cevap, ama bir şey önerebilir eğer biraz daha okunabilir: .reduce((state, [key, value]) => (state[key] = value, state), {}). Ve bunun cevabın amacını bozduğunu, ancak .reduce((state, [key, value]) => Object.assign(state, { [key]: value }), {})virgül operatörüne olan ihtiyacı tamamen ortadan kaldıracağını anlıyorum .
Patrick Roberts

Object.assign bugünlerde muhtemelen daha deyimsel olsa da, hatta sadece yayılma operatörü olsa da, o zamanlar yaygın kullanımda olduklarından emin değilim. Ayrıca virgül operatörü biraz daha belirsiz olsa da, veri kümesinin çok büyük olduğu durumlarda bunun çok daha az çöp üretebileceğini de belirtmek isterim. Yıkım kesinlikle okunabilirliğe yardımcı olacaktır!
Syynth

18

Virgül operatörünün başka bir kullanımı, yalnızca kolaylık sağlamak amacıyla repl veya konsolda umursamadığınız sonuçları gizlemektir.

Örneğin myVariable = aWholeLotOfText, repl veya konsolda değerlendirirseniz , az önce atadığınız tüm verileri yazdıracaktır. Bu, sayfalar ve sayfalar olabilir ve görmemeyi tercih ederseniz, bunun yerine değerlendirebilirsiniz myVariable = aWholeLotOfText, 'done've repl / console sadece 'bitti' yazacaktır.

Doğru işaret Oriel özelleştirilmiş olduğu toString()veya get()fonksiyonlar hatta bu yararlı hale getirebileceğini.


1
Ha, çok güzel fikir! (Son olarak, neredeyse tüm cevapların aksine soruyu gerçekten cevaplayan bir cevap {ve görmek için
20.000

1
Atanan değer bir nesneyse, konsol onu güzel bir şekilde görüntülemeye çalışabilir. Bunu yapmak için örneğin alıcıları çağırabilir ve bu da nesnenin durumunu değiştirebilir. Virgül kullanmak bunu önleyebilir.
Oriol

@Oriol - Güzel! Tamamen haklısın. Her nasılsa bu potansiyel olarak yararlı olmak biraz hayal kırıklığı yaratıyor :)
Julian de Bhal

13

Virgül operatörü JavaScript'e özel değildir, C ve C ++ gibi diğer dillerde mevcuttur . Bir ikili operatör olarak bu, genellikle bir ifade olan birinci işlenen, ikinci işlenenin gerektirdiği istenen yan etkiye sahip olduğunda yararlıdır. Wikipedia'dan bir örnek:

i = a += 2, a + b;

Açıkçası iki farklı kod satırı yazabilirsiniz, ancak virgül kullanmak başka bir seçenektir ve bazen daha okunabilirdir.


1
Bunu bir alternatif olarak düşünün, ancak iyinin tanımı kişiden kişiye farklılık gösterebilir. Ancak virgül kullanmanız GEREKEN herhangi bir örnek bulamıyorum. Benzer bir başka şey de üçlü?: Operatör. Bu her zaman if-else ile değiştirilebilir, ancak bazen?: İf-else'ten daha okunabilir kod yapar. Aynı kavram virgül için de geçerli.
taskinoor

BTW, değişken bildiriminde virgül kullanımını veya döngüde birden çok değişkeni başlatmayı düşünmüyorum. Bu durumlarda virgül çoğunlukla daha iyidir.
taskinoor

2
bu kafa karıştırıcı görünüyor af ... wtf.
Timmerz

6

Flanagan'a katılmıyorum ve virgülün gerçekten yararlı olduğunu ve özellikle ne yaptığınızı bildiğinizde daha okunaklı ve zarif kod yazmanıza izin verdiğini söyleyebilirim:

Virgül kullanımıyla ilgili çok ayrıntılı makale şu şekildedir:

Gösteri kanıtı için oradan birkaç örnek:

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

Bir fibonacci üreteci:

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()fonksiyonunun analog olan birinci ebeveyn öğesini bulun :

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">


1
Son örnekte while döngüsünde virgül kullanmanıza gerek yok while ((el = el.parentNode) && (el.tagName != tagName.toUpperCase())), bu bağlamda gayet iyi olur.
PitaJ

5

Bunun dışında pratik bir kullanım bulamadım ama işte James Padolsey'in bu tekniği bir süre döngüsünde IE tespiti için güzelce kullandığı bir senaryo :

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;

}());

Bu iki satırın yürütülmesi gerekir:

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

Ve virgül operatörünün içinde, her ikisi de değerlendirilir, ancak biri bir şekilde ayrı ifadelerde bulunmuş olabilir.


3
Bu olabilirdi do- whiledöngü.
Casey Chu

5

JavaScript'te virgül operatörü kullanılarak dolaylı olarak bir işlevi çağırarak yapılabilecek "tuhaf" bir şey vardır.

Burada uzun bir açıklama var: JavaScript'te dolaylı işlev çağrısı

Bu sözdizimini kullanarak:

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

Global değişkene erişebilirsiniz çünkü evaldoğrudan çağrıldığında ve dolaylı olarak çağrıldığında farklı çalışır.


4

Bunun gibi yardımcıları yazarken en kullanışlı virgül operatörünü buldum.

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

Virgülü bir || ile değiştirebilirsiniz. veya &&, ancak daha sonra işlevin ne döndürdüğünü bilmeniz gerekir.

Bundan daha da önemlisi, virgül ayırıcı amacı iletir - kod , sol işlenenin neyi değerlendirdiğini umursamaz , oysa alternatiflerin orada olmak için başka bir nedeni olabilir. Bu da anlaşılmasını ve yeniden düzenlenmesini kolaylaştırır. İşlev dönüş türü herhangi bir şekilde değişirse, yukarıdaki kod etkilenmeyecektir.

Doğal olarak aynı şeyi başka şekillerde de başarabilirsiniz, ancak bu kadar özlü değil. Eğer || ve && virgül operatörü gibi ortak kullanımda bir yer buldu.


Ramda \ Lodash'ın tap( ramdajs.com/docs/#tap ) ile yaptıklarına benzer . Esasen, bir yan etki yürütüyorsunuz ve ardından başlangıç ​​değerini döndürüyorsunuz; fonksiyonel programlamada çok yararlı :)
avalanche1

1

Kullanmak zorunda kaldığım tipik bir durum, isteğe bağlı bağımsız değişken ayrıştırması sırasında. Bence onu hem daha okunabilir hem de daha özlü hale getiriyor, böylece ayrıştırma argümanı işlev gövdesine hakim olmaz.

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

  // ...
}

Ben kendimden hoşlanmasam da, bir kişinin tamamen delice olduklarını düşünmeden, eşdeğer bireysel ifade ifadeleri listesinden daha okunabilirlik için daha iyi olduğunu söyleyebileceğini düşündüğüm tek örnek bu.
Noktalı virgül

1

Diyelim ki bir diziniz var:

arr = [];

Bu pushdiziye girdiğinizde , nadiren pushdöndürülen değerle, yani dizinin yeni uzunluğuyla, daha çok dizinin kendisiyle ilgilenirsiniz :

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

Virgül operatörünü kullanarak, diziye itebilir, diziyi virgül için son işlenen olarak belirleyebilir ve ardından sonucu (dizinin kendisi) sonraki bir dizi yöntemi çağrısı için, bir tür zincirleme olarak kullanabiliriz:

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

-2

Virgül operatörünün kullanılabileceği başka bir alan da Kod Gizleme'dir .

Bir geliştiricinin şöyle bir kod yazdığını varsayalım:

var foo = 'bar';

Şimdi, kodu gizlemeye karar veriyor. Kullanılan araç kodu şu şekilde değiştirebilir:

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

Demo: http://jsfiddle.net/uvDuE/


1
@gdoron Lütfen C ++ 'daki Virgül Operatörü ile ilgili stackoverflow.com/a/17903036/363573 yanıtına bir göz atın . James Kanze'nin şaşırtma hakkındaki yorumunu fark edeceksiniz.
Stephan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.