Las matrices vacías son verdaderas, pero también son iguales a falsas.
var arr = [];
console.log('Array:', arr);
if (arr) console.log("It's true!");
if (arr == false) console.log("It's false!");
if (arr && arr == false) console.log("...what??");
Supongo que esto se debe a la conversión implícita operada por el operador de igualdad.
¿Alguien puede explicar lo que sucede detrás de escena?
javascript
Patonza
fuente
fuente
arr == true
no se evalúa como verdadero ;-)===
. Entonces, si desea probar el vacío de una matriz, usearr === []
arr === []
, ya que eso SIEMPRE devolverá falso, ya que el lado derecho está instanciando una nueva matriz, y la variable de la izquierda no puede referirse a algo que acaba de crear. La prueba del vacío debe hacerse mirando hacia arribaarr.length === 0
.Respuestas:
Estás probando cosas diferentes aquí.
if (arr)
llamado en el objeto (Array es una instancia de Object en JS) verificará si el objeto está presente y devuelve verdadero / falso.Cuando llama
if (arr == false)
, compara los valores de este objeto y elfalse
valor primitivo . Internamente,arr.toString()
se llama, lo que devuelve una cadena vacía""
.Esto se debe a que se
toString
llama a los retornos de matrizArray.join()
, y la cadena vacía es uno de los valores falsos en JavaScript.fuente
Boolean([])
regresatrue
?En cuanto a la línea:
Quizás estos ayuden:
Lo que creo que está sucediendo es que el booleano
false
está obligado a0
compararlo con un objeto (el lado izquierdo). El objeto es forzado a una cadena (la cadena vacía). Luego, la cadena vacía se convierte en un número, también, es decir, cero. Y así, la comparación final es0
==0
, que estrue
.Editar: consulte esta sección de la especificación para obtener detalles sobre cómo funciona exactamente.
Esto es lo que sucede, comenzando en la regla 1:
La siguiente regla que aplica es la # 19:
El resultado de
ToNumber(false)
es0
, así que ahora tenemos:Nuevamente, la regla # 1 nos dice que saltemos al paso # 14, pero el siguiente paso que realmente aplica es el # 21:
El resultado de
ToPrimitive([])
es la cadena vacía, por lo que ahora tenemos:Nuevamente, la regla n. ° 1 nos dice que saltemos al paso n. ° 14, pero el siguiente paso que realmente se aplica es el n. ° 17:
El resultado de
ToNumber("")
es0
, lo que nos deja con:Ahora, ambos valores tienen el mismo tipo, por lo que los pasos continúan desde el # 1 hasta el # 7, que dice:
Entonces volvemos
true
.En breve:
fuente
[] == 0
es cierto. Entiendo cómo sucede esto en función de su explicación de la especificación, pero parece un comportamiento extraño del lenguaje desde un punto de vista lógico.Para complementar la respuesta de Wayne y tratar de explicar por qué
ToPrimitive([])
regresa""
, vale la pena considerar dos posibles tipos de respuestas a la pregunta 'por qué'. El primer tipo de respuesta es: "porque la especificación dice que así es como se comportará JavaScript". En la especificación ES5, sección 9.1 , que describe el resultado de ToPrimitive como valor predeterminado para un objeto:La Sección 8.12.8 describe el
[[DefaultValue]]
método. Este método toma una "pista" como argumento, y la pista puede ser String o Number. Para simplificar el asunto prescindiendo de algunos detalles, si la pista es String,[[DefaultValue]]
devuelve el valor detoString()
si existe y devuelve un valor primitivo y, de lo contrario, devuelve el valor devalueOf()
. Si la sugerencia es Número, las prioridades detoString()
yvalueOf()
se invierten, por lo quevalueOf()
se llama primero y se devuelve su valor si es un primitivo. Por lo tanto, si[[DefaultValue]]
devuelve el resultadotoString()
ovalueOf()
depende del PreferredType especificado para el objeto y si estas funciones devuelven o no valores primitivos.El
valueOf()
método Object predeterminado solo devuelve el objeto en sí, lo que significa que a menos que una clase anule el método predeterminado,valueOf()
solo devuelve el Object en sí. Este es el caso paraArray
.[].valueOf()
devuelve el objeto en[]
sí. Como unArray
objeto no es primitivo, la[[DefaultValue]]
sugerencia es irrelevante: el valor de retorno para una matriz será el valor detoString()
.Para citar el JavaScript de David Flanagan : The Definitive Guide , que, por cierto, es un libro excelente que debería ser el primer lugar de todos para obtener respuestas a este tipo de preguntas:
El segundo tipo de respuesta a la pregunta "por qué", que no sea "porque la especificación dice", da una explicación de por qué el comportamiento tiene sentido desde la perspectiva del diseño. Sobre este tema solo puedo especular. Primero, ¿cómo se convertiría una matriz en un número? La única posibilidad sensata que se me ocurre sería convertir una matriz vacía a 0 y cualquier matriz no vacía a 1. Pero como reveló la respuesta de Wayne, una matriz vacía se convertirá a 0 para muchos tipos de comparaciones de todos modos. Más allá de esto, es difícil pensar en un valor de retorno primitivo sensible para Array.valueOf (). Por lo tanto, se podría argumentar que tiene más sentido tener
Array.valueOf()
el valor predeterminado y devolver la matriz en sí, lotoString()
que lleva a ser el resultado utilizado por ToPrimitive. Simplemente tiene más sentido convertir una matriz en una cadena, en lugar de un número.Además, como lo sugiere la cita de Flanagan, esta decisión de diseño permite ciertos tipos de comportamientos beneficiosos. Por ejemplo:
Este comportamiento le permite comparar una matriz de un solo elemento con números y obtener el resultado esperado.
fuente
fuente
En if (arr), siempre se evalúa (ToBoolean) como verdadero si arr es un objeto porque todos los objetos en JavaScript son verdaderos . (nulo no es un objeto!)
[] == false
se evalúa en enfoque iterativo. Al principio, si un lado de==
es primitivo y el otro es objeto, primero convierte el objeto en primitivo, luego convierte ambos lados en Número si ambos lados no lo sonstring
(la comparación de cadenas se usa si ambos lados son cadenas). Entonces la comparación se repite como,[] == false
->'' == false
->0 == 0
->true
.fuente
Ejemplo:
Sucede porque
[]
es unArray
objeto vacío →ToPrimitive([])
→ "" →ToNumber("")
→0
ToNumber(false)
→ 0fuente
Una matriz con elementos (independientemente de si 0, falso u otra matriz vacía), siempre resuelve
true
usar la Comparación de igualdad abstracta==
.Pero utilizando una comparación estricta de igualdad
===
, está intentando evaluar el contenido de la variable, así como su tipo de datos, por eso:fuente
Puede vaciar una matriz de JavaScript haciendo referencia a una nueva matriz, utilizando
list = []
o eliminando los elementos de la matriz referenciada actualmentelist.length = 0
.Fuente: JavaScript Empty Array
fuente
Nada de lo anterior me ayudó, cuando traté de usar el complemento de mapeo knockout.js, tal vez porque una "matriz vacía" no está realmente vacía.
Terminé usando:
data-bind="if: arr().length"
que hizo el truco.Esto es específico del nocaut, no es la pregunta del OP, pero tal vez ayude a alguien más a navegar aquí en una situación similar.
fuente