<p>Dado um objeto javascript, é possível varrer seus métodos e propriedades e até mesmo serializá-lo. </p>
<p>Para isso devemos fazer uma conversão forçada do objeto para um vetor, e varre-lo. Cada item desse vetor pode ser um método ou uma propriedade. </p>
<p>O que vai dizer se ele é um método ou uma propriedade é que seu tipo, dado pela função typeof():
	<ul>
	<li>quando, como string, for igual a "function" significa que ele é um método ou função. </li>
	<li>caso contrário é uma propriedade.</li>
	</ul>

</p>	
<p>Código da função de serialização</p>	
<pre class="brush: javascript">
			///Transforma um objeto em string considerandp se é null ou undefined
			function ObjToString(obj)
			{
				if(obj === null)
				{
					return "null";
				}
				
				if(typeof obj === "undefined")
				{					
					return "undefined";
				}
					
				return obj.toString();
			}
		
			///escreve as propriedades do objeto na página
			function serialize(obj)
			{
				//coleção de métodos
				var metodos = [];
				//coleção de propriedades
				var propriedades = [];
				
				//varre as propriedades
				for (i in obj) 
				{
					//verifica se não é a própria função
					if (i != "serialize")
					{
						if (typeof(obj[i]) == "function") 
						{
							//se for método adiciona em uma coleção
							metodos.push(typeof(obj[i]) + ": " + i + ": " + ObjToString(obj[i]) );
						}
						else
						{
							//senão adiciona na outra
							propriedades.push(typeof(obj[i]) + ": " + i + ": " + ObjToString(obj[i]) );
						}
					}
				}
				
				//varre as coleções escrevendo na página
				document.write("<strong>metodos</strong><br/>");
				for (m in metodos) 
				{
					document.write(metodos[m]+"<br/>");
				}				
				document.write("<br/><br/><strong>propriedades</strong><br/>");
				for (p in propriedades) 
				{
					document.write(propriedades[p]+"<br/>");
				}				
			}	
</pre>
	
<p>No caso dessa função, ela simplesmente lista as propriedades e métodos e os concatena a seus devidos valores, pulando linha. 
Isso poderia ser feito de outra forma, por exemplo, a função de serialização poderia gerar um JSON e usá-lo em uma requisição ajax, 
ou interpretá-lo com eval() e gerar um clone do objeto em questão (apenas as propriedades, um DTO), ou ainda serializá-lo em XML.
Por enquanto vamos listar os métodos e propriedades na página mesmo. Depois tentamos gravar em uma string ou objeto json.</p>

<p>
	Note o uso do comando for ... in. for (i in obj)  <br/>
	Ele equivale ao foreach do c# e de outras linguagens. Ele varre todos os elementos de um array atribuindo a I o elemento do array de indice x quando for um array, ou a propriedade quando for um ojeto (como se fosse um hashtable/dictionay). 
	Usando esse comando, para uma varredura geral sem armazenar ou utilizar o índice, você pode fazer uma varredura geral em um array sem se preocupar com os limites inferior e superior. 
</p>

<p>
	A função ObjToString apenas verifica se o objeto é nulo ou undefined antes de chamar .toString() nele.
</p>

<p>Abaixo um exemplo de serialização do objeto window:</p>

<pre class="brush: javascript">
	serialize(window);
</pre>

<script>
$(document).ready(function(){
	$("#saida1").hide();
	$("#show1").click(function(){
	  $("#saida1").show();
	});
	
	
	$("#saida2").hide();
	$("#show2").click(function(){
	  $("#saida2").show();
	});
});
</script>

<a id="show1">Com a saída:</a>

