Cosa fa una tilde quando precede un'espressione?


Risposte:


267

~è un operatore bit a bit che capovolge tutti i bit nel suo operando.

Ad esempio, se il tuo numero fosse 1, la sua rappresentazione binaria del float IEEE 754 (come JavaScript tratta i numeri) sarebbe ...

0011 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

Quindi ~converte il suo operando in un numero intero a 32 bit (lo fanno gli operatori bit a bit in JavaScript) ...

0000 0000 0000 0000 0000 0000 0000 0001

Se fosse un numero negativo, sarebbe memorizzato nel complemento di 2: inverti tutti i bit e aggiungi 1.

... e poi lancia tutti i suoi bit ...

1111 1111 1111 1111 1111 1111 1111 1110

Allora, a che cosa serve? Quando si potrebbe mai usarlo?

Ha parecchi usi. Se stai scrivendo cose di basso livello, è utile. Se hai profilato la tua applicazione e trovato un collo di bottiglia, potrebbe essere reso più performante usando trucchi bit a bit (come uno strumento possibile in una borsa molto più grande).

È anche un trucco (generalmente) poco chiaro per trasformare indexOf()il valore di ritorno trovato in verità (pur non trovandolo come falsa ) e le persone spesso lo usano per il suo effetto collaterale di troncare i numeri a 32 bit (e far cadere il suo decimale raddoppiandolo, effettivamente lo stesso che Math.floor()per i numeri positivi).

Dico poco chiaro perché non è immediatamente ovvio per cosa viene utilizzato. In genere, si desidera che il codice comunichi chiaramente alle altre persone che lo leggono. Mentre l'utilizzo ~può sembrare interessante , è generalmente troppo intelligente per il suo bene. :)

È anche meno rilevante ora che JavaScript ha Array.prototype.includes()e String.prototype.includes(). Questi restituiscono un valore booleano. Se la tua piattaforma di destinazione lo supporta, dovresti preferirlo per verificare l'esistenza di un valore in una stringa o matrice.


2
Brutta è la parola giusta? Se funziona, lo definirei semplicemente un linguaggio della lingua. Ci sono molti modi di dire. Una volta che li impari non sono chiari. Le comprensioni dell'elenco non sono chiare in Python se non le conosci e puoi realizzarle con più loop dettagliati ma non chiedi mai a un programmatore Python di non usarle. Allo stesso modo value = value || defaultin JavaScript è un linguaggio comune e valido fintanto che sai quando puoi e non puoi usarlo.
Gman,

3
@gman Immagino che non importa se qualcuno lo usa o no. Penso che confrontare la comprensione dell'elenco (funzionalità del linguaggio) con questa non sia proprio la stessa cosa ( un modo intelligente per evitare di scrivere alcuni caratteri extra). Se pensi che il termine cattivo sia troppo duro, sentiti libero di modificare la mia risposta.
alex,

2
Forse è un esempio più comune v = t ? a : b;. Trovo che sia molto più chiaro del var v; if (t} { v = a; } else { v = b; }solito suddiviso su 5+ righe e anche più chiaro di quello var v = b; if (t) { v = a; }che di solito sarebbe 4+ righe. Ma conosco molte persone che non hanno familiarità con gli ? :operatori che preferirebbero la seconda o la terza via. Trovo che il primo sia più leggibile. Sono d'accordo con il principio generale, chiarisco il codice, non usare gli hack. Immagino di vedere ~v.indexOf('...')molto chiaro una volta che l'ho imparato.
Gman,

9
Quando lavori in una grande azienda con molti sviluppatori, vuoi che il codice sia chiaramente scritto (INGLESE) e ben documentato. Il punto della codifica di alto livello in un linguaggio con garbage collection è evitare di pensare alle operazioni binarie e molti sviluppatori front-end non hanno nemmeno esperienza del linguaggio assembly sotto le loro cinture.
user2867288

3
non definirei ~idiomatico. fa tecnicamente parte delle specifiche del linguaggio , ma non fa tanto parte del linguaggio in uso generale .
worc,

109

indexOf()Usarlo prima di un'espressione ti dà effettivamente un risultato di verità / falsità invece dell'indice numerico che viene restituito direttamente.

Se il valore restituito è -1, allora ~-1è 0perché -1è una stringa di tutti e 1 i bit. Qualsiasi valore maggiore o uguale a zero darà un risultato diverso da zero. Così,

if (~someString.indexOf(something)) {
}

