2011-11-23 18 views
8

Mi sono imbattuto in un codice JavaScript funzionante che non riesco a spiegare. Ad esempio:Come funziona la costruzione di ~ [] in JavaScript?

  • +[]===0
  • -[]===0
  • ~[]===-1
  • ~-~[]===-2
  • ~-~-~-~-~[]===-5
  • ~-~-~-~-~[]+~[]===-6
  • ~+~[]===0
  • ~+~+~[]===-1
  • ~+~+~+~[]===0

si può spiegare la logica di queste espressioni?

+2

Penso che avrei capovolto la scrivania se mi imbattessi in un codice del genere. –

+1

la risposta è: '+ [NaN] == !!!! 0 && + [{}] + ~~ [[]] - []' – jAndy

+1

Se ho visto che in qualsiasi codebase avrei chiesto allo sviluppatore originale di riscrivere esso. È una pessima pratica !!! –

risposta

11

[] è un oggetto array vuoto, quindi:

+ []: forza array vuoto essere intero positivo, alias 0, che è === 0
- []: forza array vuoto di essere intero negativo, alias 0, che è === a 0
~ []: array bitwise NOT vuoto, che restituisce -1, che è === a -1
~ - ~ []: bit a bit NOT di negato NOTted array vuoto: ~-(-1) -> ~1 -> -2

ecc ...

+1

dovrebbe essere: '~ 1 -> -2' sull'ultima stringa – Denis

+0

Grazie, risolto la risposta. –

+0

-1 '+ []: forza l'array vuoto come intero positivo, ovvero 0, che è === a 0' non spiega perché accade. Riafferma appena il risultato. Ovviamente se '+ [] === 0', quindi' + [] 'deve essere stato convertito in' 0'. La domanda chiede di spiegare la logica. – RightSaidFred

2

Quando si utilizza l'operatore + o - su qualsiasi cosa, viene chiamato Number. Number([]) restituisce 0, quindi ottieni le prime due risposte.

L'operatore ~ è bit per bit NOT. Fondamentalmente inversione di tutti i bit di un numero, che cambia da 0 a -1. Ulteriori informazioni sugli operatori bit a bit here.

Il resto sono solo combinazioni di questi casi. Puoi praticamente combinare queste cose per creare qualsiasi numero che desideri.

+0

Capito. Ho perso il casting di '[]' a '0' parte. – Denis

0

Credo, correggimi se ho torto, ma aggiungendo a un array (come in, aggiungendo un valore a un array piuttosto che aggiungere un valore in un array) lo lancia a un numero. Il resto usa solo gli operatori di base +, - (la tilde (~) è un bit per bit) per modificare il numero e quindi un'equazione.

So [] == array ([]); 
[] + 1 == number (0); 
+[]===0 (true) 
+0

effettivamente lo ha lanciato su una stringa, non un numero. '[1] + 1 =" 11 "' così '+ [] = 0' perché è come fare' + "" ' – pleasedontbelong

1

Farò del mio meglio:

[]===0 è naturalmente falsa perché [] non è esattamente uguale a 0. Tuttavia, []==0 è vero perché esiste un cast implicito.

+ e -[] funzionano perché il più o il meno lancia [] su un numero reale.

~0 (l'inverso bit a bit di 0) è -1. Pertanto, ~[]===-1 funziona.

Gli altri funzionano semplicemente sottraendo o aggiungendo -1 un mucchio di volte.

2

Invece di ripetere semplicemente il risultato che hai dimostrato nella domanda, proverò a fornire una descrizione di perché il risultato è.

Spiegazione

Prendendo solo il primo esempio (perché il resto lo farà qualcosa di simile), siamo in grado di seguire le specifiche per vedere cosa succede.

Da 11.4.6 Unary + Operator, possiamo vedere che una conversione ToNumber ha luogo.

Return ToNumber (GetValue (expr)).

Da 9.3 ToNumber vediamo che se dato un oggetto (come il tuo Array), una conversione ToPrimitive avviene seguito da un altro tentativo di ToNumber.

oggetto

seguire le istruzioni seguenti:

  1. Let primValue essere ToPrimitive (argomento di input, numero suggerimento).
  2. Return ToNumber (primValue).

Da 9.1 To Primitive, se ToPrimitive Ottiene un oggetto, possiamo vedere che la sua [[DefaultValue]] è inverosimile:

oggetto

Ritorna un valore predefinito per l'oggetto. Il valore predefinito di un oggetto viene recuperato chiamando il metodo interno [[DefaultValue]] dell'oggetto, passando il suggerimento opzionale PreferredType. Il comportamento del metodo interno [[DefaultValue]] interno è definito da questa specifica per tutti gli oggetti nativi ECMAScript in 8.12.8.

Da 8.12.8 [[DefaultValue]] (hint), quello che alla fine sarà accadere che toString() saranno chiamati Array e restituito. Questa stringa viene inviata al ricorsivo ToNumber come descritto sopra.

Quindi cosa succede quando la conversione ToNumber viene eseguita su una stringa? Bene è descritto in 9.3.1 ToNumber Applied to the String Type, ed è un po 'lungo. Più semplice è quello di fare solo la conversione direttamente, e vedere cosa succede:

Number("");  // result is 0 on an empty string 
Number(" "); // result is 0 on a string with only whitespace 
Number("123"); // result is 123 on a numeric string 
Number(" 123 ");// result is 123 on a numeric string with leading & trailing spaces 
Number("abc"); // result is NaN (not a number) on non-numeric strings 

Quindi la domanda è: cosa fare stringa torniamo dal nostro array. Di nuovo, questo è facile da provare semplicemente.

[].toString(); // result is "" (empty string) 

Poiché il risultato è una stringa vuota, e una conversione ToNumber di una stringa vuota è 0 come mostrato sopra, ciò significherebbe stiamo confrontando 0 === 0.

Sarebbe lo stesso come se abbiamo fatto:

Number([].toString()) === 0; // true 

O per tirarlo fuori un po 'di più:

var x = []; 
x = x.toString(); // "" 
x = Number(x); // 0 
x === 0; // true 

Più toString risultati.

per mostrare più toString conversioni di Array, considerare quanto segue:

[1].toString();   // "1" 
[1,2,3].toString();  // "1,2,3" 
["a",1,"b",2].toString(); // "a,1,b,2" 

Quindi, per fare una conversione ToNumber sugli array di cui sopra, la prima ci darebbe un numero, e gli ultimi due si tradurrebbe in NaN.

Number([1]);   // 1 
Number([1,2,3]);  // NaN 
Number(["a",1,"b",2]); // NaN 

Alcuni prova

Per fornire ulteriore prova che questa conversione toString() avviene prima della conversione ToNumber, possiamo effettivamente modificare Array.prototype.toString per fornire un risultato diverso, e qualsiasi ToNumber conversioni useremo che risultato modificato.

Array.prototype.toString = function() { 
    var n = 0; 
    for(var i = 0; i < this.length; i++) { 
     n += this[i]; 
    } 
    return n; 
}; 

Qui ho sostituito il toString su Array.prototype con una funzione che somma l'Array. Ovviamente non vuoi farlo, ma possiamo mostrare come otterremo un risultato diverso.

Number([1,2,3]); // 6 
+[1,2,3];   // 6 

Così ora si può vedere che la conversione del nostro Array ToNumber che in precedenza hanno portato a NaN è ora traduce nella somma degli elementi della matrice.

Problemi correlati