<pre id="saida1">
	metodos
	function: postMessage: function () { [native code] }
	function: close: function () { [native code] }
	function: blur: function () { [native code] }
	function: focus: function () { [native code] }
	function: getSelection: function getSelection() { [native code] }
	function: print: function print() { [native code] }
	function: stop: function stop() { [native code] }
	function: open: function open() { [native code] }
	function: alert: function alert() { [native code] }
	function: confirm: function confirm() { [native code] }
	function: prompt: function prompt() { [native code] }
	function: find: function find() { [native code] }
	function: scrollBy: function scrollBy() { [native code] }
	function: scrollTo: function scrollTo() { [native code] }
	function: scroll: function scroll() { [native code] }
	function: moveBy: function moveBy() { [native code] }
	function: moveTo: function moveTo() { [native code] }
	function: resizeBy: function resizeBy() { [native code] }
	function: resizeTo: function resizeTo() { [native code] }
	function: matchMedia: function matchMedia() { [native code] }
	function: getComputedStyle: function getComputedStyle() { [native code] }
	function: getMatchedCSSRules: function getMatchedCSSRules() { [native code] }
	function: webkitConvertPointFromPageToNode: function webkitConvertPointFromPageToNode() { [native code] }
	function: webkitConvertPointFromNodeToPage: function webkitConvertPointFromNodeToPage() { [native code] }
	function: requestAnimationFrame: function requestAnimationFrame() { [native code] }
	function: cancelAnimationFrame: function cancelAnimationFrame() { [native code] }
	function: webkitRequestAnimationFrame: function webkitRequestAnimationFrame() { [native code] }
	function: webkitCancelAnimationFrame: function webkitCancelAnimationFrame() { [native code] }
	function: webkitCancelRequestAnimationFrame: function webkitCancelRequestAnimationFrame() { [native code] }
	function: captureEvents: function captureEvents() { [native code] }
	function: releaseEvents: function releaseEvents() { [native code] }
	function: btoa: function btoa() { [native code] }
	function: atob: function atob() { [native code] }
	function: setTimeout: function setTimeout() { [native code] }
	function: clearTimeout: function clearTimeout() { [native code] }
	function: setInterval: function setInterval() { [native code] }
	function: clearInterval: function clearInterval() { [native code] }
	function: webkitRequestFileSystem: function webkitRequestFileSystem() { [native code] }
	function: webkitResolveLocalFileSystemURL: function webkitResolveLocalFileSystemURL() { [native code] }
	function: openDatabase: function openDatabase() { [native code] }
	function: addEventListener: function addEventListener() { [native code] }
	function: removeEventListener: function removeEventListener() { [native code] }
	function: dispatchEvent: function dispatchEvent() { [native code] }


	propriedades
	object: top
	object: window
	object: location
	object: external
	object: chrome
	object: document
	object: speechSynthesis
	object: localStorage
	object: sessionStorage
	object: applicationCache
	object: webkitStorageInfo
	object: indexedDB
	object: webkitIndexedDB
	object: crypto
	object: CSS
	object: performance
	object: console
	number: devicePixelRatio
	object: styleMedia
	object: parent
	object: opener
	object: frames
	object: self
	string: defaultstatus
	string: defaultStatus
	string: status
	string: name
	number: length
	boolean: closed
	number: pageYOffset
	number: pageXOffset
	number: scrollY
	number: scrollX
	number: screenTop
	number: screenLeft
	number: screenY
	number: screenX
	number: innerWidth
	number: innerHeight
	number: outerWidth
	number: outerHeight
	boolean: offscreenBuffering
	object: frameElement
	object: clientInformation
	object: navigator
	object: toolbar
	object: statusbar
	object: scrollbars
	object: personalbar
	object: menubar
	object: locationbar
	object: history
	object: screen
	object: onautocompleteerror
	object: onautocomplete
	object: ondeviceorientation
	object: ondevicemotion
	object: onunload
	object: onstorage
	object: onpopstate
	object: onpageshow
	object: onpagehide
	object: ononline
	object: onoffline
	object: onmessage
	object: onlanguagechange
	object: onhashchange
	object: onbeforeunload
	object: onwaiting
	object: onvolumechange
	object: ontoggle
	object: ontimeupdate
	object: onsuspend
	object: onsubmit
	object: onstalled
	object: onshow
	object: onselect
	object: onseeking
	object: onseeked
	object: onscroll
	object: onresize
	object: onreset
	object: onratechange
	object: onprogress
	object: onplaying
	object: onplay
	object: onpause
	object: onmousewheel
	object: onmouseup
	object: onmouseover
	object: onmouseout
	object: onmousemove
	object: onmouseleave
	object: onmouseenter
	object: onmousedown
	object: onloadstart
	object: onloadedmetadata
	object: onloadeddata
	object: onload
	object: onkeyup
	object: onkeypress
	object: onkeydown
	object: oninvalid
	object: oninput
	object: onfocus
	object: onerror
	object: onended
	object: onemptied
	object: ondurationchange
	object: ondrop
	object: ondragstart
	object: ondragover
	object: ondragleave
	object: ondragenter
	object: ondragend
	object: ondrag
	object: ondblclick
	object: oncuechange
	object: oncontextmenu
	object: onclose
	object: onclick
	object: onchange
	object: oncanplaythrough
	object: oncanplay
	object: oncancel
	object: onblur
	object: onabort
	object: onwheel
	object: onwebkittransitionend
	object: onwebkitanimationstart
	object: onwebkitanimationiteration
	object: onwebkitanimationend
	object: ontransitionend
	object: onsearch
	number: TEMPORARY
	number: PERSISTENT
