O que a construção x = x || você quer dizer?


250

Estou depurando JavaScript e não consigo explicar o que isso ||faz?

function (title, msg) {
  var title = title || 'Error';
  var msg   = msg || 'Error on Request';
}

Alguém pode me dar uma dica, por que esse cara está usando var title = title || 'ERROR'? Às vezes, também o vejo sem vardeclaração.


44
As pessoas já responderam isso ... mas esteja extremamente ciente do fato de que o segundo valor será escolhido se o primeiro valor for falsy, não APENAS undefined. A quantidade de vezes que eu vi doWeDoIt = doWeDoIt || true, é suficiente para me fazer chorar. (ou seja, doWeDoItvai agora nunca será false)
Matt


4
Para aqueles com experiência em C #, o operador de canal duplo é equivalente ao operador de coalescência nula ??. O Javascript avalia objetos não nulos como true (ou melhor, avalia objetos nulos como false)
usr-local-ΕΨΗΕΛΩΝ

3
Não se sinta mal - o JS é a única linguagem pateta que permite essa horrível codificação ... isso e ensinando que é apropriado aninhar todas as funções em linhas de código e jogá-las fora, tornando-as descartáveis ​​e inutilizáveis ​​pela 2ª vez. :) Eu tenho 30 anos de codificação e não toquei em JS até pouco tempo atrás, e sinto sua dor tudo o que posso dizer é: mantenha uma folha de rosto "não faz sentido, é apenas em JS", é a única maneira de eu ' eu consegui! :)
Collin Chaffin

1
Por favor, considere alterar a resposta aceita na minha resposta .
Michał Perłakowski

Respostas:


210

Isso significa que o titleargumento é opcional. Portanto, se você chamar o método sem argumentos, ele usará o valor padrão de "Error".

É uma abreviação para escrever:

if (!title) {
  title = "Error";
}

Esse tipo de truque abreviado com expressões booleanas também é comum no Perl. Com a expressão:

a OR b

avalia truese um aou bé true. Portanto, se afor verdade, você não precisa verificar bnada. Isso é chamado de avaliação booleana de curto-circuito, portanto:

var title = title || "Error";

basicamente verifica se titleavalia para false. Se isso acontecer, ele "retorna" "Error", caso contrário, ele retorna title.


3
Desculpe ser exigente, mas o argumento não é opcional, o argumento é verificado
themightybun

4
Esta NÃO é a resposta e eu concordo com o último comentário que nem é opcional. Nenhuma parte desta resposta está correta, nem mesmo a referência Perl, pois a instrução Perl realmente faz SENSE e é avaliada de uma maneira completamente diferente. O JS é eval em um método lógico booleano muito mais "convertido" que eu também acho muito mais confuso para ler / escrever. A resposta abaixo intitulada "O que é o operador de tubo duplo" é na verdade uma resposta correta.
precisa saber é o seguinte

198

O que é o operador de tubo duplo ( ||)?

O operador de canal duplo ( ||) é o operador lógicoOR . Na maioria dos idiomas , funciona da seguinte maneira:

  • Se o primeiro valor for false, ele verifica o segundo valor. Se for true, ele retorna truee se é false, ele retorna false.
  • Se o primeiro valor for true, ele sempre retornará true, independentemente do segundo valor.

Então, basicamente, funciona como esta função:

function or(x, y) {
  if (x) {
    return true;
  } else if (y) {
    return true;
  } else {
    return false;
  }
}

Se você ainda não entende, veja esta tabela:

      | true   false  
------+---------------
true  | true   true   
false | true   false  

Em outras palavras, só é falso quando ambos os valores são falsos.

Como é diferente em JavaScript?

O JavaScript é um pouco diferente, porque é uma linguagem pouco digitada . Nesse caso, significa que você pode usar o ||operador com valores que não são booleanos. Embora não faça sentido, você pode usar este operador com, por exemplo, uma função e um objeto:

(function(){}) || {}

O que acontece lá?

