Javascript e l'uguaglianza
medio
Il problema
La particolare tipizzazione (debole e dinamica) rende complesso il confronto di variabili javascript.
Ad esempio abbiamo due diversi operatori di uguaglianza e diversità:
== e != cercano di convertire il tipo in stringa (utilizzando il metodo toString) prima del confronto.
=== e !== non convertono il tipo
Quindi :
>>>100 == "100" true
mentre
>>>100 === "100" false
e infine
>>>100 === 100 true
E' consigliabile quindi utilizzare sempre === e !== (o almeno essere consapevoli di cosa comporta l'utilizzo dell'operatore == ).
Quando confrontiamo tipi complessi ci troviamo un altro problema ! A quanto pare due variabili oggetto sono uguali solo se sono in effetti lo stesso oggetto.
Quindi:
>>>var obj1 = {"value":1}
>>>var obj2 = obj1;
>>>obj1 == obj2
true
mentre
>>>var obj1 = {"value":1}
>>>var obj2 = {"value":1}
>>>obj1 == obj2
false
Inoltre ogni oggetto può contenere un altro oggetto!
Dobbiamo quindi testare ricorsivamente ogni attributo.
La soluzione
Ecco la soluzione che ho trovato:
function equals (obj1,obj2){
if (obj1 === null || obj2 === null){
return obj1 === obj2;
}
switch(typeof(obj1)){
case 'object':
if (typeof(obj2) == 'object'){
for (i in obj2){ // object or array
if (typeof(obj1[i]) == "undefined"){
return false;
}
}
for (i in obj1){
if (! arguments.callee(obj1[i],obj2[i])){
return false; //if are not equals return false
}
}
return true;
}
break;
case 'function':
if ((typeof(obj2) == 'function') && (obj1.toString() == obj2.toString())){
return true;
}
break;
default:
if (obj1 === obj2){
return true;
}
}
return false;
}
Come prima cosa controllo se uno dei due oggetti è null. A quanto pare, nonostante null sia un "object", il confronto tra due null funziona correttamente.Poi a seconda del tipo faccio un diverso tipo di confronto: se il tipo è "function" controllo l'uguaglianza tramite il metodo toString che restituisce il sorgente della funzione. In caso di oggetto (ricordo che in javascript gli array hanno tipo "object") controllo in primo luogo se i membri (metodi e gli attributi) del secondo oggetto sono definiti nel primo, in seguito lancio ricorsivamente la funzione su ogni coppia di membri verificando quindi che siano uguali.
In caso che il tipo sia diverso da "function" e da "object" considero che il tipo sia primitivo (number, string, undefined) e tra questi il confronto funziona correttamente (con ===).