Acho que a função var_dump (ou similares, como print_r e debug_zval_dump) é uma das mais úteis para se depurar alguns problemas em PHP. Ela avalia uma ou mais variáveis ou valores, mostrando informações sobre elas (tipo, classe, etc). Este recurso, no entanto, não existe nativamente em JavaScript. Para prover esta solução em JavaScript, tentei implementar uma var_dump parecida com a de PHP. Como ela não consegue detectar recursividade infinita (quando um elemento aponta para algum que já foi mostrado), então criei o atributo "max_iteracoes", que pode ser configurado antes de se chamar a função. Com isso, a função previne loops infinitos.
Linguagem: JavaScript
Copyright 2011 Rubens Takiguti Ribeiro
Licença: LGPL 3 ou superior
/**
* Versao JavaScript da funcao var_dump do PHP
* @param mixed ... Qualquer valor
* @return string Informacoes do valor
*/
function var_dump(/* ... */) {
/**
* Recursao do metodo var_dump
* @param midex item Qualquer valor
* @param int nivel Nivel de indentacao
* @return string Informacoes do valor
*/
this.var_dump_rec = function(item, nivel) {
if (var_dump.max_iteracoes > 0 && var_dump.max_iteracoes < nivel) {
return this.indentar(nivel) + "*MAX_ITERACOES(" + var_dump.max_iteracoes+ ")*\n";
}
if (item === null) {
return this.indentar(nivel) + "NULL\n";
} else if (item === undefined) {
return this.indentar(nivel) + "undefined\n";
}
var str = '';
var tipo = typeof(item);
switch (tipo) {
case 'object':
var classe = this.get_classe(item);
switch (classe) {
case 'Array':
str += this.indentar(nivel) + "Array(" + item.length + ") {\n";
for (var i in item) {
str += this.indentar(nivel + 1) + "[" + i + "] =>\n";
str += this.var_dump_rec(item[i], nivel + 1);
}
str += this.indentar(nivel) + "}\n";
break;
case 'Number':
case 'Boolean':
str += this.indentar(nivel) + classe + "(" + item.toString() + ")\n";
break;
case 'String':
str += this.indentar(nivel) + classe + "(" + item.toString().length + ") \"" + item.toString() + "\"\n";
break;
default:
str += this.indentar(nivel) + "object(" + classe + ") {\n";
var exibiu = false;
for (var i in item) {
exibiu = true;
str += this.indentar(nivel + 1) + "[" + i + "] =>\n";
try {
str += this.var_dump_rec(item[i], nivel + 1);
} catch (e) {
str += this.indentar(nivel + 1) + "(Erro: " + e.message + ")\n";
}
}
if (!exibiu) {
str += this.indentar(nivel + 1) + "JSON(" + JSON.stringify(item) + ")\n";
}
str += this.indentar(nivel) + "}\n";
break;
}
break;
case 'number':
str += this.indentar(nivel) + "number(" + item.toString() + ")\n";
break;
case 'string':
str += this.indentar(nivel) + "string(" + item.length + ") \"" + item + "\"\n";
break;
case 'boolean':
str += this.indentar(nivel) + "boolean(" + (item ? "true" : "false") + ")\n";
break;
case 'function':
str += this.indentar(nivel) + "function {\n";
str += this.indentar(nivel + 1) + "[code] =>\n";
str += this.var_dump_rec(item.toString(), nivel + 1);
str += this.indentar(nivel + 1) + "[prototype] =>\n";
str += this.indentar(nivel + 1) + "object(prototype) {\n";
for (var i in item.prototype) {
str += this.indentar(nivel + 2) + "[" + i + "] =>\n";
str += this.var_dump_rec(item.prototype[i], nivel + 2);
}
str += this.indentar(nivel + 1) + "}\n";
str += this.indentar(nivel) + "}\n";
break;
default:
str += this.indentar(nivel) + tipo + "(" + item + ")\n";
break;
}
return str;
};
/**
* Devolve o nome da classe de um objeto
* @param Object obj Objeto a ser verificado
* @return string Nome da classe
*/
this.get_classe = function(obj) {
if (obj.constructor) {
return obj.constructor.toString().replace(/^.*function\s+([^\s]*|[^\(]*)\([^\x00]+$/, "$1");
}
return "Object";
};
/**
* Retorna espacos para indentacao
* @param int nivel Nivel de indentacao
* @return string Espacos de indentacao
*/
this.indentar = function(nivel) {
var str = '';
while (nivel > 0) {
str += ' ';
nivel--;
}
return str;
};
var str = "";
var argv = var_dump.arguments;
var argc = argv.length;
for (var i = 0; i < argc; i++) {
str += this.var_dump_rec(argv[i], 0);
}
return str;
}
var_dump.prototype.max_iteracoes = 0;
A forma de usar é parecida como em PHP: basta passar um ou mais valores ou variáveis para a função. A diferença é que, ao invés de a função exibir o valor, ela retorna o valor na forma de string. Ele pode ser mostrado com uma mensagem em window.alert(retorno), ou colocado no documento HTML (dentro de uma tag PRE para facilitar a visualização). Veja um exemplo e, em seguida, seu resultado:
JavaScript:
window.onload = function() {
// Objeto a ser avaliado
var obj = new Object();
obj.indef = undefined;
obj.vazio = null;
obj.num1 = 3.5;
obj.inf1 = Number.POSITIVE_INFINITY;
obj.inf2 = Number.NEGATIVE_INFINITY;
obj.str1 = 'teste';
obj.b1 = true;
obj.b2 = false;
obj.vet1 = ['a','b'];
obj.data = new Date();
obj.num2 = new Number(2.5);
obj.str2 = new String('testando');
obj.bool1 = new Boolean(true);
obj.bool2 = new Boolean(false);
obj.vet2 = new Array();
obj.vet2.push('a');
obj.vet2.push(5);
obj.f = function() { window.alert('oi'); };
obj.f.prototype.pi = 3.14;
obj.f.prototype.msg = 'oi';
obj.f.prototype.func = function() { var x = 1; };
// Obtendo informacoes de obj
var dump = var_dump(obj);
// Criando uma tag PRE no documento e inserindo o resultado
var pre = document.createElement("pre");
pre.appendChild(document.createTextNode(dump));
document.getElementsByTagName("body").item(0).appendChild(pre);
}
Resultado:
object(Object) {
[indef] =>
undefined
[vazio] =>
NULL
[num1] =>
number(3.5)
[inf1] =>
number(Infinity)
[inf2] =>
number(-Infinity)
[str1] =>
string(5) "teste"
[b1] =>
boolean(true)
[b2] =>
boolean(false)
[vet1] =>
Array(2) {
[0] =>
string(1) "a"
[1] =>
string(1) "b"
}
[data] =>
object(Date) {
JSON("2011-03-12T22:10:13.716Z")
}
[num2] =>
Number(2.5)
[str2] =>
String(8) "testando"
[bool1] =>
Boolean(true)
[bool2] =>
Boolean(false)
[vet2] =>
Array(2) {
[0] =>
string(1) "a"
[1] =>
number(5)
}
[f] =>
function {
[code] =>
string(39) "function () {
window.alert("oi");
}"
[prototype] =>
object(prototype) {
[pi] =>
number(3.14)
[msg] =>
string(2) "oi"
[func] =>
function {
[code] =>
string(30) "function () {
var x = 1;
}"
[prototype] =>
object(prototype) {
}
}
}
}
}
Para especificar o número de recursões, faça como no exemplo:
var_dump.max_recursoes = 3; var x = var_dump(obj);