</pre>


<p>
	Agora imagine um objeto json, por exemplo pessoa:
</p>

<pre class="brush: javascript">
			var pessoa = {
				nome:"Vitor",
				sobrenome:"Rubio",
				email:"vitorrubio@gmail.com",
				idade:30,
				dataCadastro:"14/10/2014",
				dependente:null,
				hobby:undefined};
</pre>


<a id="show2">Com a saída:</a>

<pre id="saida2">
	metodos


	propriedades
	string: nome: Vitor
	string: sobrenome: Rubio
	string: email: vitorrubio@gmail.com
	number: idade: 30
	string: dataCadastro: 14/10/2014
	object: dependente: null
	undefined: hobby: undefined
</pre>

<p>

	Repare também que foi necessário colocar uma excessão quanto ao método "serialize" para ele não serializar a si mesmo. 
	Se um método for nativo do browser ele é serializado como [native code], mas se for um método seu então todo o source do método é serializado. 
	Veja o poder disso: nas linguagens compiladas como C ou Delphi, ou nas linguagens com compilação Just In Time como C# e Java, os objetos podem ter suas propriedades e valores varridos, serializando-os para xml, json e outros formatos. Mas apenas seus campos e propriedades. NUNCA SEUS MÉTODOS.
	Então nas aplicações, não importa se você usa um banco de dados relacional ou orientado a objeto, você nunca poderia armazenar o código executável (métodos) no banco de dados. Apenas os dados poderiam ser armazenados. Isso significaria ter que tratar os dados com functions e stored procedures no banco de dados ou reconstituir o objeto e tratar na aplicação. 
	Com javascript é diferente. Você pode salvar o SOURCE de métodos e argumentos em um banco de dados, trazêlos de volta a vida com eval(), JSON.parse ou jQuery.parseJSON e executar as mesmas funções que eles já possuiam.
	Não é possível fazer isso com JSON.parse(), apenas com eval, pois entende-se que o JSON é apenas para transferência de DADOS. Mesmo assim você pode embutir o eval como mostrado <a href="http://ovaraksin.blogspot.com.br/2013/10/pass-javascript-function-via-json.html">nesse link</a>

</p>

<p>
	O método abaixo faz o mesmo que o serialize, mas joga o resultado em uma string.
</p>