Se os valores não forem booleanos, o JavaScript fará uma conversão implícita em booleano . Isso significa que, se o valor for Falsey (por exemplo 0, "", null, undefined(ver também Todos os valores Falsey no JavaScript )), que serão tratadas como false; caso contrário, é tratado como true.

Portanto, o exemplo acima deve dar true, porque a função vazia é verdadeira. Bem, não. Retorna a função vazia. Isso ||ocorre porque o operador do JavaScript não funciona como eu escrevi no começo. Funciona da seguinte maneira:

  • Se o primeiro valor for falsey , ele retornará o segundo valor .
  • Se o primeiro valor for verdadeiro , ele retornará o primeiro valor .

Surpreso? Na verdade, é "compatível" com o ||operador tradicional . Pode ser escrito da seguinte forma:

function or(x, y) {
  if (x) {
    return x;
  } else {
    return y;
  }
}

Se você passar um valor verdadeiro como x, ele retornará x, ou seja, um valor verdadeiro. Portanto, se você usá-lo posteriormente na ifcláusula:

(function(x, y) {
  var eitherXorY = x || y;
  if (eitherXorY) {
    console.log("Either x or y is truthy.");
  } else {
    console.log("Neither x nor y is truthy");
  }
}(true/*, undefined*/));

você recebe "Either x or y is truthy.".

Se xfosse falsey, eitherXorYseria y. Nesse caso, você obteria o "Either x or y is truthy."if yera verdade; caso contrário, você receberia "Neither x nor y is truthy".

A questão real

Agora, quando você souber como o ||operador funciona, provavelmente poderá entender por si mesmo o que x = x || ysignifica. Se xé verdade, xé atribuído a x, então, na verdade, nada acontece; caso contrário, yé atribuído a x. É comumente usado para definir parâmetros padrão nas funções. No entanto, muitas vezes é considerada uma má prática de programação , porque impede que você passe um valor de falsey (que não é necessariamente undefinedou null) como parâmetro. Considere o seguinte exemplo:

function badFunction(/* boolean */flagA) {
  flagA = flagA || true;
  console.log("flagA is set to " + (flagA ? "true" : "false"));
}

Parece válido à primeira vista. No entanto, o que aconteceria se você passasse falsecomo flagAparâmetro (já que é booleano, ou seja, pode ser trueou false)? Isso se tornaria true. Neste exemplo, não há nenhuma maneira para definir flagAa false.

Seria uma idéia melhor verificar explicitamente se flagAé undefinedassim:

function goodFunction(/* boolean */flagA) {
  flagA = typeof flagA !== "undefined" ? flagA : true;
  console.log("flagA is set to " + (flagA ? "true" : "false"));
}

Embora seja mais longo, sempre funciona e é mais fácil de entender.


Você também pode usar a sintaxe ES6 para os parâmetros de função padrão , mas observe que ela não funciona em navegadores mais antigos (como o IE). Se você deseja oferecer suporte a esses navegadores, transpile seu código com o Babel .

Consulte também Operadores lógicos no MDN .


13
+1 - de longe a resposta mais correta e completa. E, para aqueles com essa pergunta (alguns de nós, programadores veteranos novos no JS incluídos), certamente devemos concentrar o máximo de toda essa resposta nesta linha: "Embora não faça sentido", porque esse "tipo de loosley" simplesmente nunca fará sentido para aqueles de nós que cresceram sem ele. Para nós, um operador booleano é exatamente isso e SOMENTE isso ...... e quem pensou que seria uma boa ideia ter que parar e pensar em alguma conversão maluca de valores não-booleanos em booleanos durante a leitura / gravação de código , esqueci de tomar seus remédios naquele dia! :)
Collin Chaffin

2
+1, em poucas palavras: title = title || 'Error'significaif (title) { title = title; } else { title = 'Error'; }
Andre Elrico 19/02/19

Na verdade, eu não concordo com a linha "embora não faça sentido". Entendo que a linha não seria compilada em C, por exemplo, mas é bem compreendida se você veio do Ruby, por exemplo, ou até do Groovy. Em Ruby você pode expressar ainda mais title ||= 'Error',.
Elliot Nelson

