Respostas:
~
é um operador bit a bit que inverte todos os bits em seu operando.
Por exemplo, se seu número fosse 1
, sua representação binária do flutuador IEEE 754 (como JavaScript trata os números) seria ...
0011 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
Portanto, ~
converte seu operando em um número inteiro de 32 bits (operadores bit a bit em JavaScript fazem isso) ...
0000 0000 0000 0000 0000 0000 0000 0001
Se fosse um número negativo, seria armazenado no complemento de 2: inverta todos os bits e adicione 1.
... e depois vira todos os seus bits ...
1111 1111 1111 1111 1111 1111 1111 1110
Então, qual é a utilidade disso? Quando alguém poderia usá-lo?
Tem alguns usos. Se você está escrevendo coisas de baixo nível, é útil. Se você definiu o perfil do seu aplicativo e encontrou um gargalo, ele poderia ter um desempenho melhor usando truques bit a bit (como uma ferramenta possível em um pacote muito maior).
É também uma (geralmente) claro truque para transformar indexOf()
's encontrados valor de retorno em truthy (ao fazer não encontrado como Falsas ) e muitas vezes as pessoas usá-lo para seu efeito colateral de truncar números para 32 bits (e soltando sua casa decimal, duplicando-a, efetivamente o mesmo que Math.floor()
para números positivos).
Digo claro porque não é imediatamente óbvio para o que está sendo usado. Geralmente, você deseja que seu código se comunique claramente com outras pessoas que o leem. Embora o uso ~
possa parecer legal , geralmente é inteligente demais para o seu próprio bem. :)
Também é menos relevante agora que JavaScript Array.prototype.includes()
e String.prototype.includes()
. Eles retornam um valor booleano. Se a (s) sua (s) plataforma (s) de destino o suportarem, você deve preferir isso para testar a existência de um valor em uma string ou matriz.
value = value || default
, o JavaScript é um idioma comum e válido, desde que você saiba quando pode e não pode usá-lo.
v = t ? a : b;
. Eu acho isso muito mais claro do que var v; if (t} { v = a; } else { v = b; }
normalmente dividido em mais de 5 linhas e também mais claro do var v = b; if (t) { v = a; }
que o que normalmente seria 4+ linhas. Mas conheço muitas pessoas não familiarizadas com os ? :
operadores que preferem a segunda ou terceira via. Acho que o primeiro é mais legível. Eu concordo com o princípio geral, deixe o código claro, não use hacks. Eu acho que só fico ~v.indexOf('...')
muito claro depois de aprender.
~
idiomático. é tecnicamente parte das especificações do idioma , mas não faz parte do idioma em uso geral .
Usá-lo antes de uma indexOf()
expressão efetivamente fornece um resultado de verdade / falsidade em vez do índice numérico retornado diretamente.
Se o valor de retorno for -1
, então ~-1
é 0
porque-1
é uma sequência de todos os 1 bits. Qualquer valor maior ou igual a zero dará um resultado diferente de zero. Portanto,
if (~someString.indexOf(something)) {
}
causará o if
código seja executado quando "algo" estiver em "someString". Se você tentar usar .indexOf()
como um booleano diretamente, isso não funcionará porque, às vezes, retorna zero (quando "algo" está no início da string).
Obviamente, isso também funciona:
if (someString.indexOf(something) >= 0) {
}
e é consideravelmente menos misterioso.
Às vezes, você também verá isso:
var i = ~~something;
Usar o ~
operador duas vezes como esse é uma maneira rápida de converter uma string em um número inteiro de 32 bits. O primeiro ~
faz a conversão e o segundo ~
inverte os bits. Obviamente, se o operador for aplicado a algo que não pode ser convertido em um número, você obtém o NaN
resultado. ( editar - na verdade, é o segundo ~
que é aplicado primeiro, mas você entendeu.)
~
quando executado em números inteiros é igual a -(x + 1)
.
0
ser false
e ser diferente de zero true
remonta há muito tempo, pelo menos a C nos anos 70 e provavelmente muitas outras linguagens de programação de sistemas então contemporâneas. Provavelmente decorre da maneira como o hardware funciona; Muitas CPUs definem um bit zero após uma operação e possuem uma instrução de ramificação correspondente para testá-lo.
| 0
, nesse caso, sua única operação.
~~
mesma maneira.
O operador~
é Bitwise NOT , ~x
é aproximadamente o mesmo que -(x+1)
. É mais fácil entender, mais ou menos. Assim:
~2; // -(2+1) ==> -3
Considere -(x+1)
. -1
pode executar essa operação para produzir a 0
.
Em outras palavras, o ~
uso com um intervalo de valores numéricos produzirá um valor de falsificação (coagir a false
partir de 0
) apenas para o -1
valor de entrada; caso contrário, qualquer outro valor de verdade.
Como sabemos, -1
é comumente chamado de valor sentinela . Ele é usado para muitas funções que retornam >= 0
valores para o sucesso e -1
para a falha na linguagem C. Qual a mesma regra de retorno indexOf()
em JavaScript.
É comum verificar a presença / ausência de uma substring em outra string dessa maneira
var a = "Hello Baby";
if (a.indexOf("Ba") >= 0) {
// found it
}
if (a.indexOf("Ba") != -1) {
// found it
}
if (a.indexOf("aB") < 0) {
// not found
}
if (a.indexOf( "aB" ) == -1) {
// not found
}
No entanto, seria mais fácil fazê-lo ~
como abaixo
var a = "Hello Baby";
~a.indexOf("Ba"); // -7 -> truthy
if (~a.indexOf("Ba")) { // true
// found it
}
~a.indexOf("aB"); // 0 -> falsy
!~a.indexOf("aB"); // true
if (!~a.indexOf( "aB" )) { // true
// not found
}
-(x+1)
se a vi em uma declaração if. O til me diz exatamente o que está fazendo para compensar a natureza baseada em 0 do Javascript. Além disso, quanto menos parênteses, melhor para a leitura
if (a.indexOf("Ba") > -1) {// found} //true
qual, embora um pouco mais longo que os exemplos til, é consideravelmente menor do que os dois exemplos que você deu e é var opinion = !~-1 ? 'more' : 'less'
compreensível para novos programadores .
~indexOf(item)
aparece com bastante frequência, e as respostas aqui são ótimas, mas talvez algumas pessoas precisem saber como usá-lo e "pular" a teoria:
if (~list.indexOf(item)) {
// item in list
} else {
// item *not* in list
}
++
e --
porque eles "incentivar trickiness excessiva" e ainda de alguma forma ~
sobreviveram (à espreita nas sombras) github.com/airbnb/javascript/issues/540
list.indexOf(item) >= 0
ou ... > -1
já que o javascript é baseado em zero e não optou por resolver isso desde o início. Além disso, apenas a opinião (igual à do Airbnb), qualquer pessoa que esteja fazendo algo significativo em javascript sabe ++
e, embora --
seja menos comum, o significado pode ser inferido.
++
e --
em um tempo por causa de métodos primitivos como map
, forEach
etc. Meu ponto é mais sobre por que não também considerar ~
excessivamente complicado quando tudo o padrão usado inclui incremento e operadores decréscimo. Proibir algo para que o CIS101 não faça sentido.
Para aqueles que consideram usar o truque til para criar um valor verdadeiro a partir de um indexOf
resultado, é mais explícito e tem menos mágica para usar o includes
métodoString
.
'hello world'.includes('hello') //=> true
'hello world'.includes('kittens') //=> false
Observe que esse é um novo método padrão a partir do ES 2015, portanto não funcionará em navegadores mais antigos. Nos casos em que isso for importante, considere usar o polyfill String.prototype.includes .
Esse recurso também está disponível para matrizes usando a mesma sintaxe :
['apples', 'oranges', 'cherries'].includes('apples') //=> true
['apples', 'oranges', 'cherries'].includes('unicorns') //=> false
Aqui está o polyfill Array.prototype.includes, se você precisar de suporte mais antigo ao navegador.