Olá, achei muito interessante a idéia desse blog e me cadastrei porque queria dar alguma contribuição. Estou aqui pra falar sobre técnicas de programação em Javascript, já que eu gosto mais da parte algorítmica da coisa. Não sou fã de frameworks e ainda que eu use para facilitar e agilizar meu trabalho não é minha paixão.

Eu precisava de uma função que pegasse elementos pela classe e vi várias implementações de “getElementsByClassName”, mas queria aprender como fazer e fazer da minha forma.

Pensei, pensei, pensei, testei, testei, pensei…NADA! Tinha muito erro de lógica, cada vez que eu consertava criava um problema novo. Precisava procurar um algoritmo que resolvesse esse problema, pra isso tive que aprender um conceito novo (para mim) uma estrutura de dados chamada Árvores.
Afinal de contas a estrutura do HTML não é a de uma árvore?

Aprendi no Wikipédia o algoritmo, peguei o primeiro código recursivo que tinha em “C” lá e implementei em Javascript. Vergonhoso, a solução tinha 7 linhas. Ok, mas a recursão para funcionar empilha os dados, sabendo disso era só implementar uma Pilha (isso eu sabia o que era) para fazer a versão iterativa da travessia da árvore em pré-ordem (filhos são processados após o pai):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function getEBA(no, classe){
  var retorno=[]
  var pilha=[]
  pilha[pilha.length]=no
 
  //Enquanto a pilha contiver elementos...
  while(pilha.length > 0){
 
    // Guardo o primeiro elemento da pilha em "no"
    no=pilha[pilha.length-1]
 
      // Se o nodo tiver classe e for a que eu procuro,
      // empilho o elemento no array de retorno.
      if(typeof no.className!=”undefined” && no.className==classe)
      retorno[retorno.length]=no
 
    // Desempilho o nó atual da pilha.
    pilha.pop()
 
      // Se o nó atual tiver filhos, empilho os filhos na pilha[]
      if(no.childNodes)
        for(var x in no.childNodes)
        pilha[pilha.length]=no.childNodes[x]
    }
 
  return retorno
}

Mas o algoritmo tinha limitações como os outros que tinha visto. Eu não poderia escolher uma condição… a função só funcionaria para classes. E se eu quisesse usar um dia a função para pegar elementos pelo atributo “type” ou “language” ou qualquer outro? A função precisaria ser mais genérica. Outro problema.

Solução? Usar um pouquinho de Programação Funcional:

12
13
14
15
      // Se o nodo tiver classe e for a que eu procuro,
      // empilho o elemento no array de retorno.
      if(fn(no))  // A condição é definida pela função.
      retorno[retorno.length]=no

A condição então não é mais fixa, ela é definida por uma outra função passada como argumento na função principal e esse não será mais “classe” e sim “fn”.

Então, se quisesse pegar os elementos do div “divPai” que tenham apenas uma classe chamada “h-card”:

17
18
19
20
21
22
23
24
25
var classes=getEBA(
  document.getElementById("divPai"),
    function(obj){
      return(
      typeof obj.className!="undefined" &&
      obj.className=="h-card"
      )
    }
)

Agora sim. Nesta minha “busca algorítimica” implementei 4 conceitos muito interessantes que não havia dado muita atenção: Pilhas, Árvores, Programação Funcional e até Expressões Regulares.

Expressões Regulares? Sim, se eu quisesse pegar elementos que tenham “ieHOVER” sendo que esses elementos poderiam ter mais de uma classe:

27
28
29
30
31
32
33
34
35
var ieHover=getEBA(
  document.getElementById("divPai"),
    function(obj){
      return(
      typeof obj.className!="undefined" &&
      obj.className.match(/ieHOVER/)
      )
    }
)

Não chamo de “getElementsByClassName”, chamo de “getElementsByAnything”, o getEBA =). Se for interessante para você, pode executar a tarefa nos nodos usando a função passada como argumento ao invés de fazer isso percorrendo o array retornado, que agora é uma mera opção. =P

Mas minha intenção não era o código em si mas mostrar alguns dos obstáculos inevitáveis que surgem durante o processo de desenvolvimento e como contorná-los diminuindo drásticamente sua dificuldade.

É importante conhecer as diversas técnicas de programação e mais importante que conhecê-las é saber identificar a natureza do seu problema para só então procurar a solução e botar a mão na massa. Já pensaram nas coisas complicadas, para que perder tempo pensando do zero tudo de novo???

Bom, é isso… desculpem ficou longo o post, to engatinhando ainda e é meu primeiro post em blog (se for aceito).

Comentem, sugestões e críticas construtivas são bem-vindas. Você tem uma idéia melhor? Me ensina!

Ah…a frase do título foi inspirada numa citação de Albert Einstein.

Abraços e ótimo 2008 para todos.