2011-11-08 10 views
5

Ciò che segue mi confonde molto. Come notato nei commenti, i paragoni sembrano funzionare da soli, ma quando messi insieme non lo fannoJavascript "==" operatore bugie

Il tempo dovrebbe essere eseguito per tutti i giorni nello stesso mese, quindi incrementare i dati per uno, quindi ricominciare da capo.

Ho allacciato l'intera sequenza con console.log per cercare di capirlo, ma non ha alcun senso. Tutto sembra uguale l'un l'altro, ma continua a fallire il test "==" nell'istruzione while.

var i=0; 
    var currentdate = 0; 
    var currentmonth = 0; 
    var opensmonth = 0; 
    var opens = [ 
    { "date":"3/30/2006","zip":"30038","latitude":"33.676358","longitude":"-84.15381"}, 
    { "date":"4/31/2006","zip":"30519","latitude":"34.089419","longitude":"-83.94701"} 
    ]; 
    intid = setInterval("stepthrough()", 250); 
    function stepthrough() { 
    //figure out first date. 
    if (currentdate == 0) { // we've not been run before 
     currentdate = opens[0]["date"]; 
     currentmonth = currentdate.split("/", 1); 
     console.log("Current Month: >" + currentmonth +"<"); 
    } 
    console.log("Current month: " + currentmonth + " And opensdate: " + opens[i]["date"].split("/", 1)); 

    // 
    // TWILIGHT ZONE ENTERED. 
    // 
    if (currentmonth == 3) { 
     console.log("Current month equals 3."); // PASSES 
    } 
    if (opens[i]["date"].split("/", 1) == 3) { 
     console.log("Opens date equals 3."); // PASSES 
    } 
    // BOTH THE ABOVE TESTS PASS IN CHROME AND SAFARI WHAT THE F*$K JAVASCRIPT 

    while(opens[i]["date"].split("/", 1) == currentmonth) { // WHY DOESNT THIS WORK I HATE COMPUTERS 
     console.log("Trying to add a point one."); 
     addpoint(i); 
     i++; 
     console.log("Trying to add a point."); 
    } 

    //set the date for next iteration 
    currentdate = opens[i]["date"]; 
    currentmonth = currentdate.split("/", 1); 
    console.log ("Current date is now: " + currentdate + " and current month is now: " + currentmonth); 
    jQuery('div#date').text(currentdate); 

    //if (i>=5000) { 
    if (!opens[i]["date"]) { 
     console.log("Clearing interval"); 
     clearInterval(intid); 
     //jQuery('div#date').text("Limited at 5000 records") 
    } 
    } 
+3

provare a utilizzare 'parseInt (stringValue, 10)'. –

+0