28

Se o título não estiver definido, use 'ERRO' como valor padrão.

Mais genérico:

var foobar = foo || default;

Lê: defina foobar como fooou default. Você pode encadear isso várias vezes:

var foobar = foo || bar || something || 42;

1
Achei confuso porque as variáveis ​​têm o mesmo nome. Muito mais fácil quando não o fazem.
Norbert Norbertson

14

Explicando isso um pouco mais ...

O ||operador é o oroperador lógico . O resultado é verdadeiro se a primeira parte é verdadeira e é verdade se a segunda parte é verdadeira e é verdade se ambas as partes são verdadeiras. Para maior clareza, aqui está uma tabela:

 X | Y | X || Y 
---+---+--------
 F | F |   F    
---+---+--------
 F | T |   T    
---+---+--------
 T | F |   T    
---+---+--------
 T | T |   T    
---+---+--------

Agora percebe algo aqui? Se Xfor verdade, o resultado é sempre verdadeiro. Portanto, se sabemos que isso Xé verdade, não precisamos verificar Ynada. Muitas linguagens, portanto, implementam avaliadores de "curto-circuito" para lógicos or(e lógicos) andvindos de outra direção. Eles verificam o primeiro elemento e, se isso for verdade, não se incomodam em verificar o segundo. O resultado (em termos lógicos) é o mesmo, mas em termos de execução há potencialmente uma enorme diferença se o segundo elemento for caro de calcular.

Então, o que isso tem a ver com o seu exemplo?

var title   = title || 'Error';

Vamos olhar para isso. O titleelemento é passado para sua função. No JavaScript, se você não passar um parâmetro, o padrão será um valor nulo. Também em JavaScript, se sua variável for um valor nulo, ela será considerada falsa pelos operadores lógicos. Portanto, se essa função é chamada com um título fornecido, é um valor não falso e, portanto, é atribuído à variável local. Se, no entanto, não receber um valor, será um valor nulo e, portanto, falso. O oroperador lógico avalia então a segunda expressão e retorna 'Erro'. Então agora a variável local recebe o valor 'Erro'.

Isso funciona devido à implementação de expressões lógicas em JavaScript. Ele não retorna um valor booleano adequado ( trueou false), mas retorna o valor que foi fornecido sob algumas regras sobre o que é considerado equivalente truee o que é considerado equivalente false. Procure sua referência JavaScript para saber o que o JavaScript considera verdadeiro ou falso em contextos booleanos.


8

Tubo duplo significa "OR" lógico. Este não é realmente o caso quando o "parâmetro não está definido", pois estritamente no javascript, se você tiver um código como este:

function foo(par) {
}

Então chama

foo()
foo("")
foo(null)
foo(undefined)
foo(0)

não são equivalentes.

O pipe duplo (||) converterá o primeiro argumento em booleano e, se o resultado booleano for verdadeiro - faça a atribuição, caso contrário, ele atribuirá a parte correta.

Isso importa se você verificar o parâmetro não definido.

Digamos que temos uma função setSalary que possui um parâmetro opcional. Se o usuário não fornecer o parâmetro, o valor padrão 10 deve ser usado.

se você fizer a verificação assim:

function setSalary(dollars) {
    salary = dollars || 10
}

Isso dará resultados inesperados de plantão, como

setSalary(0) 

Ele ainda definirá os 10 seguindo o fluxo descrito acima.


8

Basicamente, verifica se o valor antes do || avalia como true; se sim, ele aceita esse valor; se não, ele aceita o valor após o ||.

Valores para os quais ele assumirá o valor após o || (Até onde eu lembro):

  • Indefinido
  • falso
  • 0 0
  • '' (String nula ou nula)

1
falso || null || indefinido || 0 || '' || 'você esqueceu null'
Dziamid 16/05

7

Embora a resposta de Cletus esteja correta, sinto que mais detalhes devem ser adicionados em relação a "avalia como falso" em JavaScript.