<pre class="brush: javascript">
			///o mesmo que serialize só que retornando uma string
			function SerializeObjToString(obj)
			{
				var metodos = [];
				var propriedades = [];
				var resultado = "";
				
				for (i in obj) 
				{
					//tirada a restrição do "serialize". Deixa trazer tudo. 
						if (typeof(obj[i]) == "function") 
						{
							metodos.push(typeof(obj[i]) + ": " + i + ": " + ObjToString(obj[i]) );
						}
						else
						{
							propriedades.push(typeof(obj[i]) + ": " + i + ": " + ObjToString(obj[i]) );
						}
				}
				
				//a string já é formatada
				resultado+="<strong>metodos</strong><br/>";
				for (m in metodos) 
				{
					resultado+=metodos[m]+"<br/>";
				}				
				resultado+="<br/><br/><strong>propriedades</strong><br/>";
				for (p in propriedades) 
				{
					resultado+=propriedades[p]+"<br/>";
				}	

				return resultado;
			}
			
</pre>


<p>
	O método abaixo transforma o objeto javascript em uma string JSON.
</p>

<pre class="brush: javascript">
			///gera uma string json para ser interpretada com eval ou json.parse
			///não é segura quanto à recursividade, referência cíclica
			function SerializeObjToJSON(obj)
			{
				var metodos = [];
				var propriedades = [];
				var resultado = "";
				
				for (i in obj) 
				{
					//tirada a restrição do "serialize". Deixa trazer tudo. 
						
						//verifica primeiro se o objeto é undefined, para retornar undefined 
						if(typeof (obj[i]) === "undefined")
						{							
							metodos.push("\""+i+"\"" + ":" + "\"undefined\"" );
						}
						//se for uma function retorna o corpo da mesma com ObjToString sem aspas
						else if (typeof(obj[i]) == "function") 
						{
							metodos.push("\""+i+"\""  + ":"  + ObjToString(obj[i]) );
						}
						//se for um número usa ObjToString para retornar sem aspas
						else if (typeof(obj[i]) == "number") 
						{
							metodos.push("\""+i+"\""  + ":" + ObjToString(obj[i]) );
						}
						//se for objeto verifica se é nulo ou não
						else if (typeof(obj[i]) == "object") 
						{
							//se for nulo simplesmente concatena null
							if(obj[i] === null)
							{
								metodos.push("\""+i+"\""  + ":" + "\"null\"" );
							}
							//senão chama a propria função e serializa recursivamente
							else
							{
								metodos.push("\""+i+"\""  + ":" + SerializeObjToJSON(obj[i]) );
							}
						}
						else
						{
							//senão assume que é string e poe entre aspas. Se tiver errado é fácil alterar. 
							propriedades.push("\""+i+"\""  + ":\"" + ObjToString(obj[i])+"\"" );
						}
				}
				
				//começa e termina entre chaves
				resultado+="{";
				for (var m = 0; m<metodos.length; m++) 
				{
					resultado+=metodos[m];
					if(m == metodos.length-1)
					{
						//se for igual só adiciona virgula se também tiver propriedades
						if(propriedades.length > 0)
						{
							resultado+=",";
						}
					}
					else
					{
						resultado+=",";
					}
					resultado+="\r\n";
				}				
				
				for (var p = 0; p<propriedades.length; p++) 
				{
					resultado+=propriedades[p];
					
					if(p < propriedades.length-1)
					{
						resultado+=",";
					}
					
					resultado+="\r\n";
					
				}
				resultado+="}";		

				return resultado;
			}
</pre>



<p>
	Que pode ser transformada de volta em objeto da seguinte maneira.
</p>

<pre class="brush: javascript">
				function evalJson()
				{	try
					{
						//poe a string entre parenteses antes do eval						
						var txt = SerializeObjToJSON(pessoa);
						alert(txt);
						//var obj = eval("(" + txt + ")"); //para usar eval
						var obj = JSON.parse(txt); //para usar JSON.parse nativo
						//var obj = JSON && JSON.parse(txt) || $.parseJSON(txt); //para decidir de acordo com o browser se vai usar JSON nativo ou a versão do jQuery
						alert(obj.email);
					}
					catch(e)
					{
						alert(e.message);
					}
				}
</pre>




<p>
	Bom, por enquanto é isso. Acredito que esse é o meu maior post sobre javascript. Pretendo postar amanhã uma galeria com jQuery e dar uma organizada nesse blog. Have fun :)
</p>