Cosa succede se usi '===' nella riga '// WHY DOESNT THIS WORK'? [Questa risposta] (http://stackoverflow.com/questions/359494/javascript-vs-does-it-matter-which-equal-operator-i-use/359509#359509) suggerisce che '==' è malvagio e non ci si può fidare. – CanSpice

+2

Sinceramente non vedo una domanda qui. –

risposta

4

Ecco il problema: ["1"] == 1 in Javascript, a causa delle conversioni implicite descritte da @Matt. Ma ["1"] != ["1"] in Javascript, perché stai confrontando due array, e quindi due oggetti, e il confronto tra oggetti sono veri solo se puntano allo stesso oggetto, non se puntano a due oggetti identici.

Quando si assegna con .split('/', 1), che stai ricevendo una matrice come ['3'], non la stringa "3" (come penso che potrebbe essere assumendo). Quindi:

currentmonth = currentdate.split("/", 1); // currentmonth is ["3"] 
currentmonth == 3; // true, as described above 
opens[i]["date"].split("/", 1) == 3; // true, because left-hand evals to ["3"] 
opens[i]["date"].split("/", 1) == currentmonth; 
// false, because you're comparing two arrays - ["3"] != ["3"] 

Per risolvere questo problema con il codice corrente, si può solo ottenere la stringa, non è la matrice, in questo modo:

currentmonth = currentdate.split("/")[0]; // currentmonth is "3" 
opens[i]["date"].split("/")[0] == currentmonth; // true, both sides are "3" 
+0

Avrei dovuto controllare il resto delle risposte prima di procedere, sono arrivato alla stessa conclusione. Buona risposta. – Nicole

+0

Ho aggiunto alcuni [dettagli personali] (http://stackoverflow.com/questions/8056317/javascript-operator-lies/8056914#8056914), ma il merito va a te per aver individuato prima il problema dell'array. – Nicole

0

Puoi provare questo solo per sapere se è un errore intero vs stringa?

Questa non è una soluzione piacevole ma dà un indizio.

while(opens[i]["date"].split("/", 1) + "str" == currentmonth + "str") 
+1

userei invece 'parseInt'. –

7

La scrittura in JavaScript è implicita. Ciò significa che se si pensa di voler trattare qualcosa come un numero, sarà meglio trattare quell'oggetto come un numero, anche se è, per esempio, un booleano o una stringa.

Quando si esegue lo standard ==, JavaScript utilizzerà le conversioni implicite per provare e abbinare i tipi. Ciò si traduce spesso in risultati di confronto imprevisti.

Se si desidera forzare confronti forti, è necessario utilizzare l'operatore ===.

Detto questo, se si sta esaminando la rappresentazione del "numero" di una stringa, ad es. "123", e vuoi usare forti confronti, devi convertirlo in un numero usando parseInt (str, 10);

Per alcuni esempi sulla digitazione implicita in azione, vedere la risposta JavaScript truth table.

+0

Buona risposta, ma in realtà non spiega la causa del problema, solo le migliori pratiche. – nrabinowitz

+0

'Number' [costruttore chiamato come funzione] (http://stackoverflow.com/questions/2381399/what-is-the-difference-between-new-number-and-number-in-javascript/2381580#2381580) funziona anche – Nicole

1

prega Upvote nrabinowitz's answer perché era prima e che sia corretto.

Tuttavia, desidero aggiungere alcuni dettagli sul problema sottostante e come Javascript gestisce le conversioni implicite == tra matrici, numeri e stringhe.

Per riepilogare: Ogni tipo ha regole leggermente diverse quando si utilizza == con tipi diversi. Le matrici vengono convertite in valore primitivo se confrontate con Numero o Stringa, ma non quando confrontate con un'altra matrice.

Particolare:

  1. String.split restituisce un array.
  2. Le stringhe e i numeri sono grezzi types in Javascript. Gli altri sono Boolean, Object, Null e Undefined.
  3. Array è digitare oggetto
  4. == segue il "Abstract equality comparison algorithm" (x == y)
  5. Nei suoi primi due confronti, poiché uno dei tipi (3) è un numero, la sua condizione rientra nella seguente regola:

    Se tipo (x) è o String o Numero e Tipo (y) è Oggetto, restituisce il risultato del confronto x == ToPrimitive (y).

    In altre parole, converte l'array ["3"] a 3 e la confronta con 3 — vero (vedere la docs on ToPrimitive)

  6. Nell'ultimo caso che dici è rotto, cade sotto la prima regola, ("Tipo (x) è la stessa come (y)" — entrambi siano oggetto Poi valuta la seguente regola:.

    Restituisce vero se xey si riferiscono allo stesso oggetto. Altrimenti, restituisci falso.

  7. Essi contengono lo stesso valore, ma non sono gli stessi oggetto (ciascuno è un diverso risultato di una chiamata a String.split), quindi il risultato è falso .

Per chiarire:

console.log("3 == [3]?", 3 == [3]); // true 
console.log("3 == ['3']?", 3 == ['3']); // true 
console.log("'3' == [3]?", "3" == [3]); // true 
console.log("'3' == ['3']?", '3' == ['3']); // true 
console.log("[3] == [3]?", [3] == [3]); // false 
console.log("['3'] == ['3']?", ['3'] == ['3']); // false - NOT SAME OBJECT 

var a = ['3']; 
var b = a; // SAME OBJECT 

console.log("a == b?", a == b); // true! 

La soluzione, come @nrabinowitz dice, è quello di aggiungere semplicemente [0] alla fine della chiamata differita in modo che il valore è il primo elemento (una stringa) anziché la matrice stessa.

+0

Buoni dettagli, e grazie per la raccomandazione di upvote! – nrabinowitz