Função Dollar do Prototype para capturar elementos HTML

Enquanto não preparo um material exclusivo sobre manpulação DOM da especificação W3C, gostaria de falar sobre o encapsulamento dessas operações que os Frameworks Javascript fazem.

A funcionalidade principal de todos os Frameworks, é abstrair a complexidade da manipulação DOM, que não é tão complexa assim mas é chata para muitos. Como o DOM é o acesso aos elementos, e dependemos deles para montar a UI (User Interface) das aplicações, todos (Frameworks) tentam minimizar ou associar essa manipulação com a facilidade de linguagens UI que temos costume no desktop.

O Extjs por exemplo, tem o objeto Ext.Element que representa um elemento DOM e possui métodos amigáveis como: Ext.get(id), para capturar um elemento, Ext.get(“my-div”).setWidth(100) para setar uma largura de 100 pixels a um elemento capturado, entre outros métodos.

O Bruno Torres em seu projeto, O Básico da web, escreveu um artigo básico sobre captura de elementos HTML. Esse artigo me inspirou a falar sobre a função $ (Dollar) famosa no Framework Prototype pela simplicidade. Quem quiser aprender como se seleciona um elemento DOM, dê uma olhada no artigo, lá está bem explicado e com uma didática legal.

A função $ (Dollar), símbolo do uso do Prototype, representa um mecanismo “conveniente” de captura de um elemento, presenteado com métodos auxiliares para a manipulação do DOM em um lote de elementos.

Para capturar o elemento DOM, você precisa usar a sintaxe:

var el = document.getElementById("id_elemento");

A partir daí podemos selecionar ou alterar suas propriedades como:

alert(el.innerHTML); // exibe o conteúdo

Enquanto no Prototype, a função $ providencia um acesso mais limpo:

var el = $("id_elemento");

Essa função é amada por todos os desenvolvedores javascript, a construção dela é absolutamente simples:

function $(els) {
	this.elements = [];
	for (var i=0; i < els.length; i++) {
		var element = els[i];
		if (typeof element == 'string') {
			element = document.getElementById(element);
		};
		this.elements.push(element);
	};
	return this;
};

O código da função acrescenta os elementos passados como parâmetros (caso queira capturar vários, apenas separe por vírgula) em uma propriedade array na função. Caso o parâmetro seja uma String, um elemento é capturado pela forma tradicional usando essa String (que deve ser referência a um ID) e acrescentado no array, a cláusula return devolve o escopo da própria função.

A função $ é enriquecida com funçõse que manpulam esse conjunto de elementos. A lógica é que ao retornar esse elemento(s), uma função seja acionada e manipule esse elemento (ou conjunto deles). Essas funções podem ser adicionadas via prototype (propriedade herdada da Global que representa o escopo interno de todos os objetos):

$.prototype = {    
	each: function(fn) {
		for ( var i=0,len=this.elements.length;i++) 
		{
			fn.call(this, this.elements[i]);
		};
		return this;
	}
}

Assim, ao selecionar vários elementos, podemos aplicar essas funções diretamente. Outras funções podem ser adicionadas usando o prototype, criando um ecosistema elementar para manipulação desses elementos.

Veja como a aplicação dessa função reduz o código necessário para acionarmos um elemento diretamente e aplicarmos uma instrução que se feita por DOM, levaria várias linhas:

$('botao').on('click', 
	function() { 	
		$('teste').each(
			function(el){
				alert(el.value);
		});
		alert($('teste').value);
	});
}

Nos próximos posts, destilaremos vários frameworks e como cada um faz sua manipulação.

[UPDATE 10-02-2008]

Para exemplificar melhor como trabalha o Framework Prototype, Devido aos comentários do Edu, ficou faltando código para compreender como a função “$” está disponível no código.

Nas versões antigas do framework, eles faziam assim:

  1. Cria-se uma função privada no contexto referenciada por _$;
  2. Retorna uma instãncia dessa função _$ referenciada a $;

