quinta-feira, 1 de setembro de 2016

Como funciona o jQuery - O que ele é - Hacking jQuery - I

Para explicar o que é, e como funciona o jQuery, reproduzimos aqui um código mínimo do mínimo, com o essencial do essencial para melhor compreendê-lo:

tQuery.js


(function( window, undefined ) {

var
      // Referência à raiz jQuery(document)
      rootjQuery,

     // Usa o documento correto de acordo com a chamada (sandbox)
     document = window.document,
location = window.location,
core_version = "a.0.0",
jQuery = function( selector, context ) {
     // O objeto jQuery é realmente o construtor init 'melhorado'
     return new jQuery.fn.init( selector, context, rootjQuery );
     }
jQuery.fn = jQuery.prototype = {
     // Versão corrente do jQuery
     jquery: core_version,

     constructor: jQuery,
     init: function( selector, context, rootjQuery ) {
         var match, elem;

          // Manipula: $(""), $(null), $(undefined), $(false)
          if ( !selector ) {
               return this;
               }
      },
      size: function() {
      return this.length;
      },
      version: function() {
         return this.jquery;
         }
   }
   window.jQuery = window.$ = jQuery;
   jQuery.fn.init.prototype = jQuery.fn;


})( window );


E o código HTML que chama este objeto (porque realmente é um objeto).

rtQuery.html


<!DOCTYPE html>
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1" />
            <title>jQuery Demo</title>
                <script type="text/javascript" src="tQuery.js"></script>
       </head>
       <body id="b1" name="nb1" OnLoad="inicia();">
             <p id="p1" name="np1">xxx xxx xxx</p>
       </body>
       <script>
              function inicia(){
                  var a = $("#p1").version();
                   }
       </script>
</html>

Explicação:


Definimos um breakpoint na linha da instrução da função inicia (var a = $("#p1").version()):

Instanciação da classe jQuery no interior do arquivo tQuery.js
Ao utilizarmos a diiretiva "new", criamos uma nova instância do objeto jQuery.

A classe jQuery tem um protótipo para as funções (fn)
O protótipo da classe possui um construtor (constructor) e seus métodos: init, size e version (em nosso caso reduzido para melhor compreensão).

Como o método chamado foi "init", foi nele que o debug entrou, com o parâmetro "selector" tendo carregado o valor "#p1". O teste "! selector" devolve verdadeiro se nenhum seletor tiver sido fornecido. Como existe um seletor fornecido ("#p1"), 


o processamento pula para a segunda chave, se preparando para retornar. E o retorno se dá na linha posterior ao método "init":
 

O retorno posterior se dará de volta ao html (rtQuery.html):


E como mágica, o processamento avança para o método após o ponto (".") do seletor, ao invés de avançar para a linha 17.


Desta vez, não há nova instanciação da classe jQuery. O método "init", que é uma abstração da classe jQuery, se confunde com ele mesmo, devolvendo a própria instância obtida nos passos anteriores (this). E o processamento vai direto ao método "version" chamado.


E no passo seguinte, o processamento vai para a chave que fecha o método "version". E desta forma,


é devolvido o valor da versão que demos ao jQuery, e o processamento avança para a chave da linha 17 no HTML que provocou a instanciação do jQuery.

É basicamente este o mecanismo e a filosofia do jQuery que utilizamos, e que "quebra tanto o nosso galho".

Uncaught TypeError: $(...). ... is not a function

Vamos demonstrar qual é a natureza dos retornos do jQuery. Vamos tentar reaproveitar métodos do jQuery após um retorno de método. Vamos acrescentar uma chamada ao método "size" na linha 16:

var a = $("#p1").version().size();


Por que este erro ocorreu ?

O método "size" é um método de jQuery. O método 'version" nos devolveu uma string (this.jquery). Quando tentamos usar o método "size" sobre uma string, obtivemos o erro. Mas o debug não avisa, por exemplo que "...version().size is not a string", e sim que "version(...).size is not a function". O debug está se referindo a "version()". O método "version", para possibilitar o reuso do objeto jQuery, deveria devolver um objeto da classe jQuery.













Nenhum comentário:

Postar um comentário