var title = title || 'Error';
var msg   = msg || 'Error on Request';

Não está apenas verificando se o título / msg foi fornecido, mas também se algum deles é falso . ou seja, um dos seguintes:

  • falso.
  • 0 (zero)
  • "" (sequência vazia)
  • nulo.
  • Indefinido.
  • NaN (um valor numérico especial que significa Não é um número!)

Então na fila

var title = title || 'Error';

Se o título é verdadeiro (ou seja, não é falso, então title = "titleMessage" etc.), o operador booleano OR (||) encontrou um valor 'verdadeiro', o que significa que ele é avaliado como verdadeiro, portanto, causa um curto-circuito e retorna o valor verdadeiro (título).

Se o título for falso (ou seja, um da lista acima), o operador booleano OR (||) encontrou um valor 'falso' e agora precisa avaliar a outra parte do operador, 'Erro', que avalia como verdadeiro e, portanto, é retornado.

Também parece (após algumas experiências rápidas com o console do firebug) se os dois lados do operador avaliam como falso, ele retorna o segundo operador 'falso'.

ie

return ("" || undefined)

retorna indefinido, provavelmente isso permitirá que você use o comportamento questionado nesta pergunta ao tentar usar o título / mensagem padrão como "". ou seja, depois de correr

var foo = undefined
foo = foo || ""

foo seria definido como ""


5

operador de tubo duplo

este exemplo é útil?

var section = document.getElementById('special');
if(!section){
     section = document.getElementById('main');
}

pode ser também

var section = document.getElementById('special') || document.getElementById('main');

4

Para adicionar uma explicação a tudo o que foi dito antes, devo dar alguns exemplos para entender os conceitos lógicos.

var name = false || "Mohsen"; # name equals to Mohsen
var family = true || "Alizadeh" # family equals to true

Isso significa que, se o lado esquerdo avaliado como uma afirmação verdadeira, ele será finalizado e o lado esquerdo será retornado e atribuído à variável. em outros casos, o lado direito será retornado e atribuído.

E o operador tem a estrutura oposta, como abaixo.

var name = false && "Mohsen" # name equals to false
var family = true && "Alizadeh" # family equals to Alizadeh

3

|| é o operador OR booleano. Como no javascript, undefined, null, 0, false são considerados como valores false .

Significa simplesmente

true || true = true
false || true = true
true || false = true
false || false = false

undefined || "value" = "value"
"value" || undefined = "value"
null || "value" = "value"
"value" || null = "value"
0 || "value" = "value"
"value" || 0 = "value"
false || "value" = "value"
"value" || false = "value"

2

Citação: "O que a construção x = x || y significa?"

Atribuindo um valor padrão.

Isso significa fornecer um valor padrão de y a x , caso x ainda esteja aguardando seu valor, mas ainda não o tenha recebido ou tenha sido deliberadamente omitido para retornar ao padrão.


Esse é o significado exato da construção e o único significado dela. E foi amplamente como uma sub-rotina na escrita de funções que poderiam ser buscadas como protótipos, funções independentes e também como métodos emprestados para serem aplicados em outro elemento. Onde seu principal e único dever era modificar a referência do alvo. Exemplo: function getKeys(x) { x = x || this ; .... }que pode ser usado sem modificação como uma função autônoma, como um método de propriedade em protótipos e como um método de um elemento que pode obter outro elemento como argumento como `[elemento] .getKeys (anotherElement);`
Bekim Bacaj

-5

E tenho que acrescentar mais uma coisa: esse pedaço de taquigrafia é uma abominação. Utiliza incorretamente uma otimização acidental do intérprete (não se incomoda com a segunda operação, se a primeira for verdadeira) para controlar uma atribuição. Esse uso não tem nada a ver com o objetivo do operador. Não acredito que deva ser usado.

Prefiro o operador ternário para inicialização, por exemplo,

var title = title?title:'Error';

Isso usa uma operação condicional de uma linha para sua finalidade correta. Ele ainda joga jogos desagradáveis ​​com veracidade, mas isso é Javascript para você.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.