¿La consola JavaScript de Chrome es vaga a la hora de evaluar objetos?
Empezaré con el código:
var s = ["hi"];
console.log(s);
s[0] = "bye";
console.log(s);
Sencillo, ¿verdad? En respuesta a esto, la consola de Firefox dice:
[ "hi" ]
[ "bye" ]
Maravilloso, pero la consola JavaScript de Chrome (7.0.517.41 beta) dice:
[ "bye" ]
[ "bye" ]
¿He hecho algo mal o la consola JavaScript de Chrome está siendo excepcionalmente perezosa a la hora de evaluar mi matriz?
Gracias por el comentario, tec. Pude encontrar un error de Webkit no confirmado existente que explica este problema: https://bugs.webkit.org/show_bug.cgi?id=35801 (EDITAR: ¡ahora solucionado!)
Parece haber cierto debate sobre hasta qué punto es un error y si se puede solucionar. Me parece un mal comportamiento. Fue especialmente preocupante para mí porque, al menos en Chrome, ocurre cuando el código reside en scripts que se ejecutan inmediatamente (antes de cargar la página), incluso cuando la consola está abierta, cada vez que se actualiza la página. Llamar a console.log cuando la consola aún no está activa solo genera una referencia al objeto en cola, no la salida que contendrá la consola. Por lo tanto, la matriz (o cualquier objeto) no se evaluará hasta que la consola esté lista. Realmente es un caso de evaluación perezosa.
Sin embargo, existe una forma sencilla de evitar esto en su código:
var s = ["hi"];
console.log(s.toString());
s[0] = "bye";
console.log(s.toString());
Al llamar a toString, crea una representación en la memoria que no será alterada por las siguientes declaraciones, que la consola leerá cuando esté lista. La salida de la consola es ligeramente diferente de pasar el objeto directamente, pero parece aceptable:
hi
bye
Según la explicación de Eric, se debe a console.log()
que está en cola e imprime un valor posterior de la matriz (u objeto).
Puede haber 5 soluciones:
1. arr.toString() // not well for [1,[2,3]] as it shows 1,2,3
2. arr.join() // same as above
3. arr.slice(0) // a new array is created, but if arr is [1, 2, arr2, 3]
// and arr2 changes, then later value might be shown
4. arr.concat() // a new array is created, but same issue as slice(0)
5. JSON.stringify(arr) // works well as it takes a snapshot of the whole array
// or object, and the format shows the exact structure
Puedes clonar una matriz con Array#slice
:
console.log(s); // ["bye"], i.e. incorrect
console.log(s.slice()); // ["hi"], i.e. correct
Una función que puedes usar en lugar de console.log
la que no tiene este problema es la siguiente:
console.logShallowCopy = function () {
function slicedIfArray(arg) {
return Array.isArray(arg) ? arg.slice() : arg;
}
var argsSnapshot = Array.prototype.map.call(arguments, slicedIfArray);
return console.log.apply(console, argsSnapshot);
};
Para el caso de los objetos, desafortunadamente, el mejor método parece ser depurar primero con un navegador que no sea WebKit o escribir una función complicada para clonar. Si sólo trabaja con objetos simples, donde el orden de las teclas no importa y no hay funciones, siempre puede hacer:
console.logSanitizedCopy = function () {
var args = Array.prototype.slice.call(arguments);
var sanitizedArgs = JSON.parse(JSON.stringify(args));
return console.log.apply(console, sanitizedArgs);
};
Todos estos métodos son obviamente muy lentos, por lo que incluso más que con console.log
los mensajes de correo electrónico normales, debes eliminarlos una vez que hayas terminado de depurar.
Esto ha sido parcheado en Webkit, sin embargo, cuando uso el marco React, esto me sucede en algunas circunstancias, si tiene tales problemas, simplemente use como otros sugieren:
console.log(JSON.stringify(the_array));