Co robi przecinek w wyrażeniach JavaScript?

89

Jeśli używam:

1.09 * 1; // returns "1.09"

Ale jeśli używam:

1,09 * 1; // returns "9"

Wiem, że 1,09 nie jest liczbą.

Co robi przecinek w ostatnim fragmencie kodu?

Więcej przykładów

if (0,9) alert("ok"); // alert
if (9,0) alert("ok"); // don't alert

alert(1); alert(2); alert(3); // 3 alerts
alert(1), alert(2), alert(3); // 3 alerts too

alert("2",
    foo = function (param) {
        alert(param)
    },
    foo('1')
)
foo('3'); // alerts 1, 2 and 3
Topera
źródło
1
Dziwię się, że 09 nie zawodzi w przypadku nielegalnej cyfry „9” w dosłownym ósemkowym.
rekurencyjne
7
@recursive - dowolne 9 w reprezentacji ósemkowej powoduje powrót do wartości dziesiętnej.
Yuval Adam
Nie pomyl przecinka na liście argumentów. alertprzyjmuje tylko jeden argument. Wszystko po tym jest odrzucane.
Andrew,
@Andrew: tak, jest odrzucany przez alert (), który pobiera tylko jeden argument, ale zostanie uruchomiony! To jest dziwne. Dzięki.
Topera
1
@Topera: nic dziwnego, jeśli myślisz o tym z perspektywy JS. W JS nie musisz podawać swojej listy argumentów w deklaracji funkcji (możesz argumentszamiast tego użyć obiektu, który może mieć dowolną długość). Nawet w przypadku nowoczesnego skompilowanego JS nie byłoby sposobu, aby przewidzieć, ile argumentów zajmie funkcja. Rozważ to: function test() { args=[]; for (var i = 0; i < arguments.length; i++) { args.push(arguments[i] + 1); } ;interpreter musiałby wiedzieć, w jaki sposób funkcja była używana, aby wiedzieć, ile argumentów zajmie. Zamiast tego ocenia wszystko.
Andrew,

Odpowiedzi:

95

Operator przecinka ocenia oba swoje operandy (od lewej do prawej) i zwraca wartość drugiego operandu.

Źródło: https://developer.mozilla.org/en/JavaScript/Reference/Operators/Special_Operators/Comma_Operator

Na przykład wyrażenie 1,2,3,4,5oblicza 5. Oczywiście operator przecinka jest przydatny tylko w przypadku operacji z efektami ubocznymi.

console.log(1,2,3,4,5);
console.log((1,2,3,4,5));

Yuval Adam
źródło
2
Wzięli to od C. Myślę, że jest to przydatne tylko w przypadku wyrażeń, które mają skutki uboczne.
Radomir Dopieralski 24.08.10
3
Nie przychodzi mi do głowy wiele przypadków, w których operator przecinka jest używany do jakiegokolwiek wpływu poza zapisywaniem znaków (zmniejszaniem) lub zaciemnianiem kodu.
user17753
1
@ user17753 może być legalnie używany w oddzielonej średnikami sekcji forpętli.
Cyoce
1
@Cyoce: To prawda, ale ogólnie rzecz biorąc, taka logika jest bardziej przejrzysta w pętli. Niektórzy ludzie twierdzą wtedy, że ich droga pozwala na uzyskanie wielu continuepunktów bez powielania, ale wtedy nie powinieneś mieć wielu continuepunktów.
Wyścigi lekkości na orbicie
@ user17753 Jesteś na pieniądzach; próbując zrozumieć mały fragment zminimalizowanego kodu, dlaczego tu jestem
Rzadko „Where's Monica” Needy
6

Więcej do rozważenia:

console.log((0, 9));
console.log((9, 0));
console.log(("foo", "bar"));

Douglas
źródło
7
Lol, fajnie:alert("1", alert("2", alert("3")))
Topera
1
@Andrew: Ups, zaktualizowałem odpowiedź o to, czego chciałem użyć.
Douglas,
Operator przecinka ocenia każdy z jego operandów (od lewej do prawej) i zwraca wartość lastoperandu.
xgqfrms
2
Operator przecinka ocenia oba swoje operandy (od lewej do prawej) i zwraca wartość second operandu.

https://stackoverflow.com/a/3561056/5934465

Tak powinno być!

Operator przecinka ocenia każdy z jego operandów (od lewej do prawej) i zwraca wartość lastoperandu.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator

xgqfrms
źródło
5
Operator przecinka przyjmuje dwa operandy, więc oryginalny cudzysłów był poprawny. To, o czym mówisz, jest końcowym rezultatem zagnieżdżenia takich wyrażeń, ale oznacza to, że Twój cytat zastępczy jest subtelnie błędnie sformułowany. a,b,c,djest((((a),b),c),d)
Wyścigi lekkości na orbicie
1

Spójrz tutaj - przecinek oznacza wiele wyrażeń / instrukcji. Na przykład w swoim kodzie możesz użyć następującej linii:

var a=0, b=0, c=0;

To zadeklarowałoby wszystkie trzy zmienne bez pisania:

var a=0;
var b=0;
var c=0;

Mam nadzieję, że to pomoże.

dhh
źródło
23
Jest trochę stary, ale należy pamiętać: (1) podany przykład nie używa operatora przecinka ( vardeklaracje nie używają operatora przecinka , mimo że jest to przecinek) i (2) nie można go oddzielić zdania za pomocą operatorów przecinków; dozwolone są tylko wyrażenia.
Qantas 94 Heavy
0

Dodanie / modyfikacja właściwości do obiektu i zwrócenie go w tym samym wierszu to możliwy przypadek użycia:

console.log(
  ((x) => (o = {biggerCond: r => r >= x},
           o.r5 = Array.from(window.crypto.getRandomValues(new Uint16Array(5))),
           o.isAnyBigger = o.r5.some(o.biggerCond),
           o.bigger = o.isAnyBigger ? o.r5.filter(o.biggerCond) : [x], o )
  )(5e4)
);
// Example
// {
//   bigger: [58414, 56500, 63397],
//   isAnyBigger: true,
//   isBiggerCond: r => r >= x,
//   r5: [58414, 12015, 56500, 63397, 43861]
// }

Powyższa funkcja anonimowa zwraca obiekt z losowymi wartościami większymi niż wartość wejściowa lub, jeśli ich nie ma, z samą wartością wejściową w tablicy zawartej we biggerwłaściwości.

Wciąż jest to cukier syntaktyczny (podobnie jak funkcje strzałkowe ), ale skraca liczbę linii ... Zastanawiam się, czy niektóre minifierki JS automatycznie wykrywają i dostosowują kod w podobny sposób. Uruchom go w konsoli:

((x)=>(o={biggerCond:r=>r>=x},o.r5=Array.from(window.crypto.getRandomValues(new Uint16Array(5))),o.isAnyBigger=o.r5.some(o.biggerCond),o.bigger=o.isAnyBigger?o.r5.filter(o.biggerCond):[x],o))(5e4)
CPHPython
źródło
2
Ale oczywiście nie umieściłbyś takich tajemniczych zaklęć w kodzie produkcyjnym, prawda?
Wyścigi lekkości na orbicie
@LightnessRacesinOrbit cóż, powiem, że zależy to od celu (np. Nauczanie, skracanie kodu, brak deklaracji zmiennych / funkcji itp.). Jeśli wcinasz to tak, jak zrobiłem powyżej, jest to doskonale czytelne ... Nie mogę przestać zauważać, że użyłeś słowa "tajemniczy" :)
CPHPython
1
Heh, to nie było nawet zamierzone 😂
Lightness Races in Orbit