Como fica isso em código:

  // função privada com o código que vimos nesse post
  function _$(els) {
    this.elements = [];
    for (var i=0; i<els.length;>
      var element = els[i];
      if (typeof element == 'string') {
        element = document.getElementById(element);
      };
      this.elements.push(element);
    };
    return this;
  };
</els.length;>

Cria a função global “$” com referência a uma instância da função privada “_$”

  $ = function() {
    return new _$(arguments);
  };

O código completo ficaria assim:

(function() {
  function _$(els) {
    this.elements = [];
    for (var i=0; i<els.length; i++) {
      var element = els[i];
      if (typeof element == 'string') {
        element = document.getElementById(element);
      };
      this.elements.push(element);
    };
    return this;
  };
 
  _$.prototype = {
    each: function(fn) {
      for ( var i = 0, len = this.elements.length; i<len; ++i ) {
        fn.call(this, this.elements[i]);
      };
      return this;
    },
    setStyle: function(prop, val) {
      this.each(function(el) {
        el.style[prop] = val;
      });
      return this;
    },
    addClass: function(className) {
      this.each(function(el) {
        el.className += ' '+className;
      });
      return this;
    },
    css: function(o) {
      var that = this;
      this.each(function(el) {
        for (var prop in o) {
          that.setStyle(prop, o[prop]);
        };
      });
      return this;
    }
  };
  $ = function() {
    return new _$(arguments);
  };
}());

Observe que hoje ficou bem mais rebuscado no código das últimas versões, mas o conceito é o mesmo.

8 thoughts on “Função Dollar do Prototype para capturar elementos HTML

  1. Pingback: Resumo javascript - Jan 2008 - CMilfont Tech

  2. cmilfont Post author

    Edu, a função dollar “$” está disponível ao acrescentar o script do prototype sem a necessidade de instanciação de qualquer novo objeto. Como você fez que não funcionou?

  3. Edu

    Oi Christiano, eu tentei simplificar ao máximo para eu entender o conceito.

    function $(id){
    var obj=document.getElementById(id)
    return this
    }

    Tentei adicionar um método por prototype:
    $.prototype.color=function(cor){obj.style.color=cor}

    Na hora de chamar a função: $(“caixa”).color(“blue”), dava erro:
    “objeto não dá suporte ao método”. Ou seja, não existe o método.

    Quando eu colocava o método “color” dentro do corpo da função funcionava . Mesmo quando eu testei na base do copy & paste seu código não funcionou, dava o mesmo erro.

    Eu queria saber como não conheci seu blog antes…Seu blog é daqueles que eu considero “chato” porque tem tanta coisa interessante que a gente se perde…rsrsrs

    Ganhou um leitor assíduo rsrs

    Abraço

  4. cmilfont Post author

    Ah, agora entendi! Pensei que você estava se referindo ao Framework Prototype.
    Se voce acrescentar o script dele na sua página diretamente, verá que funciona -> http://www.prototypejs.org/assets/2008/1/25/prototype-1.6.0.2.js

    Qual o segredo aqui, antigamente eles faziam assim:
    1 – definiam uma função privada ao escopo do script chamada de function _$() {…}
    2 – retornava uma instância dessa função referenciada à variável $.

    Observe o update que fiz no post.

  5. Edu

    Agora simmm!!! Entendi!!!!

    Muito interessante isso. Olha se vc for mesmo destrinchar os frameworks vai ser muito bom!! Vai ser muito interessante e didático.

    Uma referência assim seria até agora inédito, acho, já que não vi ninguém fazer.

    Abraços

  6. Paulinholiveira

    Tentei aqui $(‘Loading’).css(‘display’, ‘block’) e nao deu certo estou chamando errado? vc poderia fazer uma pagina de exemplo?

  7. José A M Pacheco

    I made a page with only the following:

    before the

    console.log (cpf.value); // “Anything”

    tested in chrome 36; IE8 and IE11 and latest version firefox and it worked in all of them.
    Because this work? This makes obsolete document.getElementById?

Comments are closed.