O que ~~ ("double til") faz em Javascript?


Respostas:


248

Ele remove tudo após o ponto decimal porque os operadores bit a bit implicitamente convertem seus operandos em números inteiros de 32 bits assinados. Isso funciona se os operandos são números ou cadeias (ponto flutuante) e o resultado é um número.

Em outras palavras, produz:

function(x) {
  if(x < 0) return Math.ceil(x);
  else return Math.floor(x);
}

somente se x estiver entre - (2 31 ) e 2 31 - 1. Caso contrário, ocorrerá um estouro e o número será "contornado".

Isso pode ser considerado útil para converter o argumento de seqüência de caracteres de uma função em um número, mas, devido à possibilidade de estouro e por estar incorreto para uso com números não inteiros, eu não o usaria dessa maneira, exceto para "code golf" ( ou seja, cortar inutilmente os bytes do código-fonte do seu programa em detrimento da legibilidade e robustez). Eu usaria +xou Number(x)não.


Como esse é o NÃO do NÃO

O número -43,2, por exemplo, é:

-43,2 10 = 11111111111111111111111111010101 2

como um número binário de 32 bits assinado (complemento de dois). (JavaScript ignora o que está depois do ponto decimal.) A inversão dos bits fornece:

NÃO -43 10 = 000000000000000000000000000000101010 2 = 42 10

A inversão novamente fornece:

NÃO 42 10 = 11111111111111111111111111010101 2 = -43 10

Isso difere de Math.floor(-43.2)que os números negativos são arredondados para zero, não para longe dele. (A função de piso, que seria igual a -44, sempre arredonda para o próximo número inteiro inferior, independentemente de o número ser positivo ou negativo.)


6
Ou seja, ~~é uma maneira abreviada (e possivelmente uma boa solução?) Para criar uma função truncada , mas obviamente em javascript .
Ruffin

4
JSLint irá reclamar sobre o uso de ~~.
Richard Cook

1
Tente Math.trunc ()
Xitalogy

30

O primeiro operador ~ força o operando a um número inteiro (possivelmente após coagir o valor a uma string ou a um valor booleano) e depois inverte os 31 bits mais baixos. Oficialmente, os números do ECMAScript são todos de ponto flutuante, mas alguns são implementados como números inteiros de 31 bits no mecanismo SpiderMonkey.

Você pode usá-lo para transformar uma matriz de 1 elemento em um número inteiro. Os pontos flutuantes são convertidos de acordo com a regra C, ie. truncamento da parte fracionária.

O segundo operador ~ inverte os bits de volta, para que você saiba que terá um número inteiro. Isso não é o mesmo que coagir um valor para booleano em uma declaração de condição, porque um objeto vazio {} é avaliado como verdadeiro, enquanto ~~ {} é avaliado como falso.

js>~~"yes"
0
js>~~3
3
js>~~"yes"
0
js>~~false
0
js>~~""
0
js>~~true
1
js>~~"3"
3
js>~~{}
0
js>~~{a:2}
0
js>~~[2]
2
js>~~[2,3]
0
js>~~{toString: function() {return 4}}
4
js>~~NaN
0
js>~~[4.5]
4
js>~~5.6
5
js>~~-5.6
-5

1
Obrigado por todos os exemplos aqui Shanti, realmente ajudou!
Shane Tomlinson

6
também~~undefined // 0
rampion

1
Também~~null // 0
chovy 03/08

Tecnicamente, você tem a ordem errada. O segundo ~faz o que você descreveu o primeiro ~e vice-versa. O ~operador é um operador unário e é interoperado da direita para a esquerda ~~Xe ~(~X)não como (~~)X(o que seria um erro de sintaxe)
yunzen 15/06

20

No ECMAScript 6, o equivalente a ~~é Math.trunc :

Retorna a parte integral de um número removendo quaisquer dígitos fracionários. Não arredonda nenhum número.

Math.trunc(13.37)   // 13
Math.trunc(42.84)   // 42
Math.trunc(0.123)   //  0
Math.trunc(-0.123)  // -0
Math.trunc("-1.123")// -1
Math.trunc(NaN)     // NaN
Math.trunc("foo")   // NaN
Math.trunc()        // NaN

O polyfill:

function trunc(x) {
    return x < 0 ? Math.ceil(x) : Math.floor(x);
}

6
Surpreendentemente, o ~~ é mais rápido que o Math.trunc, jsperf.com/math-trunc-vs-double-bitwise-not-operator . No entanto, nem tudo é sobre velocidade; legibilidade também.
Gajus

3
Existe uma diferença importante entre ~~ e Math.trunc: se você passar uma string, ou NaN ou qualquer coisa que não seja um número, Math.trunc retornará NaN e ~~ sempre retornará um número; nesses casos, ele retornará 0.
Buzinas

O Math.trunc é um pouco mais rápido que o ~~ no Chrome 59+, de acordo com jsperf.com/math-trunc-vs-double-bitwise-not-operator .
Jack Steam



4

Apenas um aviso. As outras respostas aqui me causaram alguns problemas.

A intenção é remover qualquer coisa após o ponto decimal de um número de ponto flutuante, mas há alguns casos de canto que o tornam um risco de bug. Eu recomendo evitar ~~.

Primeiro, o ~~ não funciona em números muito grandes.

~~1000000000000 == -727279968

Como alternativa, use Math.trunc()(como Gajus mencionou, Math.trunc()retorna a parte inteira de um número de ponto flutuante, mas só está disponível no JavaScript compatível com ECMAScript 6). Você sempre pode criar seus próprios ambientes Math.trunc()não-ECMAScript-6 fazendo o seguinte:

if(!Math.trunc){
    Math.trunc = function(value){
        return Math.sign(value) * Math.floor(Math.abs(value));
    }
}

Eu escrevi um post sobre isso para referência: http://bitlords.blogspot.com/2016/08/the-double-tilde-x-technique-in.html


1

Aqui está um exemplo de como esse operador pode ser usado com eficiência, onde faz sentido usá-lo:

leftOffset = -(~~$('html').css('padding-left').replace('px', '') + ~~$('body').css('margin-left').replace('px', '')),

Fonte:

Consulte a seção Interagindo com pontos


1

Convertendo seqüências de caracteres em números

console.log(~~-1);    // -1
console.log(~~0);     // 0
console.log(~~1);     // 1
console.log(~~"-1");  // -1
console.log(~~"0");   // 0
console.log(~~"1");   // 1
console.log(~~true);  // 1
console.log(~~false); // 0

~ -1 é 0

if (~someStr.indexOf("a")) {
  // Found it
} else  {
  // Not Found
}

fonte


1

Tilde (~) tem um algorihm - (N + 1)

Por exemplo:

~0 = -(0+1) = -1
~5 = -(5+1) = -6
~-7 = -(-7+1) = 6

O til duplo é - (- (N + 1) +1)

Por exemplo:

~~5 = -(-(5+1)+1) = 5
~~-3 = -(-(-3+1)+1) = -3

O til triplo é - (- (- (N + 1) +1) +1)

Por exemplo:

~~~2 = -(-(-(2+1)+1)+1) = -3
~~~3 = -(-(-(3+1)+1)+1) = -4
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.