Eu li esta pergunta sobre o "operador de vírgula" em expressões ( ,
) e os documentos MDN sobre ele, mas não consigo pensar em um cenário em que seja útil.
Então, quando o operador vírgula é útil?
Eu li esta pergunta sobre o "operador de vírgula" em expressões ( ,
) e os documentos MDN sobre ele, mas não consigo pensar em um cenário em que seja útil.
Então, quando o operador vírgula é útil?
,
operadora. Essa linha também é válida em C#
, mas a ,
operadora não existe lá.
,
nem sempre é o ,
operador (e nunca é o ,
operador em C #). Portanto, pode faltar um ,
operador ao C # , embora ainda seja usado livremente ,
como parte da sintaxe.
,
não é amplamente usado (e nem toda ocorrência de a ,
é o operador vírgula) . Mas você pode pegá-lo e um Array emprestados para fazer uma troca de variável embutida sem criar uma variável temporária. Dado que você deseja trocar os valores de a
e b
, você pode fazer a = [b][b = a,0]
. Isso coloca a corrente b
no Array. A segunda []
é a notação de acesso à propriedade. O índice acessado é 0
, mas não antes de ser atribuído a
a b
, que agora é seguro, pois b
é retido no Array. o ,
nos permite fazer as expressões múltiplas no []
.
Respostas:
O que se segue provavelmente não é muito útil, pois você não o escreve sozinho, mas um minificador pode reduzir o código usando o operador vírgula. Por exemplo:
if(x){foo();return bar()}else{return 1}
se tornaria:
return x?(foo(),bar()):1
O ? :
operador pode ser usado agora, já que o operador vírgula (até certo ponto) permite que duas instruções sejam escritas como uma única instrução.
Isso é útil porque permite uma compressão precisa (39 -> 24 bytes aqui).
Gostaria de enfatizar o fato de que a vírgula in nãovar a, b
é o operador vírgula porque não existe em uma expressão . A vírgula tem um significado especial nas declarações . em uma expressão estaria se referindo às duas variáveis e avaliada , o que não é o caso de .var
a, b
b
var a, b
if (condition) var1 = val1, var2 = val2;
eu pessoalmente acho que evitar colchetes sempre que possível torna o código mais legível.
O operador vírgula permite que você coloque várias expressões em um lugar onde uma expressão é esperada. O valor resultante de várias expressões separadas por uma vírgula será o valor da última expressão separada por vírgula.
Eu pessoalmente não o uso com muita frequência porque não há muitas situações em que mais de uma expressão seja esperada e não há uma maneira menos confusa de escrever o código do que usando o operador vírgula. Uma possibilidade interessante é no final de um for
loop, quando você deseja que mais de uma variável seja incrementada:
// 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
}
Aqui você vê que i++, j++
pode ser colocado em um local onde uma expressão é permitida. Nesse caso específico, as expressões múltiplas são usadas para efeitos colaterais, portanto, não importa se as expressões compostas assumem o valor da última, mas há outros casos em que isso pode realmente importar.
O Operador de vírgula é frequentemente útil ao escrever código funcional em Javascript.
Considere este código que escrevi para um SPA um tempo atrás, que tinha algo como o seguinte
const actions = _.chain(options)
.pairs() // 1
.filter(selectActions) // 2
.map(createActionPromise) // 3
.reduce((state, pair) => (state[pair[0]] = pair[1], state), {}) // 4
.value();
Este era um cenário bastante complexo, mas do mundo real. Tenha paciência enquanto eu explico o que está acontecendo e, no processo, explique o caso para o Operador de vírgula.
Desmontar todas as opções passadas para esta função usando o pairs
que se transformará { a: 1, b: 2}
em[['a', 1], ['b', 2]]
Essa matriz de pares de propriedades é filtrada por aqueles que são considerados "ações" no sistema.
Em seguida, o segundo índice na matriz é substituído por uma função que retorna uma promessa que representa essa ação (usando map
)
Finalmente, a chamada para reduce
mesclará cada "array de propriedade" ( ['a', 1]
) de volta em um objeto final.
O resultado final é uma versão transformada do options
argumento, que contém apenas as chaves apropriadas e cujos valores são consumíveis pela função de chamada.
Olhando apenas
.reduce((state, pair) => (state[pair[0]] = pair[1], state), {})
Você pode ver que a função de redução começa com um objeto de estado vazio,, state
e para cada par que representa uma chave e um valor, a função retorna o mesmo state
objeto após adicionar uma propriedade ao objeto correspondente ao par chave / valor. Por causa da sintaxe da função de seta do ECMAScript 2015, o corpo da função é uma expressão e, como resultado, o Operador de vírgula permite uma função de "iteração" concisa e útil .
Pessoalmente, encontrei vários casos ao escrever Javascript em um estilo mais funcional com ECMAScript 2015 + Funções de seta. Dito isso, antes de encontrar funções de seta (como no momento em que escrevi a pergunta), nunca usei o operador vírgula de forma deliberada.
reduce
.reduce((state, [key, value]) => (state[key] = value, state), {})
. E eu percebo que isso vai contra o propósito da resposta, mas .reduce((state, [key, value]) => Object.assign(state, { [key]: value }), {})
eliminaria totalmente a necessidade do operador vírgula.
Outro uso do operador vírgula é ocultar resultados indesejados no repl ou no console, apenas por conveniência.
Por exemplo, se você avaliar myVariable = aWholeLotOfText
no repl ou console, ele imprimirá todos os dados que você acabou de atribuir. Isso pode ser páginas e páginas, e se você preferir não ver, você pode avaliar myVariable = aWholeLotOfText, 'done'
, e o repl / console imprimirá apenas 'concluído'.
Oriel aponta corretamente † que funções toString()
ou customizadas get()
podem até tornar isso útil.
O operador vírgula não é específico do JavaScript, ele está disponível em outras linguagens como C e C ++ . Como um operador binário, isso é útil quando o primeiro operando, que geralmente é uma expressão, tem o efeito colateral desejado exigido pelo segundo operando. Um exemplo da wikipedia:
i = a += 2, a + b;
Obviamente, você pode escrever duas linhas de código diferentes, mas usar vírgulas é outra opção e às vezes mais legível.
Eu discordaria de Flanagan e diria que a vírgula é realmente útil e permite escrever um código mais legível e elegante, especialmente quando você sabe o que está fazendo:
Aqui está o artigo bastante detalhado sobre o uso de vírgulas:
Vários exemplos de lá para a prova de demonstração:
function renderCurve() {
for(var a = 1, b = 10; a*b; a++, b--) {
console.log(new Array(a*b).join('*'));
}
}
Um gerador de fibonacci:
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
Encontre o primeiro elemento pai, análogo à .parent()
função 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()))
seria ótimo nesse contexto.
Não encontrei outro uso prático disso, mas aqui está um cenário em que James Padolsey usa muito bem essa técnica para detecção de IE em um loop 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;
}());
Essas duas linhas devem ser executadas:
div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
all[0]
E dentro do operador vírgula, ambos são avaliados, embora alguém pudesse tê-los feito instruções separadas de alguma forma.
do
- while
loop.
Existe algo "estranho" que pode ser feito em JavaScript chamando uma função indiretamente usando o operador vírgula.
Há uma longa descrição aqui: Chamada de função indireta em JavaScript
Usando esta sintaxe:
(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);
}());
Você pode obter acesso à variável global porque eval
funciona de maneira diferente quando chamado diretamente vs chamado indiretamente.
Achei o operador vírgula mais útil ao escrever auxiliares como este.
const stopPropagation = event => (event.stopPropagation(), event);
const preventDefault = event => (event.preventDefault(), event);
const both = compose(stopPropagation, preventDefault);
Você pode substituir a vírgula por um || ou &&, mas então você precisa saber o que a função retorna.
Mais importante do que isso, o separador de vírgula comunica a intenção - o código não se importa com o que o operando esquerdo avalia, enquanto as alternativas podem ter outro motivo para estar lá. Isso, por sua vez, torna mais fácil entender e refatorar. Se o tipo de retorno da função mudar, o código acima não será afetado.
Naturalmente, você pode conseguir o mesmo de outras maneiras, mas não de forma tão sucinta. Se || e && encontrou um lugar de uso comum, assim também pode o operador vírgula.
tap
( ramdajs.com/docs/#tap ). Essencialmente, você está executando um efeito colateral e, em seguida, retornando o valor inicial; muito útil na programação funcional :)
Um caso típico que acabo usando é durante a análise opcional do argumento. Acho que o torna mais legível e mais conciso para que a análise do argumento não domine o corpo da função.
/**
* @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();
// ...
}
Digamos que você tenha uma matriz:
arr = [];
Quando você push
entra nessa matriz, raramente está interessado no push
valor de retorno de, ou seja, o novo comprimento da matriz, mas sim na própria matriz:
arr.push('foo') // ['foo'] seems more interesting than 1
Usando o operador vírgula, podemos enviar para a matriz, especificar a matriz como o último operando a vírgula e, em seguida, usar o resultado - a própria matriz - para uma chamada de método de matriz subsequente, uma espécie de encadeamento:
(arr.push('bar'), arr.push('baz'), arr).sort(); // [ 'bar', 'baz', 'foo' ]
Outra área onde o operador vírgula pode ser usado é a Ofuscação de código .
Digamos que um desenvolvedor escreva algum código como este:
var foo = 'bar';
Agora, ela decide ofuscar o código. A ferramenta usada pode alterar o código assim:
var Z0b=(45,87)>(195,3)?'bar':(54,65)>(1,0)?'':'baz';// Z0b == 'bar'
var i, j, k;
vsvar i; var j, var k
?