Eu estava olhando o código da Mozilla que adiciona um método de filtro ao Array e ele tinha uma linha de código que me confundia.
var len = this.length >>> 0;
Eu nunca vi >>> usado em JavaScript antes.
O que é isso e o que isso faz?
javascript
operators
bit-shift
Kenneth J
fonte
fonte
Array.prototype.push
/Array.prototype.pop
- hexmen.com/blog/2006/12/push-and-pop (embora ele tenha feito os testes, haha).Respostas:
Ele não converte apenas não-números em número, mas também em números que podem ser expressos como ints não assinados de 32 bits.
Embora os números de JavaScript são bóias de precisão dupla (*), os operadores bit a bit (
<<
,>>
,&
,|
e~
) são definidos em termos de operações sobre inteiros de 32 bits. Fazer uma operação bit a bit converte o número em um int assinado de 32 bits, perdendo frações e bits de posição superior a 32, antes de fazer o cálculo e depois converter novamente em Number.Portanto, fazer uma operação bit a bit sem efeito real, como um deslocamento para a direita de 0 bits
>>0
, é uma maneira rápida de arredondar um número e garantir que ele esteja no intervalo int de 32 bits. Além disso, o>>>
operador triplo , depois de fazer sua operação não assinada, converte os resultados de seu cálculo em Number como um número inteiro não assinado, em vez do número inteiro assinado que os outros, para que possa ser usado para converter negativos no complemento de 32 bits e dois versão como um número grande. Usar>>>0
garante que você tenha um número inteiro entre 0 e 0xFFFFFFFF.Nesse caso, isso é útil porque o ECMAScript define índices de matriz em termos de entradas não assinadas de 32 bits. Portanto, se você estiver tentando implementar
array.filter
de uma maneira que duplique exatamente o que o padrão ECMAScript Fifth Edition diz, você converterá o número em int não assinado de 32 bits dessa maneira.(Na realidade, há pouca necessidade prática para isso, espero que as pessoas não vão estar definindo
array.length
a0.5
,-1
,1e21
ou'LEMONS'
. Mas isso é JavaScript autores que estamos falando, então nunca se sabe ...)Resumo:
(*: bem, eles são definidos como se comportando como carros alegóricos. Não me surpreenderia se algum mecanismo JavaScript realmente usasse ints quando pudesse, por razões de desempenho. Mas isso seria um detalhe de implementação que você não faria nada vantagem de.)
fonte
RangeError: invalid array length
.Array.prototype.filter.call
), portanto,array
pode não ser realmente realArray
: pode ser alguma outra classe definida pelo usuário. (Infelizmente, não pode ser um NodeList confiável, que é quando você realmente deseja fazer isso, pois é um objeto host. Isso deixa o único lugar em que você realmente faz isso comoarguments
pseudo-matriz.)if
afirmação disso ao tentar identificar que o lado esquerdo da avaliação não era um int?'lemons'>>>0 === 0 && 0 >>>0 === 0
avalia como verdadeiro? mesmo que limões seja obviamente uma palavra ..?O operador de deslocamento à direita não assinado é usado em todas as implementações de métodos do Mozilla para todo o array extra , para garantir que a
length
propriedade seja um número inteiro de 32 bits não assinado .A
length
propriedade dos objetos de matriz é descrita na especificação como:Esse operador é a maneira mais curta de alcançá-lo; os métodos de matriz interna usam a
ToUint32
operação, mas esse método não está acessível e existe na especificação para fins de implementação.As implementações extras do array Mozilla tentam ser compatíveis com ECMAScript 5 , veja a descrição do
Array.prototype.indexOf
método (§ 15.4.4.14):Como você pode ver, eles apenas querem reproduzir o comportamento do
ToUint32
método para estar em conformidade com as especificações do ES5 em uma implementação do ES3 e, como eu disse antes, o operador de mudança à direita não assinado é a maneira mais fácil.fonte
ToUint32
parece um pouco desnecessário.Array.prototype
métodos é intencionalmente genérica , eles podem ser usados em objetos de matriz, por exemploArray.prototype.indexOf.call({0:'foo', 1:'bar', length: 2}, 'bar') == 1;
. Oarguments
objeto também é um bom exemplo. Para objetos puros de array, é impossível alterar o tipo dalength
propriedade, porque eles implementam um método interno [[Put
]] especial e, quando uma atribuição é feita àlength
propriedade, ela é convertida novamenteToUint32
e outras ações são executadas, como a exclusão de índices acima. o novo comprimento ...Esse é o operador de mudança de bit certo não assinado . A diferença entre este e o operador de mudança de bit direito assinado é que o operador de mudança de bit direito não assinado ( >>> ) preenche os zeros da esquerda e o operador de mudança de bit direito assinado ( >> ) preenche o bit de sinal, portanto preservando o sinal do valor numérico quando deslocado.
fonte
>>>
converte em um número inteiro, o que é unário+
.Driis explicou suficientemente o que é o operador e o que ele faz. Aqui está o significado por trás disso / por que foi usado:
Mudar qualquer direção por do
0
retorna o número original e será convertidonull
em0
. Parece que o código de exemplo que você está visualizando está usandothis.length >>> 0
para garantir quelen
seja numérico, mesmo quethis.length
não esteja definido.Para muitas pessoas, as operações bit a bit não são claras (e Douglas Crockford / jslint sugere não usar essas coisas). Isso não significa que é errado, mas existem métodos mais favoráveis e familiares para tornar o código mais legível. Uma maneira mais clara para garantir que
len
é0
é qualquer um dos dois métodos seguintes.ou
fonte
NaN
.. Ex+{}
... É provavelmente o melhor para combinar os dois:+length||0
>>>
é o unsigned operador de deslocamento para a direita ( ver p. 76 da especificação JavaScript 1,5 ), ao contrário do>>
, o assinado do operador deslocamento para a direita.>>>
altera os resultados da mudança de números negativos porque não preserva o bit de sinal ao mudar . As conseqüências disso podem ser entendidas por exemplo, a partir de um interpretador:Portanto, o que provavelmente deve ser feito aqui é obter o comprimento, ou 0, se o comprimento for indefinido ou não for um número inteiro, conforme o
"cabbage"
exemplo acima. Eu acho que, neste caso, é seguro assumir quethis.length
nunca será< 0
. No entanto, eu argumentaria que este exemplo é um truque desagradável , por duas razões:O comportamento de
<<<
usar números negativos, um efeito colateral provavelmente não intencional (ou provável de ocorrer) no exemplo acima.A intenção do código não é óbvia , como verifica a existência dessa pergunta.
A melhor prática é provavelmente usar algo mais legível, a menos que o desempenho seja absolutamente crítico:
fonte
-1 >>> 0
poderia acontecer e, nesse caso, é realmente desejável alterá-lo para 4294967295? Parece que isso faria com que o loop fosse executado mais algumas vezes do que o necessário.this.length
, é impossível saber. Para qualquer implementação "sã", o comprimento de uma string nunca deve ser negativo, mas pode-se argumentar que em um ambiente "sã" podemos assumir a existência de umathis.length
propriedade que sempre retorna um número inteiro.Duas razões:
O resultado de >>> é uma "integral"
undefined >>> 0 = 0 (como o JS tentará coagir o LFS ao contexto numérico, isso funcionará também para "foo" >>> 0, etc.)
Lembre-se de que os números em JS têm uma representação interna de double. É apenas uma maneira "rápida" de melhorar a sanidade básica dos insumos.
Contudo , -1 >>> 0 (opa, provavelmente não é o tamanho desejado!)
fonte
A amostra do código Java abaixo explica bem:
A saída é a seguinte:
fonte