Depuração de aplicativos Javascript

Cenário

Vamos enfrentá-lo, se você não sabe como usar as ferramentas de desenvolvedor do Chrome ou Firebug , dificilmente pode se chamar um desenvolvedor web. No entanto, apesar de todos os seus recursos incríveis, às vezes ambas as ferramentas deixam de resolver bugs complexos quando várias bibliotecas estão envolvidas: elas têm chamadas de função aninhadas que você não sabe onde estão ou muda o valor de ‘this’!

Para solucionar esse tipo de bug, precisamos de estratégias alternativas para ajudar a eliminar até mesmo o bug mais cruel da cidade. Neste artigo, discutiremos maneiras e técnicas incomuns para solucionar bugs que são difíceis de corrigir.

Problema: funções aninhadas AKA Quem está me chamando?

Imagine que você tenha uma função X que é chamada de vez em quando e com um parâmetro Y. Na maioria das vezes, Y é o que você está esperando, mas, em um caso específico, é undefined. Você sabe que o código é acionado pela função A em sua biblioteca incrível, mas a função A chama várias funções que podem ir tão longe quanto a função B, função C e assim por diante, até que finalmente cheguem à sua função.

Se o código for óbvio e você for bom com as ferramentas de desenvolvimento do Chrome, poderá usar pontos de interrupção para começar a rastrear o problema. No entanto, se as funções estiverem realmente aninhadas e o fluxo da chamada for longo, você pode demorar um pouco antes de encontrar um bom ponto de interrupção. Por outro lado, se você tiver acesso à função que está sendo usada pela biblioteca A, use caller:

function X(Y){
console
.log(X.caller);
}

O callermétodo dirá qual função está chamando sua função. Se a função for anônima, você pode usar a palavra this, desde que o contexto da função não tenha sido substituído. Outra maneira de fazer isso é por meio, caso a função não tenha sido criada com um newoperador , então o mesmo de antes seria:arguments.callee

function X(Y){
console
.log(arguments.callee.caller);
}

Tenha cuidado com o que não é totalmente suportado e também desanime. Pode ser parte do seu código de desenvolvimento, mas nem deveria estar em teste.arguments.callee

Problema: Valores indefinidos / errados, AKA Qual é o valor this?

Com toda a troca de contexto que o Javacript pode ter e sua falta de escopo, você poderia estar em uma situação onde o valor de uma variável não é o que você esperava. Um dos meus exemplos favoritos é este.

var count = 0; 
for ( var i = 0; i < 4; i++ ) {
setTimeout
(function(){
console
.log("Value of i should be equal to count");
console
.log("Value of i:"+i);
console
.log("value of count:"+ ++count);
}, i * 200);
}

O valor de ié sempre 4. Por quê? Porque o fechamento não funciona mais devido à mudança de contexto feita pelo setTimeout. Isso vai consertar:

var count = 0; 
for ( var i = 0; i < 4; i++ ) { (function(i){
setTimeout
(function(){
console
.log("Value of i should be equal to count");
console
.log("Value of i:"+i);
console
.log("value of count:"+ count++);
}, i * 200);
})(i)
}

Às vezes, os problemas não são tão sutis. Agora, imagine que este código caiu em suas mãos:

var town = { 
name
: "Christmas Town",
king
: "Santa",
whosTheKing
: function() {
var town = this.name;
var king = this.king;
var getKing = function() {
return this.king
}();
return getKing + " is the king of "+ town
}
}

(Se um código como este realmente cair em suas mãos, sinto muito por você. Este código vem do meu Protip sobre a palavra-chavethis )

Corra e você obterá “undefined is the king of Christmas Town”. Bananas. O que está acontecendo aqui? Se você ler minha dica, saberá que o Javascript está quebrando a referência à palavra, mas caso contrário, como você poderia depurar isso? para o resgate.town.whosTheKing()this.call

.callaltera o valor do thisobjeto para o que for fornecido. Nesse caso, queremos ver se algumas propriedades estão devidamente vinculadas. Por exemplo:

town.whosTheKing.call({name:"Gotham City", king: "Batman"}) // returns "undefined is the king of Gotham City"

Com este teste, sabemos agora que o método não está usando o thisvalor adequado . Onde está o valor de kingentão? Vamos usar o objeto janela agora.

town.whosTheKing.call(window) // returns "undefined is the king of "

As propriedades são declaradas, portanto, devem ser armazenadas em algum lugar . Poderia ser o objeto principal global?

window.name = "Arkham Asylum";
window
.king = "The Joker";
town
.whosTheKing.call(window) // returns "The Joker is the king of Arkham Asylum"

Aha! Portanto, eles estão de fato sendo armazenados no windowobjeto, também conhecido como objeto principal global. Embora seja um exemplo bobo, este pode ter sido provavelmente o padrão que as pessoas descobriram que a referência estava sendo quebrada quando 2 níveis aninhados de contexto foram fornecidos.

Conclusão

Ambos e são comandos javascript nativos extremamente úteis que podem ajudá-lo a depurar seus aplicativos. Se usados ​​corretamente, eles podem até mesmo fazer parte do seu código para construir padrões de design interessantes. Use-os em conjunto com seu conjunto de ferramentas de depuração atual e comece a eliminar os bugs..caller.call