Czytałem to pytanie o "operator przecinka" w wyrażeniach ( ,
) i dokumentację MDN na ten temat, ale nie przychodzi mi do głowy scenariusz, w którym by się przydał.
Kiedy więc operator przecinka jest przydatny?
Czytałem to pytanie o "operator przecinka" w wyrażeniach ( ,
) i dokumentację MDN na ten temat, ale nie przychodzi mi do głowy scenariusz, w którym by się przydał.
Kiedy więc operator przecinka jest przydatny?
,
operatorem. Ta linia jest również ważna w C#
, ale ,
operator tam nie istnieje.
,
nie zawsze jest ,
operatorem (i nigdy nie jest ,
operatorem w C #). Więc C # może brakować ,
operatora, ale nadal może swobodnie używać ,
jako części składni.
,
nie jest powszechnie używany (i nie każde wystąpienie a ,
jest operatorem przecinka) . Ale możesz pożyczyć ją i Array, aby dokonać bezpośredniej zamiany zmiennych bez tworzenia zmiennej tymczasowej. Biorąc pod uwagę, że chcesz zamienić wartości a
i b
, możesz to zrobić a = [b][b = a,0]
. Spowoduje to umieszczenie prądu b
w Array. Drugi []
to notacja dostępu do właściwości. Indeks, do którego uzyskano dostęp, jest 0
, ale nie przed przypisaniem a
do b
, który jest teraz bezpieczny, ponieważ b
jest przechowywany w tablicy. ,
pozwala nam wykonać wiele wyrażeń w []
.
Odpowiedzi:
Poniższe prawdopodobnie nie są zbyt przydatne, ponieważ nie piszesz tego samodzielnie, ale minifier może zmniejszyć kod za pomocą operatora przecinka. Na przykład:
if(x){foo();return bar()}else{return 1}
stanie się:
return x?(foo(),bar()):1
? :
Operator może być używany teraz, ponieważ operator przecinek (do pewnego stopnia) pozwala na dwa oświadczenia mają być zapisane jako jeden oświadczeniu.
Jest to przydatne, ponieważ pozwala na pewną zgrabną kompresję (tutaj 39 -> 24 bajty).
Chciałbym podkreślić, że przecinek w nievar a, b
jest operatorem przecinka, ponieważ nie istnieje w wyrażeniu . Przecinek ma specjalne znaczenie w wypowiedziach . w wyrażeniu odnosiłoby się do dwóch zmiennych i oceniał do , co nie ma miejsca .var
a, b
b
var a, b
if (condition) var1 = val1, var2 = val2;
Osobiście uważam, że unikanie nawiasów, jeśli to możliwe, sprawia, że kod jest bardziej czytelny.
Operator przecinka umożliwia umieszczenie wielu wyrażeń w miejscu, w którym oczekiwane jest jedno wyrażenie. Wynikowa wartość wielu wyrażeń oddzielonych przecinkami będzie wartością ostatniego wyrażenia oddzielonego przecinkami.
Osobiście nie używam go zbyt często, ponieważ nie ma tak wielu sytuacji, w których oczekuje się więcej niż jednego wyrażenia i nie ma mniej zagmatwanego sposobu pisania kodu niż użycie operatora przecinka. Jedna interesująca możliwość znajduje się na końcu for
pętli, kiedy chcesz zwiększyć więcej niż jedną zmienną:
// 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
}
Tutaj widzisz, że i++, j++
można to umieścić w miejscu, w którym dozwolone jest jedno wyrażenie. W tym konkretnym przypadku wiele wyrażeń jest używanych do efektów bocznych, więc nie ma znaczenia, że wyrażenia złożone przyjmują wartość ostatniego, ale są inne przypadki, w których może to mieć znaczenie.
Operator przecinka jest często przydatny podczas pisania kodu funkcjonalnego w JavaScript.
Rozważ ten kod, który napisałem jakiś czas temu dla SPA, który miał coś podobnego do następującego
const actions = _.chain(options)
.pairs() // 1
.filter(selectActions) // 2
.map(createActionPromise) // 3
.reduce((state, pair) => (state[pair[0]] = pair[1], state), {}) // 4
.value();
To był dość złożony, ale prawdziwy scenariusz. Trzymaj się ze mną, gdy wyjaśniam, co się dzieje, i podczas tego procesu przedstaw argumenty dla operatora przecinka.
Rozłóż wszystkie opcje przekazane do tej funkcji za pomocą, pairs
która zamieni się { a: 1, b: 2}
w[['a', 1], ['b', 2]]
Ta tablica par właściwości jest filtrowana według tego, które z nich są uważane za „akcje” w systemie.
Następnie drugi indeks w tablicy jest zastępowany funkcją, która zwraca obietnicę reprezentującą tę akcję (za pomocą map
)
Na koniec wywołanie funkcji reduce
połączy każdą „tablicę właściwości” ( ['a', 1]
) z powrotem w ostateczny obiekt.
Efektem końcowym jest przekształcona wersja options
argumentu, która zawiera tylko odpowiednie klucze i których wartości są używane przez funkcję wywołującą.
Patrząc tylko
.reduce((state, pair) => (state[pair[0]] = pair[1], state), {})
Możesz zobaczyć, że funkcja redukcji zaczyna się od pustego obiektu stanu state
, a dla każdej pary reprezentującej klucz i wartość funkcja zwraca ten sam state
obiekt po dodaniu właściwości do obiektu odpowiadającego parze klucz / wartość. Ze względu na składnię funkcji strzałek ECMAScript 2015, treść funkcji jest wyrażeniem, w wyniku czego operator przecinka umożliwia zwięzłą i użyteczną funkcję „iteruj” .
Osobiście spotkałem się z wieloma przypadkami podczas pisania Javascript w bardziej funkcjonalnym stylu z ECMAScript 2015 + Arrow Functions. Powiedziawszy to, zanim napotkałem funkcje strzałkowe (takie jak w czasie pisania pytania), nigdy nie użyłem operatora przecinka w żaden celowy sposób.
reduce
.reduce((state, [key, value]) => (state[key] = value, state), {})
. I zdaję sobie sprawę, że to podważa cel odpowiedzi, ale .reduce((state, [key, value]) => Object.assign(state, { [key]: value }), {})
całkowicie wyeliminowałoby potrzebę stosowania operatora przecinka.
Innym zastosowaniem operatora przecinka jest ukrycie wyników, na których nie zależy nam w repl lub konsoli, wyłącznie dla wygody.
Na przykład, jeśli oceniasz myVariable = aWholeLotOfText
w repl lub konsoli, wydrukuje wszystkie dane, które właśnie przypisałeś. Mogą to być strony i strony, a jeśli wolisz ich nie widzieć, możesz zamiast tego ocenić myVariable = aWholeLotOfText, 'done'
, a repl / console po prostu wydrukuje „gotowe”.
Oriel słusznie wskazuje †, że dostosowywanie toString()
lub get()
funkcje mogą nawet sprawić, że będzie to przydatne.
Operator przecinka nie jest specyficzny dla JavaScript, jest dostępny w innych językach, takich jak C i C ++ . Jako operator binarny jest to przydatne, gdy pierwszy operand, który jest generalnie wyrażeniem, ma pożądany efekt uboczny wymagany przez drugi operand. Jeden przykład z Wikipedii:
i = a += 2, a + b;
Oczywiście możesz napisać dwa różne wiersze kodu, ale przecinek jest inną opcją i czasami jest bardziej czytelny.
Nie zgodziłbym się z Flanaganem i powiedziałbym, że przecinek jest naprawdę przydatny i pozwala pisać bardziej czytelny i elegancki kod, zwłaszcza gdy wiesz, co robisz:
Oto bardzo szczegółowy artykuł na temat używania przecinków:
Kilka przykładów z tego miejsca na dowód demonstracji:
function renderCurve() {
for(var a = 1, b = 10; a*b; a++, b--) {
console.log(new Array(a*b).join('*'));
}
}
Generator Fibonacciego:
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
Znajdź pierwszy element nadrzędny, odpowiednik .parent()
funkcji 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">
while ((el = el.parentNode) && (el.tagName != tagName.toUpperCase()))
w tym kontekście wystarczy.
Nie znalazłem praktycznego zastosowania tego innego niż to, ale oto jeden scenariusz, w którym James Padolsey ładnie używa tej techniki do wykrywania IE w pętli 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;
}());
Te dwie linie muszą zostać wykonane:
div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
all[0]
Wewnątrz operatora przecinka oba są oceniane, chociaż w jakiś sposób można by je rozdzielić.
do
- while
.
Jest coś „dziwnego”, co można zrobić w JavaScript wywołując funkcję pośrednio za pomocą operatora przecinka.
Tutaj jest długi opis: Pośrednie wywołanie funkcji w JavaScript
Używając tej składni:
(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);
}());
Możesz uzyskać dostęp do zmiennej globalnej, ponieważ eval
działa inaczej, gdy jest wywoływana bezpośrednio, a inaczej wywoływana pośrednio.
Zauważyłem, że operator przecinka jest najbardziej przydatny podczas pisania takich pomocników.
const stopPropagation = event => (event.stopPropagation(), event);
const preventDefault = event => (event.preventDefault(), event);
const both = compose(stopPropagation, preventDefault);
Możesz zamienić przecinek na || lub &&, ale wtedy musisz wiedzieć, co zwraca funkcja.
Co ważniejsze, separator przecinka komunikuje zamiar - kod nie dba o to, do czego oblicza lewy operand, podczas gdy alternatywy mogą mieć inny powód, dla którego istnieją. To z kolei ułatwia zrozumienie i refaktoryzację. Jeśli typ zwracanej funkcji kiedykolwiek się zmieni, powyższy kod nie ulegnie zmianie.
Oczywiście możesz osiągnąć to samo na inne sposoby, ale nie tak zwięźle. Jeśli || i && znalazły miejsce w powszechnym użyciu, podobnie jak operator przecinka.
tap
( ramdajs.com/docs/#tap ). Zasadniczo wykonujesz efekt uboczny, a następnie zwracasz wartość początkową; bardzo przydatne w programowaniu funkcjonalnym :)
Jednym z typowych przypadków, w których go używam, jest opcjonalna analiza argumentów. Myślę, że dzięki temu jest bardziej czytelny i zwięzły, dzięki czemu analiza argumentów nie dominuje w treści funkcji.
/**
* @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();
// ...
}
Powiedzmy, że masz tablicę:
arr = [];
Kiedy wchodzisz push
do tej tablicy, rzadko jesteś zainteresowany push
zwracaną wartością, a mianowicie nową długością tablicy, ale raczej samą tablicą:
arr.push('foo') // ['foo'] seems more interesting than 1
Używając operatora przecinka, możemy wypchnąć tablicę, określić tablicę jako ostatni operand przecinka, a następnie użyć wyniku - samej tablicy - do kolejnego wywołania metody tablicowej, rodzaj łączenia:
(arr.push('bar'), arr.push('baz'), arr).sort(); // [ 'bar', 'baz', 'foo' ]
Innym obszarem, w którym można użyć operatora przecinka, jest zaciemnianie kodu .
Powiedzmy, że programista pisze taki kod:
var foo = 'bar';
Teraz postanawia zaciemnić kod. Użyte narzędzie może zmienić kod w następujący sposób:
var Z0b=(45,87)>(195,3)?'bar':(54,65)>(1,0)?'':'baz';// Z0b == 'bar'
var i, j, k;
vsvar i; var j, var k
?