farà ifeseguire il codice quando "qualcosa" è in "someString". Se provi a usarlo .indexOf()direttamente come booleano, allora non funzionerà perché a volte restituisce zero (quando "qualcosa" è all'inizio della stringa).

Naturalmente funziona anche questo:

if (someString.indexOf(something) >= 0) {
}

ed è notevolmente meno misterioso.

A volte vedrai anche questo:

var i = ~~something;

Usare l' ~operatore due volte in questo modo è un modo rapido per convertire una stringa in un numero intero a 32 bit. Il primo ~esegue la conversione e il secondo ~ribalta i bit. Naturalmente se l'operatore viene applicato a qualcosa che non può essere convertito in un numero, si ottiene NaNdi conseguenza. ( modifica - in realtà è il secondo ~che viene applicato per primo, ma ottieni l'idea.)


2
Per coloro che non vogliono negare bit per bit, ~quando eseguito su numeri interi è uguale a -(x + 1).
Fabrício Matté,

Sembra, beh, sai, i valori numerici NEGATIVI dovrebbero restituire anche valori booleani negativi. Ma solo un altro dei JS fallisce, immagino?
wwaawaw,

7
@adlwalrus bene la tradizione 0dell'essere falsee dell'essere diverso da zero truerisale a molto tempo fa, almeno a C negli anni '70 e probabilmente molti altri linguaggi di programmazione di sistemi allora contemporanei. Probabilmente deriva dal modo in cui funziona l'hardware; molte CPU impostano un bit zero dopo un'operazione e dispongono di un'istruzione di ramo corrispondente per testarla.
Puntato il

4
Un modo più rapido per convertirlo in un int a 32 bit sarebbe | 0, nel qual caso è una sola operazione.
alex,

@alex infatti, anche se non possiamo necessariamente fidarci del runtime di non interpretare una semplice applicazione ~~esattamente allo stesso modo.
Punta il

29

Il ~è Bitwise NON Operator , ~xè più o meno lo stesso di -(x+1). È più facile da capire, in un certo senso. Così:

~2;    // -(2+1) ==> -3

Prendere in considerazione -(x+1). -1può eseguire quell'operazione per produrre a 0.

In altre parole, ~usato con un intervallo di valori numerici produrrà un valore falso (coerce to falsefrom 0) solo per il -1valore di input, altrimenti qualsiasi altro valore di verità.

Come sappiamo, -1viene comunemente chiamato un valore sentinella . È usato per molte funzioni che restituiscono >= 0valori per il successo e -1per il fallimento nel linguaggio C. Che la stessa regola del valore di ritorno di indexOf()in JavaScript.

In questo modo è comune verificare la presenza / assenza di una sottostringa in un'altra stringa

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
}

Tuttavia, sarebbe più facile farlo ~come di seguito

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
}

Non conosci JS: tipi e grammatica di Kyle Simpson


1
È sicuramente più facile da capire al valore nominale, anche se una persona non capisce lo sfondo che lo fa funzionare. Darei una seconda occhiata -(x+1)se lo vedessi in una dichiarazione if. La tilde mi dice esattamente cosa sta facendo per compensare la natura basata su 0 di Javascript. Inoltre, meno parentesi meglio è per la lettura
Regular Joe

Nel blocco iniziale del codice di controllo potresti digitare meno usando if (a.indexOf("Ba") > -1) {// found} //truequale, sebbene un po 'più lungo degli esempi di tilde, è considerevolmente inferiore ai due esempi che hai dato e per i nuovi programmatori var opinion = !~-1 ? 'more' : 'less'comprensibili.
HalfMens

24

~indexOf(item) arriva abbastanza spesso, e le risposte qui sono fantastiche, ma forse alcune persone hanno solo bisogno di sapere come usarlo e "saltare" la teoria:

   if (~list.indexOf(item)) {
     // item in list
   } else {
     // item *not* in list
   }

1
Concordo. La Guida di stile JavaScript di Airbnb non consente ++e --perché "incoraggiano l'eccessiva inganno" e tuttavia in qualche modo sono ~sopravvissuti (in agguato nell'ombra) github.com/airbnb/javascript/issues/540
Shanimal

@Shanimal L'alternativa è list.indexOf(item) >= 0o ... > -1poiché javascript è basato su zero e non ha scelto di affrontarlo sin dall'inizio. Inoltre, solo l'opinione (come quella di Airbnb), chiunque stia facendo qualcosa di significativo in javascript lo sa ++, e mentre --è meno comune, il significato può essere dedotto.
Regolare Joe,

@RegularJoe Sono d'accordo con la maggior parte di questo. Personalmente non ne ho avuto bisogno ++e --per un po 'a causa di metodi primitivi come map, forEachecc. Il mio punto è più sul perché non considerano anche ~eccessivamente complicato quando qualunque standard utilizzato include operatori di incremento e decremento. Proibire qualcosa in modo che CIS101 non abbia alcun senso.
Shanimal,

11

Per coloro che considerano l'utilizzo del trucco della tilde per creare un valore veritiero da un indexOfrisultato, è più esplicito e ha meno magia invece di usare il includesmetodoString .

'hello world'.includes('hello') //=> true
'hello world'.includes('kittens') //=> false

Si noti che questo è un nuovo metodo standard a partire da ES 2015, quindi non funzionerà su browser meno recenti. Nei casi in cui ciò è importante, prendere in considerazione l'uso di String.prototype.includes polyfill .

Questa funzione è disponibile anche per le matrici che utilizzano la stessa sintassi :

['apples', 'oranges', 'cherries'].includes('apples') //=> true
['apples', 'oranges', 'cherries'].includes('unicorns') //=> false

Ecco il file polifill Array.prototype.incles se hai bisogno del supporto del browser precedente.


2
Evitare di utilizzare Includes (). Non è supportato in nessuna versione di IE (non solo nei browser più vecchi) al momento in cui scrivo: developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Onshop il

8
O semplicemente usa un compilatore, così puoi scrivere un codice più chiaro, invece di scrivere la lingua secondo il peggior interprete comune JS in circolazione ...
Kyle Baker,

2
@Ben ha ragione, non funziona neanche in Netscape 4.72.
mikemaccana,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.