Você está na página 1de 296

JavaScript

Objetos
Arrays e Funcões
Conceitos Importantes
Tony de Araujo, Technical Writer
New Jersey, Janeiro 2014
copyright © 2013 Tony de Araujo
All Rights Reserved
Sendo este livro em formato eBook e com hiperligações para ficheiros onde se encontram versões
reais dos exercícios aqui demonstrados, o leitor tirará mais proveito se ler o livro no seu
computador. Amazon tem vários aplicativos gratuitos que são bastante práticos para esse efeito.
Carregue no link indicado, selecione o leitor mais apropriado para o seu tipo de computador e
baixe o aplicativo.
"Excelência não é técnica, é atitude."

-- Soren Kierkegaard
A todos os professores e autores de quem aprendi, a minha gratitude.
À minha família, estudantes e amigos por este mundo afora,
um Grande obrigado!
INDEX
INDEX

Prefácio

Nota do Autor

Representação de Cores Neste Livro

Protótipos versus Classes

O Conceito de Memória

Variáveis versus Valores de Referencia

Em JavaScript Tudo Vem de Objetos


Lab 1
Lab 2

Mais Variáveis , Introdução de Funções


Lab 3

Funções com Nome vs. Funções Anônimas

Primeira Revisão

O Intocável Object
Objetos Nativos
Objetos Hospedados, Hosted Objects
O que é uma propriedade?
O que é um variável?
O que é um contexto de execução?

Segunda Revisão

O Objeto Window – Intro


Um exemplo de escopo

Mais Valores Primitivos e Valores de Referência


Como passar data de stack para o heap

PARTE 2

2.1. Strings como Objetos em JavaScript


2.1.2 charAt( ) e charCodeAt( )
2.1.3 fromCharCode( )
2.1.4 concat( )
2.1.5 indexOf() e lastIndexOf( )
2.1.6 match( )
2.1.7 replace( )
2.1.8 search( )
2.1.9 slice( )
2.1.10 split( )
2.1.11 substr( )
2.1.12 substr( ) vs substring( )
2.1.13 toLowerCase() and toUpperCase()
2.1.14 trim( )
2.1.15 valueOf( )
Sumário: métodos do Objeto String

2.2 Array como Objects em JavaScript


2.2.1 concat()
2.2.2 join( )
2.2.3 reverse( )
2.2.4 sort( )
2.2.5 pop( ) e push( )
2.2.6 shift() e unshift()
2.2.7 slice( )
2.2.8 splice( )

2.3 Novos Métodos de Iteração com Arrays em JavaScript


2.3.1 forEach()
2.3.2 map( )
2.3.3 every( )
2.3.4 some( )
2.3.5 filter( )

2.4 Novos Métodos de Redução e Localização para Arrays em JavaScript


2.4.1 O que é Redução
2.4.2 reduce( )
2.4.3 reduceRight( )
2.4.4 Métodos de Localização
2.4.5 indexOf( ) versus lastIndexOf( )

2.5 Funções de JavaScript e Argumentos como Objetos


2.5.1 O objeto arguments
2.5.2 Funções dentro de Funções
2.5.3 Uma Introdução Gentil a Closures
2.5.4 O princípio de closure
2.5.5 Escopo Léxico
2.5.6 O objeto arguments versus funções internas
2.5.7 O variável “this”
2.5.8 Funções como Construtores de Objetos
2.6 Propriedades e Métodos de Função
2.6.1 apply( ) e call( )
2.6.2 Adicionando mais argumentos a call( ) e a apply( )
2.6.3 Mais prática com call( ) e apply( )

2.7 O objeto Math


2.7.1 Math.random( ), floor( ), ceil( ), round( )
2.7.2 Math.max( ) e Math.min( )
2.7.3 Math.pow( ), Math.sqrt( ), Math.abs( )
2.7.4 Constantes no Math, PI
2.7.5 Referências úteis: Objeto Math

2.8 O objeto Date


2.8.1 Convertendo objeto Date para string
2.8.2 Bibliotecas úteis de Date em JavaScript

2.9 Listas Associativas como Objects


2.9.1 Métodos acessores
2.9.2 Métodos de mutação
2.9.3 Revisão e prática: Criando uma aplicação para empréstimo
2.9.4 Como executar um método automaticamente
2.9.5 Prototipagem de novos métodos
2.9.6 Objetos que herdam de outros objetos
2.9.7 Como incluir métodos protótipos dentro de um construtor

Em Conclusão

Mais uma coisa…

APPENDIX
Resources
Errata and Contact
Copyright
Prefácio
JavaScript, Objetos Arrays e Funções vem a preencher um vácuo entre as publicações
desenhadas para ensinar sintaxe e livros sobre implementações especificas da linguagem
ECMAScript. Este método compreensivo cobre o básico fundamental de Objetos em JavaScript
sem pedir a alguém que memorize construções que raramente serão usadas no mundo real de
desenvolvimento em JavaScript. O leitor navegará muito naturalmente pela anatomia de objetos
JavaScript dominando os conceitos sem grande esforço. O único prerequisito é a vontade e
disciplina de ler e fazer os exercícios em cada tópico.
JavaScript, Objetos Arrays e Funções é mais sobre conceitos do que sobre implementação de
scripts exóticos que poderão perder a atenção do leitor antes que ele tenha a chance de dominar a
essência do tópico. E porque JavaScript é uma língua complexa (mas não complicada), o autor
decidiu simplificar (sem diminuir) certos conceitos em áreas que poderão ser novas para uma
grande maioria de leitores. Um exemplo é o de closures. O autor ataca o tema de closures de uma
forma minimalista mas ao mesmo tempo profunda, com ilustrações e scripts simplificados para
que o conceito não se perca na complexidade da codificação em si.
A intenção do autor é a de apresentar este trabalho da maneira como gostaria de ter tido quando
iniciou os seus estudos em JavaScript. Este livro não é para principiantes porque não cobre regras
de sintaxe. No entanto, se o leitor já foi exposto ao básico de JavaScript em outro sitio, não terá
dificuldades em compreender o material aqui exposto. Por outro lado, se já tem experiência em
outra língua, ou se apenas necessita uma relembrança, haverá sempre uma explicação linha por
linha dos scripts aqui apresentados.
Cada tópico é mantido curto de propósito, mas aqui encontrará informação que geralmente não
aparece em livros introdutórios e muitas vezes nem sequer em livros mais avançados. O autor
assume que qualquer pessoa com interesse suficiente para aprender JavaScript tem a capacidade
de o fazer se lhe derem tal oportunidade.
O livro não foi só escrito para novos desenvolvedores. É também dirigido aqueles que já estão
envolvidos com JavaScript, mas que não têm tempo para andar procurando as razões porque
certos mecanismos de JavaScript funcionam da maneira como funcionam. Este livro é o resultado
de muitas centenas de horas de investigação e teste da parte do autor, com o intuído de oferecer a
cada leitor algo importante que lhe retribua pelo tempo despendido na sua leitura.
JavaScript, Objetos Arrays e Funções dar-lhe-á a fundação básica necessária que lhe permitirá
avançar para livros mais complexos. Abrirá muitas portas de compreensão sem insultar ou julgar
a inteligência de cada um.
Bem vindo à primeira edição de JavaScript, Objetos Arrays e Funções.
Nota do Autor
Estimado leitor, obrigado pelo tempo despendido na investigação deste livro. Com tantos livros
por ler, é realmente uma honra e uma experiência singela para um autor saber-se ser lido. Pode ter
a certeza de que trabalharei duro na escrita deste projeto para poder merecer tal escolha.
Este livro é pratico e requer as mangas da camisa arregaçadas. Teoria e laboratório juntam-se
para trazer conceitos a uma compreensão máxima. O livro poderá ser uma leitura bem rápida,
pode também ser utilizado como referencia, ou então pode ser executado. Eu sugiro esta ultima
opção. Depois, mais tarde poderá então regressar para ler ou investigar ao acaso.
Com a exceção de scripts de linha singular, todos os outros scripts terão um link para uma copia
raw no meu servidor. Assim poderá copiar e colocar no Console se não desejar codificar à mão.
A escolha será sua.
O livro explica a execução dos novos métodos disponíveis para cada objeto original do
JavaScript. E se desejar criar seus próprios objetos e métodos, haverão também vários capítulos
que abordam esse tema num sentido mais aplicativo do que teórico, limitando o tópico apenas ao
que funciona deixando outras teorias de lado. Despendi muitos dias meditando em cada tópico de
forma a o trazer à escrita de maneira que fosse entendido por alguém que não venha de outra
linguagem semelhante. É com certeza o mínimo que posso fazer por quem investe o seu tempo
lendo este trabalho.
Objetos Nativos (os que vêm originalmente com JavaScript) são os mais utilizados na
implementação da língua. Tendo sido programados em formato mais chegado à maquina, eles são
mais rápidos e mais bem reconhecidos pelos browsers modernos. No entanto, muitos autores
decidem ensinar a criação de novos objetos logo desde o principio, confundindo o leitor com
terminologia e conceitos que o estudante raramente implementará em JavaScript na sua vida real.
Penso que esta maneira de escrever imita a maneira como outras linguagens são ensinadas. Mas
JavaScript não é outra língua. JavaScript é uma combinação de ECMAScript com a mistura do
ambiente onde se encontra ativo. É uma língua mutante: porta-se de maneira diferente
dependendo de como e onde está sendo utilizada. Até o Objeto Global não é acessível na sua
forma original; Ele se torna o interface entre ECKMAScript e a plataforma anfitriã, como por
exemplo o browser. No browser , o Objeto Global transforma-se no objeto window e é assim que
ele tem que ser endereçado.
Neste livro, conceitos virão em camadas. Dizem que JavaScript é uma língua fácil. Mas ela não é
tão fácil como parece, por vezes até é bem complexa. Complexa no sentido em que reside no seu
próprio mundo. A lenda diz que Brendan Eich, o inventor de JavaScript, queria construir uma
língua do tipo Scheme (um dialeto da Lisp), mas a realidade bateu à porta e ele teve que colocar
uma capa na língua para que a sintaxe se parecesse com C/Java a fim de poder acomodar os
milhares de programadores já existentes. Na publicação oficial da ECMAScript 5 diz assim:
“Algumas das facetas de ECMAScript são semelhantes aquelas utilizadas por outras línguas, em
particular Java™, Self, e Scheme”
Hoje, muitos programadores odeiam a língua pelo que ela não é; mas depois de conhecerem
JavaScript mais a fundo, eles amam a língua pelo que ela é. Eu certamente que a aprecio bastante
porque me surpreende todos os dias de forma muito positiva.
Obrigado pela oportunidade,
Tony de Araujo
- Technical writer – New Jersey, 2014
Representação de Cores Neste Livro
· LARANJA - Novo termo ou elemento: anotar mentalmente.
· CASTANHO - Termo já introduzido.
· VERDE - Nova ação a tomar, geralmente é aplicado a código que tem que ser escrito
pelo leitor: Focar na ação.
· AZUL - Azul representa hiperligação (externa ou interna) para leitura relacionada.
· AZUL - O Azul é também utilizado para anotações relacionadas com o tópico e serve
para chamar atenção.
· Vermelho – Aplicado a termos importantes. Serve apenas para quebrar a monotonia.

· Lilás – O lilás é aplicado a títulos de capitulo e esporadicamente a frases de interesse.


Para conveniência do leitor, imagens de scripts terão links para um script real. O script será em .txt
e no livro terá o nome de arquivo raw.
Neste livro o autor utiliza o Console de JavaScript da Google Chrome. Uma vez no Chrome browser,
pode acessar o Console clicando na sequencia de teclas CTRL+SHITF+j para as Windows ou
CMD+OPT+j para Mac. Quando abrir pela primeira vez o Console, separe-o do browser
carregando no quadradinho ao fundo na esquerda. Se não tem Google Chrome no seu computador,
pode-o baixar através do seguinte endereço: Google Chrome.
Não existe razão para memorizar absolutamente nada neste livro. Por favor siga as instruções dos
exercícios discutidos em cada capitulo. Repetição dos exercícios é o segredo para dominar o assunto
em questão.
Cada tópico é curto e direito ao assunto. Muitas das questões serão repetidas conforme seja
necessário e com uma explicação mais profunda na segunda ocasião. Uma cebola descasca-se em
várias camadas.
Os links externos serão apenas para sua conveniência e não para promover qualquer sítio que seja.
Métodos terão link direto para a fonte original da Standard ECMA-262. Por vezes esses links levam-
nos para a página principal da ECMA-262. Isto é devido a algo errado no sítio em si. Geralmente se
clicar uma segunda vez será redirecionado para o tópico em questão.
“Esvazie seu copo, aceite uma nova ideia”, como todo o cinturão negro faz pela manhã em cada dia.
Protótipos versus Classes
Porque o JavaScript é tudo sobre criar e destruir objetos, compreender a peculiaridade dos
objetos de JavaScript é o passo mais importante para poder dominar esta língua.
Vamos então revisitar JavaScript entrando pela porta do lado, embora a entrada menos utilizada
nestas andanças.

JavaScript é uma língua orientada a objetos mas baseada em protótipos. Não é uma língua
baseada em classes.
Ambas as línguas, as baseadas em protótipos ou as baseadas em classes têm um propósito comum:
a partilha de código para evitar redundância.
Nas linguagens baseadas em classes o programador cria um blueprint e a partir daí nascem
objetos baseados em tal diagrama.
Na linguagem baseada em protótipos o programador constrói um objeto e permite que esse
objeto se torne o protótipo de objetos futuros. Evita assim a repetição de código tornando a
execução mais eficiente. A partir deste ponto, a semelhança entre protótipos e classes começa a
perder validade pois as diferenças vão aumentando. E como o JavaScript permite a lincagem de
objetos entre eles numa herança prototipa, métodos podem ser reusados formando uma cadeia
associativa. Quando um objeto necessita de um método, começa procurando nele mesmo, e se não
encontra, vai subindo a cadeia associativa de protótipo em protótipo até encontrar o método que
busca. O primeiro método que encontrar com o nome associado à pesquisa será o que irá utilizar.
É importante manter este conceito em mente para evitar a chamada de métodos errados.
Este modelo sem classes, conhecido também como instance-based porque é baseado na criação
de instâncias do modelo mãe, funciona num processo conhecido como delegação, ou seja, um
objeto dependendo do processo metódico de outro objeto para criar sua própria funcionalidade.
Este paradigma resulta porque JavaScript depende do seu ambiente de real-time para fazer sua
magia. Este processamento a tempo-real é como água no rio, nunca é o mesmo quando olhamos
uma segunda vez. Estarmos a par deste ambiente em real-time é importante para compreendermos
como JavaScript funciona no que diz respeito a escopos ou ambientes de trabalho.
Só porque JavaScript pode imitar muitas das técnicas de línguas baseadas em classes utilizando
protótipos, não significa que seja uma linguagem baseada em classes. Alguém disse um dia que
familiaridade rouba as bordas da admiração. Vamos admirar o JavaScript pelo que ele é e não
com quem ele se possa parecer. JavaScript não é Java e nem é Lisp.
Haverá alguma vantagem em implementação prototipa versus línguas baseadas em classes?
Existe um artigo na Wikipedia que expande este assunto pelo que deixo como referencia.
O Conceito de Memória
A gestão de memória ou seja o ato de gerenciar memória, pode ser explicito na sua forma mais
simples como a alocação de blocos de memória e a reciclagem dos objetos que deixam de ter
validade. A reciclagem é essencial para poder dar espaço virtual a outros novos objetos. Esta
reciclagem é de certo modo gerenciada pelo browser e cada modelo de browser tem uma maneira
especifica de o fazer. Se estiver interessado em explorar este assunto para além do escopo do
livro, visite os seguintes links da Wikipedia: Gerenciamento de memória , Coletor de lixo.
Em termos gerais a memoria é subdividida em duas áreas distintas: o stack e o heap.
O stack é uma estrutura de data mais restrita. Somente um número limitado de operações atua
neste campo.
Quando cada operação finaliza, a data é automaticamente retirada para dar espaço a outra. De
certo modo o stack atua como um rascunho de operação de memória. A data aqui apresentada é
bastante curta, como por exemplo, apontadores (nomes de variáveis).
A seção heap é uma outra história. Para começar, no heap, data não é tão bem organizada como é
no stack. Aqui, blocos de data podem ser guardados de um modo ad-hoc porque no heap, se um
bloco de data necessita de ser aumentado, o heap tem permissão para o fazer conforme assim
precisar. Isto faz com que o heap seja relativamente mais vagaroso do que o stack. A memoria do
stack é bem mais rápida porque cada tipo de data tem um tamanho especifico e está sob uma
supervisão estrita.

Figure 1 A picture is worth a gazillion words

Em JavaScript, valores primitivos são guardados no stack e valores de referencia são


guardados no heap. Lembre-se de “valores de referencia”, falaremos muito sobre esses valores.
Não tente memorizar a informação que se segue. Apenas leia e compreenda. Nós revisitaremos
todos estes conceitos em mais detalhe durante o processo de descasque desta cebola a que
chamamos JavaScript.
Valores primitivos em JavaScript refere-se ao type (tipo) de valores como Number, Boolean,
String, Null e Undefined. Estes são valores simples e eles são guardados diretamente no sítio do
endereço do variável (no stack). Variáveis são simplesmente rótulos ou símbolos que apontam
para a data mais extensa no outro lado da memória, no heap. É tal e qual em álgebra em que x e y
são variáveis apontando para um numero real.
Valores de referencia por seu lado, têm o seu nome de variável guardado no stack (servindo de
apontador para a verdadeira data). Esta data (valores de referencia) é guardada no heap.

Por falar em primitivos, o type Undefined é atribuído a qualquer variável que não tenha sido
declarado. Um variável que seja indefinido não tem a propriedade de length porque é exatamente
fixo num só valor chamado undefined. Não se preocupe se necessita de clarificação do que é
length. Falaremos sobre length mais tarde.
O type Null por outro lado serve geralmente como placeholder* para um futuro objeto e deveria
ter sido considerado um objeto em si (valor de referencia), mas houve um erro da parte da
implementação da ECMAScript Standard anterior e hoje continua a ser considerado type
primitivo por razões históricas. Tal e qual undefined, só tem um valor: null.
(*) Placeholer é um termo que significa “marcador de posição”, ou “lugar reservado”. Em programação placeholder refere-se a
símbolos temporários que guardam o espaço para outro símbolo ou data ainda por declarar, ou que será declarada em runtime.

O type Boolean representa uma entidade lógica com dois valores, respectivamente true e false, ou
seja “verdadeiro” e “falso”.

O primitivo String* é um tipo um pouco estranho! Normalmente em outras linguagens Strings são
consideradas valores de referencia mas em JavaScript a string é de type Primitivo.
(*) String significa cordel ou uma corrente. Na linguagem de programação, significa uma
sequencia de caracteres alfanuméricos. Strings são sempre envolvidas em aspas singulares ou
duplas. Mesmo números que estejam envolvidos entre aspas são considerados Strings por
JavaScript e não type Number.
Com é óbvio, strings podem variar em tamanho e então em JavaScript, quando adicionamos
palavras a um string, gera-se um novo string com a combinação do antigo e do novo. O string
anterior fica com uma bandeira assinalando que tem que ser apagado na próxima vez o browser
faz a sua limpeza através do coletor de lixo.
Um string pode ter zero ou mais caracteres (cada caractere é representado por um bloco de 16-
bits). Cada um destes 16-bits é referido por um número de posição. A primeira posição é zero.
Como exemplo, na string “Tony”, a posição do último caractere (y) é o comprimento da palavra
menos 1, ou seja length – 1. E porquê? Porque o length é de 4, mas como começa contando em 0,
a quarta posição é numerada como 3.
Quando um string não contem data é representado apenas por aspas: “ “ . Quando um string
contem data, cada elemento (ou caractere) é considerado um UTF-16 code unit.
Em suma, como será demonstrado mais tarde, JavaScript strings são guardadas no stack por serem
valores primitivos. Se o string se expande, ele é trocado por outro com uma posição de memória
maior e a data anterior é apagada.
Variáveis versus Valores de Referencia
Até agora temos falado em String, Boolean, Null e Undefined, mas nada dissemos sobre Number.
Números serão tocados em mais detalhe conforme vamos desenvolvendo este tema. Basicamente
os valores primitivos são tipos fornecidos pelo sistema JavaScript ou seja, primitivos são tipos
nativos da língua. Vêm já definidos com a ‘máquina”.

Numbers, Strings, Booleans => JavaScript primitivos.


Por outro lado quando falamos em valores de referencia, aqui estamos falando de definições de
objetos. Outras linguagens utilizam classes. O ECMAScript Standard (lê-se ékma script) não tem
classes na sua definição de sintaxe. ECMAScript é o nome do padrão da língua JavaScript. A
versão corrente é a ECMA-262. JavaScript é a combinação do standard ECMA-262 mais o
ambiente onde ECMAScript é aplicado, como por exemplo em cada browser. Browser é o leitor
ou interface também conhecido por navegador que nos permite acessar a internet. Quando o
ECMAScript se junta a um browser, o objeto principal conhecido por Global Object faz de
interface entre as duas plataformas e essa combinação de objeto passa a ser conhecido como
objeto window (nada a ver com Windows). Este é o pai ou a mãe de todos os outros objetos e é daqui
que muitos métodos utilizados em outros objetos têm a sua origem. Veremos como isto funciona
incrementalmente.
Então no exemplo abaixo, se nós declararmos tony como um Object (o O é maiúsculo):

var tony = new Object();


Estamos a ceder ao variável tony certas ferramentas predefinidas para este objeto utilizar.
Quero dizer com isto que tony herda um número standard de propriedades e métodos
provenientes do biblioteca interna de JavaScript, ferramentas estas que estão na lista prototipa do
Objeto Global nativo.
Então, o que herda exatamente este novo objeto tony do Objeto Global de JavaScript?
1. Propriedades: Uma vez declarado como objeto, o nosso novo objeto tony “herda
(apontando para)” propriedades do objeto Global tais como:
(Não memorize. Cobriremos este assunto naturalmente ao longo do caminho. Tente apenas compreender. Neste momento estamos
simplesmente enumerando as propriedades e métodos que são herdadas automaticamente quando se cria um novo objeto e servirá
para referencia.)

A) Constructor – Isto é uma “formula” automática que o novo objeto herda para poder duplicar
objetos semelhantes, através do operador new. Um constructor é uma função que tem certa
programação definida para construir uma replica do objeto. Como por exemplo eu poderia
dizer que joão = new tony( ) e depois joão passaria a ser uma replica de tony. Esta maneira de
criar objetos evita repetição de programação e poupa memória. Um constructor herdado é um
apontador para a fonte dos dados originais que permitem recriar um objeto contendo a mesma
funcionalidade do objeto mãe. Ele não têm função ativa no objeto que o herda, apenas serve
para este objeto poder criar outros objetos. Um construtor é o dom de poder ser mãe. Dá a
futuros objetos o direito de poderem nascer. O constructor tira proveito de um parâmetro
chamado this. “this” é um placeholder genérico que representará especificamente o objeto em
ação, no momento em que este objeto utilizado os métodos e propriedades do objeto mãe.
“this” é como o pronome “cujo”, ou diremos o “dito-cujo” embora se traduza como “este”.
Onde programarmos “this” como por exemplo this.livroTitulo, “this” será substituído pelo
título do livro a que me refiro quando JavaScript fizer a operação a que o chamamos. Isto
permite criar scripts genéricos que depois se poderão aplicar a vários objetos e não apenas a
um só. Tocaremos neste assunto frequentemente em outras ocasiões.
B) Prototype – Outra propriedade que um novo objeto herda é Prototype. Prototype é um
interface que atua como uma corda umbilical onde os vários objetos podem consultar e utilizar
os vários métodos e propriedades disponíveis vindos de objetos superiores, ou seja, aqueles
de quem o objeto presente foi modelado. ‘Protos” or pai, é a fonte de quem o objeto corrente
herdou sua funcionalidade, algures na cadeia prototipa superior. A utilidade deste link vai para
além do objeto corrente no sentido em que permite a outros objetos mais abaixo, o de poderem
utilizar os recursos de objetos acima, incluindo o objeto atual. Tal e qual o constructor, o link
prototype funciona apenas em uma direção, isto é, pode-se receber mas não modificar a
funcionalidade que vem de cima. Podemos também pensar que esta propriedade prototype é
uma lista de toda a funcionalidade que o objeto tem autorização de poder utilizar. Todos os
novos instantes de um objeto herdam esta lista de funcionalidade. Teremos oportunidade de
trabalhar com a propriedade prototype nos nossos exercícios de laboratório.

Figure 2
2. Métodos: No nosso exemplo anterior, tony herda também “aponta para” métodos
provenientes do objeto protos (seu pai ou mãe) que é o objeto “Object” . O objeto global
se chama Object com o maiúsculo. Não confundir este nome com o nome genérico objeto.
Ele é um objeto nativo, tal e qual Array, String (sim também há um objeto String), etc, mas no
fundo Object é superior a todos estes outros porque estes herdam funcionalidade de
Object que depois modificam para poderem dar suas própria entidades (seu type) a seus
filhos. Introduzirei esses outros objetos mais à frente.
O métodos que um new Object herda são os seguintes:
(Não memorize. Cobriremos este assunto naturalmente ao longo do caminho. Tente apenas compreender. Neste momento estamos
simplesmente enumerando as propriedades e métodos que são herdadas automaticamente quando se cria um novo objeto e servirá
para referencia.)

a) hasOwnProperty – Tradução: temSuaPropriaFuncionalidade? Este método verifica se o


objeto em questão tem uma certa funcionalidade nativa dele próprio. Não serve para verificar
se este objeto tem uma certa funcionalidade proveniente do pai objeto, apenas funcionalidade
local. (por exemplo, se desejarmos saber se alguém criou uma propriedade chamada
“nacionalidade” escrevemos assim (veja script em vermelho):
será que nomeDoObjeto.hasOwnProperty(‘nacionalidade’); ?
returns (devolve resultado) true (verdade) se a propriedade existe e é do próprio objeto.

Se perguntarmos se tony.hasOwnProperty("toString");? returns false porque


toString existe mas este é um método e propriedade do objeto mãe, o Object. Note: Nós
experimentaremos com toString e todos os outros métodos mencionados muito em breve. Para
já, siga em frente com sua leitura preliminar.
b) isPrototypeOf - Tradução: éProtótipoDe? O método isPrototypeOf permite-nos verificar se
o objeto em questão recebe seus métodos do protótipo (menu) de outro objeto, ou não. Temos
que incluir o termo “prototype” para além da mesma palavra já incluída no sintaxe do método
em si. Por outras palavras, “meuObjeto.isPrototypeOf(aqueleObjeto)” não funcionará
porque JavaScript não compreende o que queremos dizer. Necessitamos de ser mais
específicos da seguinte forma: meuObjeto.prototype.isPrototypeOf(aqueleObjeto); ? O que
significa “ Pertence o protótipo utilizado pelo meuObjeto, aqueleObjeto?” Se o valor
devolvido for true (verdade) o meuObjeto utiliza o protótipo do aqueleObjeto. É o mesmo
que dizer que meuObjeto modela-se do aqueleObjeto. “Modelar-se de” poupa memória
porque o meuObjeto não tem que recriar novas propriedades porque já existem em outro
objeto a que meuObjeto tem acesso. (Note: verificaremos mais tarde que isto depende de como codificamos os
nossos objetos).

c) propertyIsEnumerable - Tradução: propriedadeÉenumerável? Este método é utilizado para


determinar se uma certa propriedade é visível ao ponto de a podermos numerar (listar) com um
script de listamento como por exemplo o ciclo for...in (loop). O for...in lista as propriedades
do próprio objeto, não do seu ancestral, porque só as próprias propriedades podem ser
enumeradas por um script.

d) toString( ) - Tradução: converterAString. Todos os objetos têm um método toString(). Este


método é automaticamente chamado quando um objeto tem que ser representado com um valor
de texto (string). Um exemplo é quando utilizamos o famoso console.log(), console.log(nome
do objeto), ou então alert(nome do objeto). Conversão a String acontece quando uma
representação em texto é necessária. Esta conversão não afeta o original.

e) valueOf() - Tradução: valorDe. O valor que é retornado através deste método, é um valor
primitivo. JavaScript devolve o valor primitivo de um determinado objeto, isto é, se x =
[1,2,3], valueof() mostrará [1,2,3]; se y = "tony". valueOf() devolve "tony", etc. A sintaxe é
meuObjeto.valueOf();. JavaScript utiliza este método internamente conforme necessita, mas
também o podemos chamar se necessário (e chamaremos).
Imagine isto: Uma propriedade de um objeto pode ser ilustrada como um variável que está
ligado ao objeto. Uma propriedade é o variável e o valor juntos. cor = "azul" é uma propriedade
chamada cor.
Então, no nosso primeiro exemplo, será tony o objeto em si?

A resposta é Não é. tony é uma etiqueta, um símbolo. Tecnicamente o símbolo tony é


classificado como um variável (um apontador) que temporariamente reside no stack e aponta
para um objeto instanciado (clonado mas com funcionalidade preexistente) de um modelo. Este objeto reside
no heap e se alguma vez apagarmos ou redirecionarmos o símbolo tony, este objeto será enviado
para o coletor de lixo onde esperará pela próxima lavagem feita pelo browser. Cada browser faz
a limpeza de modo diferente. Esta limpeza melhora com cada nova versão do browser.
Em JavaScript, quase tudo é um objeto. Todos os types primitivos, exceto null e undefined, são
na realidade tratados como objetos. Eles são internamente convertidos a objetos cada vez que
JavaScript necessita de um método para os processar. Isto acontece porque primitivos não têm
métodos por questão de memória, mas cada type de primitivo tem um espelho, um tipo objeto no
outro lado que lhes empresta o método temporariamente requerido. Quando a ação termina, o
primitivo volta ao seu estado normal de primitivo deixando de ser objeto outra vez.
E para resumir porque a repetição é a mãe do aprender, um primitivo pode ser convertido
temporariamente em objeto e assim pode utilizar propriedades e métodos, uma regalia de objeto,
com os seus próprios valores primitivos, mostrando todas as características de objeto. E é para
esse efeito que JavaScript tem também valores de referencia equivalentes a cada primitivo, como
objeto Boolean, objeto Number e objeto String que são automaticamente chamados quando
necessário. Ver e estudar a foto embaixo, onde se visualiza o que acontece quando requeremos o
método length aplicado a um primitivo:
Figure 3 (ver tabém Strings como Objetos em JavaScript)
Em JavaScript Tudo Vem de Objetos
Lab 1
É altura de ligar o seu console favorito de JavaScript e praticar um pouco. Neste projeto utilizarei o
console da Google Chrome. Quando chegar ao browser, abra o Console clicando no atalho de
combinação das seguintes teclas CRTL+SHIFT+j para Windows e CMD+OPT+j para Mac.
Uma vez no Console, se for a primeira vez, solte-o do browser carregando no quadradinho ao fundo
esquerdo. A partir de agora ele estará sempre solto até você voltar a carregar no quadrado outra vez.
Verá alguns erros no monitor mas esses erros não têm nada a ver com o nosso trabalho.
Simplesmente ignore-os.

Vamos agora experimentar com typeof. Observe cada resultado e tente deduzir as razões porque o
resultado é assim mesmo. O operador typeof devolve um string indicando o tipo (type) do operando.

Nota preliminar: o ponto e vírgula “;” termina uma expressão. Vá verificando como ele é aplicado.
O “//” significa “comentário”. Tudo o que ler à direita de um // não é para escrever no Console.
Mesmo se escrevesse, JavaScript não processaria a linha porque sabe que // significa comentário.
Escreva o seguinte código (em baixo a verde) no seu Console e clique no botão Enter (o botão de mudança de
linha). Preste mais atenção aos exercícios 9 a 15:

1- typeof 1; (Nota: O console tenta acabar a palavra typeof automaticamente. Se quiser autorizar que o faça, carregue na
tecla de final de linha e o cursor passará para o final da palavra poupando-lhe algum trabalho).

// O resultado é “number”. Claro que sim, não é?

2- typeof x;
// O resultado é “undefined”. x não existe e por isso é indefenido.

3- typeof tony;
// O resultado é “undefined”. JavaScript não brinca em ação!

4- typeof "tony";
// O resultado é “string”. Ah agora sim, estamos falando o lingo de JavaScript! Um texto entre aspas é um string para o JavaScript.
Uma palavra sem aspas seria um símbolo já declarado. Com no teste 4 tony não foi oficialmente declarado, JavaScript atribui-lhe o type
de undefined.

5- typeof true;
// O resultado é “boolean”. true é uma palavra reservada e não pode ser utilizada como símbolo.

6- typeof "true";
// O resultado é “string” Saberá porquê? Embora o termo true seja reservado, “true” em aspas pode ser utilizado como um string.
Mas sem aspas seria um símbolo. true e false não podem ser símbolos.
7- var y = 123; // Isto é uma declaração de um variável (y). O prefixo var inicia a posição de escopo de y e y por sua vez
recebe a atribuição de 123. Mais sobre isto à frente.

// depois de codificar a etapa 7 tente o seguinte:

8- typeof y;
// O resultado é “number”.

9- var z = new Object;


// O é em letra maiúscula porque Object é um nome próprio que existe na biblioteca de JavaScript.
Clique no ENTER e depois escreva o seguinte na próxima linha:

10- typeof z;
// O resultado é “object”. z aponta para um objeto no heap.

11- var b = z; // Definimos b e atribuímos-lhe z. O operador = funciona no sentido direita para esquerda.

// Mude de linha e depois entre:

12- typeof b;
// O resultado é “object”. Agora ambos z e b apontam para o mesmo objeto. Vamos agora atribuir outro valor a z:

13- z = 123; // z passou agora a ser do type number.

// Veja agora o type de z:

14- typeof z;
// O resultado agora é “number”. Z já não aponta para um objeto. Agora tem em sua possessão no stack, um primitivo (123).

15- typeof b;
// O resultado é ainda “object”. O objeto ainda existe porque ainda tem um símbolo apontando para ele.

No exercício 9 declaramos z como sendo um novo Object (isto é apontando z para um objeto).
Repare como no test 9 o O de Object é em maiúsculo. Todos os objetos nativos de JavaScript
começam com uma letra capital. String e string não são o mesmo símbolo. JavaScript é sensitivo para
com letras minúsculas e maiúsculas. Isto é importante manter em mente. Voltando ao nosso z, z é um
variável no stack que aponta para um objeto no heap, certo?
No exercício 11 declaramos o variável b e atribuímos-lhe o mesmo valor que z. Então b é agora um
símbolo que aponta para o mesmo objeto que z.
Em 13 nós mudamos de ideia e apontamos o z para o número 123. O z é agora de type “number’.
Deixou de ser um objeto.
No exercício 15 verificamos que b continua a apontar para o objeto que lhe foi atribuído
anteriormente por z. Isto faz-nos reparar que quando atribuímos um valor de um variável a outro, é
uma transação única. Tal como dizer “Amigo aponte sua pontaria para o mesmo objeto onde estou
apontando mas não se meta no meu caminho. Você é você e eu sou eu!” Se um dos variáveis é
depois atribuído a outro valor, o segundo variável não o segue. Mas por outro lado, se algum deste
variáveis modificar o objeto para onde mutuamente apontam, a modificação é refletida em ambos os
variáveis.

Note: A discrição mencionada acima só se aplica quando atribuímos valores de referencia a


variáveis. Se por outro lado variável a é um string ou um number e nós atribuímos o valor a a b,
como b = a, string a é copiado para b. Ambos variáveis e ambos valores são independentes e nunca
partilharam nada em comum. Eles são ambos valores primitivos. Apontamentos só acontecem
quando o valor está no heap e o apontador está no stack.
Pergunta:

Vamos supor que reatribuímos ao variávle b (agora o único apontador para o objeto) um outro valor diferente,
como por exemplo b=345; Agora o type de b é também um number e o objeto fica sem apontador
que o liga ao stack. Qual será o futuro do objeto que se encontra no heap?
Resposta: O objeto fica com a bandeirinha assinalando que necessita de ser processado pelo coletor
de lixo e eventualmente será apagado quando o browser fizer a próxima limpeza.
Lab 2
Vamos ligar o nosso Console de JavaScript favorito para experimentar mais codificação (estou
usando o Chrome da Google):

1- var x = "chapeu"; // Depois deste à esquerda declare mais outro variável:

2- var cor = "verde";


3- typeof x; // resultado é “string”. (Nada de novo até aqui!).
4- typeof cor; // resultado é “string”. (o mesmo que em cima).
Você já ouviu dizer que em JavaScript quase tudo é um objeto, certo?
Vamos então verificar!
5- Introduza um outro variável. Desta vez iremos adicionar mais propriedades do que apenas
uma propriedade singular no mesmo variável. Repare no ponto e vírgula à direita da chaveta
de fechamento }; no primeiro exercício. Estamos declarando um variável com nome de
camisola. Declarações sempre terminam com ponto e vírgula, mesmo quando depois de
chavetas como é este caso. É uma forma de dizer a JavaScript que não existe nada mais a
declarar:
var camisola = {cor: "branca", tamanho: "M", material: "algodão"};ro
6- Veja o type de camisola:

typeof camisola; // resultado é “object”


O que aconteceu aqui? JavaScript é inteligente e assim que reparou em chavetas decidiu logo que
isto iria ser mais complicado e passou os valores para o heap fazendo deste string um objeto, e
mantendo no stack apenas o apontador, o símbolo camisola.

NOTE: porque cada símbolo representativo (como por exemplo “cor”:) é tecnicamente um string, é
também uma boa prática escreve-los dentro de aspas na altura da declaração. Use de preferência
aspas dobradas porque, embora aspas singulares também funcionem, mais tarde quando você
programar em JSon, terá que utilizar aspas em dobro. Por isso é melhor criar já esse hábito. Não as
incluí agora nesta versão para poder simplificar, mas de futuro, apontadores de propriedades como
os nossos exemplos “cor”e “tamanho” serão escritos com aspas na sua declaração.

Ok, agora temos um objeto real, sim?


Então vamos acessar os seus valores:

1- camisola.cor; //resulto é “branca”.


2- camisola.tamanho; //resulto é “M”.
3- camisola.material; //resultado é “algodão”.
Este variável tem métodos e propriedades herdadas do modelo Object. Nós acabamos de utilizar um
tipo de sintaxe conhecido como sintaxe de ponto porque liga os objetos a seus valores colocando
um ponto entre eles e hierarquicamente da esquerda para a direta. No fundo, um objeto é um
agrupamento de elementos mapeados por uma associação de chave-valor e com um apontador
comum (o variável) que os liga a todos formando um grupo.
Poderiamos também utilizar uma sintaxe de colchetes [ ] em vez de sintaxe de ponto, com esta:

4- camisola["cor"]; //resultado é “branca”.


5- camisola["material"]; //resultado é “algodão”.

Tudo depende das nossas intenções ao programar e também das nossas preferências de sintaxe.
Sintax de colchetes requer a aspas à volta do nome da chave.

Resumo de ideias
Pense em variáveis como símbolos apontando para uma certa data.
Pense em stack apontando para o heap.
E pense também em pares associativos de chave-valor residindo no heap e atados ao
stack por um “cordel” que serve de apontador. Se não existe um cordel ou apontador,
não existirá nenhum chave-valor no heap. Tal e qual uma moeda, sem cara não existe
coroa.
Um variável a quem não tenha sido atribuído um valor, toma automaticamente o valor de undefined.
Mas ele continua a existir. Se quisermos realmente apagar este variável teremos que lhe atribuir o
valor de null quando já não necessitarmos do mesmo. Para verificar se um variável tem alguma
atribuição ou não, podemos utilizar o typeof. Mais tarde neste livro utilizaremos typeof outra vez
para verificar se um objeto foi instanciado. Continue sua leitura sem memorizar nada, apenas
compreenda e pratique os exemplos dados.
Pense em JavaScript como uma coleção de objetos herdando funcionalidade de outros objetos com
quem eles fazem interface.
Novos objetos podem também anular ou readaptar as propriedades e métodos originais, e além disso
podem até inventar outros novos métodos e propriedades.
Estas novas propriedades podem ser transmitidas para novos objetos que sejam hierarquicamente
inferiores ao objeto construindo a nova propriedade. Isto acontece via da propriedade de prototype
que este objeto delega ao outro.
Por falar em propriedade prototype, através dela podemos também adicionar diretamente nova
funcionalidade ao objeto mãe, incluindo aos objetos nativos se bem que nestes acontecerá apenas de
modo temporário e aplicado somente à execução atual. Veremos como isso funciona adiante.

Vamos então em frente?


Escreva o seguinte no seu console (só o que está a verde):
6- var estante = {"livros": 20, "CDs": 57, "Magazines": 19};

7- estante.CDs; // resultado é 57. O número de CDs é 57.


8- estante.livros; // resultado é 20. Temos 20 livros na estante.
9- estante.livros = 21; // aqui adicionamos mais 1 livro
10- estante.livros; // resultado é 21. Agora temos 21 livros.
Em cima adicionamos mais um livro à estante ao atribuir 21 livros em vez do original 20.
Cool, certo? Este tipo de sintaxe de ponto permite a manipulação e controle do objeto. Chame agora
o objeto para verificar a nossa mudança:

11- estante; // resultado é Object {livros: 21, CDs: 57, Magazines: 19}.

Podemos também adicionar novos elementos ao objeto:

12- estante.audioBooks = 11;


Chame o objeto:

13- estante;
//result: Object {books: 21, CDs: 57, Magazines: 19, audioBooks: 11}

Como vê, um variável pode apontar para uma coleção de data em formato de pares chave-valor,
formando um objeto. No entanto, mesmo até strings regulares, embora sejam valores primitivos,
herdam métodos e propriedades do objeto Global assim como do objeto equivalente a seu type.
Repare nos seguintes exemplos:

14- var x = "tony"; // e agora veja o seu type:

15- typeof x; // resultado é “string” mas repare em seguida que podemos utilizar métodos e propriedades de objeto:

16- x.length; // resulto é 4 caracteres. (de onde surgiu a propriedade length?)

17- x.substring(0,3); // resultado é “ton”.

Aprenderemos mais sobre estes métodos e propriedades na segunda parte deste livro. No entanto
para quem não está familiarizado com substring() aqui vai alguma informação preliminar: o
parâmetro 0 representa o primeiro caractere a ser incluído no resultado. Lembre-se que em
JavaScript a contagem começa em zero e não em um. O segundo parâmetro 3 representa o primeiro
caractere a ser excluído do resultado.

Voltando aos exercícios 18 e 19, o que aconteceu aí?


Lembra-se da Figura 3 ? Parece que embora JavaScript não tenha mudado o string “tony” para o heap,
fez uma conversão temporária a objeto, utilizando o objeto String, para se poder servir da
propriedade length (comprimento do string) e o método substring().
Mais Variáveis , Introdução de Funções
O que acontecerá se atribuímos uma função a um variável?
Lab 3
1- Escreva esta função num editor simples (Estou usando Notepad das Windows. Pode
também utilizar um editor de texto na internet como por exemplo: editPad de Tom Churm).
Copie o script para o Console de JavaScript (ou então pode copiar o meu ficheiro carregando
no link raw file por debaixo da imagem):

Figure 4 arquivo raw. icontemp.com/p3/4.txt

Note o ponto e vírgula no final. Isto é uma definição de função. Define o variável com nome de
mais100 como apontador para um objeto type function, que por sua vez adiciona 100 a qualquer
número introduzido em lugar do parâmetro1. (Nós ainda não passamos nenhum argumento (data)
para a função).
Funções são como caixas fechadas onde grupos de código coexistem para exercer uma determinada
função. Geralmente uma função tem um input e um output. O que entra é modificado, e o que sai é o
produto da modificação. Funções são bastante úteis para evitar redundância porque reutilizam o
mesmo script cada vez que são chamadas ao trabalho. As funções delegam seu código sempre que as
chamam. Soa familiar? Funções são objetos e por outro lado, objetos são geralmente coleções de
funções. Oh, será que objetos são coleções de outros objetos? Mas é verdade mesmo porque em
JavaScript tudo é objeto.
Uma coleção de funções desenhada para ter uma certa funcionalidade específica sob o comando de
um objeto, é chamada método. Por vezes um método só tem uma função, outras vezes um método tem
várias funções a seu dispor que fazem parte deste mesmo método. Por isso, não confundir métodos e
funções embora por vezes se misturem os termos. Eles são relacionados mas não são a mesma coisa:
O sentido semântico é diferente.
O script acima é representado da mesma forma que quando se declara um variável. O que quero dizer
com isto é que não existe valor no variável em si. O seu propósito é o de apontar para a função
(variável apontando para a função). Funciona tal e qual qualquer declaração de um variável, tal
comol var x; funcionaria. O browser manterá o símbolo mais100 como referencia, mas o
interpretador só atuará quando chamarmos a função, que se faz desta forma: mais100(3); (3) é o
argumento que passará (por cópia) para a função através do parametro1 que serve de interface. O
browser mantém depois controle desta execução como única e independente de outras execuções.
2- Vamos ao console (tenha a certeza de ter completado o primeiro exercício):

mais100(3); // resultado é 103


3- Entre: typeof mais100; // resultado é “function”.

4- mais100.length; // resultado é 1. Este número representa o número de parâmetros


codificados entre os parênteses da função. Estes parâmetros servem para introduzir data à
função. Embora length (comprimento) seja um método do objeto Object, neste caso é também
uma modificação adaptada ao objeto Function e serve para determinar quantos argumentos esta
função está programada a receber. Existe uma outra maneira de enviar argumentos à função
mas cobriremos esse tópico mais tarde.
Então nós passamos data para uma função através de placeholders* dentro dos parênteses ( ) e a que
chamamos parâmetros (podemos ter até 255 parâmetros). Se o placeholder se chama parâmetro(s), a
data em si chama-se argumento(s).
(*Placeholder: aquilo que reserva um lugar para algo que virá depois).

Por outro lado nós passamos data para fora da função através do mecanismo return. O return atua
também com um break (travão) que desativa a função uma vez que o return seja processado. return é
a última ação que acontece dentro de uma função. Se houver algum script por debaixo do return, a
função nunca lá chegará porque o interpretador já saiu da função.
Uma vez que return seja processado a função é destruída pelo browser e todos os variáveis dentro da
função são também destruídos, a não ser que tenham um apontador ainda ativado algures no script
(falaremos sobre isso um pouco mais adiante).
Funções podem ser chamadas do exterior (como nós fizemos com mais100(3)), ou podem ser
chamadas do interior, do seu próprio corpo (e isso chama-se recursão). Em JavaScript as funções
são objetos (mas você já sabia disso, certo?). Elas podem ser utilizadas em todo o sítio tal e qual objetos.
Podemos atribuir-lhes variáveis ou até incluir funções dentro de outros scripts. Funções em
JavaScript adaptam-se muito bem à situação onde são necessárias.
Em programas longos, grandes consumidores de memória, quando uma função acaba o seu processo e
sabemos que não irá ser reativada outra vez, devemos de-referenciar o seu apontador, neste caso, o
mais100. Quando de-referenciamos (tiramos a referencia) o mais100 é posto no coletor de lixo. Se
não de-referenciarmos o mais100, ele ficará no sistema o tempo inteiro da programação global,
diminuído o tamanho da memória aplicada ao browser, e isto pode aumentar com a adição de outros
variáveis não de-referenciados. De-referenciar significa remover a referencia através da atribuição
de "null“ ao variável.
5- E como de-referenciamos? Applicando-lhe Null:

mais100 = null;.
(Note: Depois de de-referenciar mais100 para null, se você verificar com typeof, verá que mais100 é agora um object . Null é um
objeto especial (Lembre-se da história porque foi considerado um objeto. Foi um erro que ficou sem mudança (capitulo 1)). De
qualquer modo, JavaScript apagará mais100 na próxima limpeza geral do browser porque o valor null inica que aquilo (o mais100)
não tem significado. Por outro lado a função também deixará de existir e já não pode ser reativada. Antes, a função tinha terminado
e apagado a data mas ainda estava ativa no sentido em que poderíamos chamar a função outra vez aravés do mais100. Mas uma
vez de-referenciado o símbolo que a chama, ela passará também para o coletor de lixo. Se tentar chamar agora a função outra
vez, receberá um erro a vermelho:
mais100(7); resultará em TypeError: object is not a function.
O tópico sobre funções continuará mais à frente num outro capitulo. Vamos continuar descascando
esta cebola.
Funções com Nome vs. Funções Anônimas
A nossa função anterior mais100 da seção Lab 3 é uma função anônima. Isto quer dizer que a
função é atribuída à declaração de um variável, e serve (a função) de expressão (a parte de
programação) do variável declarado.
Deixe explicar…

Em JavaScript podemos ter declarações de variáveis tais como:

var x; // Uma declaração por si, só introduz o apontador.


E do mesmo modo, podemos também ter declarações de funções tais como:

function y( ) { }; // Uma função com nome e corpo em branco.


Por outro lado, declarações podem incluir expressões à sua direita, tais como:

Figure 5

E vendo-se na figura a cima, variáveis podem ter como expressão, uma função, em vez de um
string. Um exemplo é o exemplo z a cima, um variável com uma função sem nome (anônima).
Quando declaramos um variável ou uma função em JavaScript eles são geralmente hoisted
(içados, pushados para) cima no topo do scope pelo interpretador. Esta lista no cimo é como um
menu que lista todos os variáveis ou seja apontadores, mas só as declarações. É como um índex
do que há disponível. Só a declaração é hoisted, não a expressão. Isto pode não fazer diferença
para o programa em si, exceto quando temos que fazer um debugging ao código. Quando
inspecionamos o código, é mais prático distinguir visualmente entre os variáveis e as funções da
lista mostrada no topo do scope. Simplifica a nossa compreensão do que existe no menu.
Eis o problema que temos quando fazemos um debug:
Nos exemplos de cima, a seguinte lista será vista(figurativamente falando) no topo do scope:
x, y( ), z
Note como y se mostra com identificação de função enquanto que z se parece como um simples
variável. Isto acontece porque só a declaração é que é içada para o topo. A parte da expressão é
ignorada até à altura de atividade da mesma. Isto é apenas um contratempo para alguém que queira
fazer uma inspeção, um debug ao código porque a resultado do processamento de JavaScript é
semelhante de uma forma ou de outra.

Para além deste possível contratempo, usar funções anônimas é perfeitamente aceitável e uma
maneira muito poderosa de codificar em JavaScript. Como exemplo, a famosa biblioteca jQuery
tira grande partido de funções anônimas (sem nome).
Primeira Revisão
JavaScript é uma linguagem baseada em protótipos.
Assim como classes, protótipos evitam a repetição de código tornando a capacidade de
memória muito mais eficiente e simplificando a codificação.
A memória de um sistema é subdividida em stack e heap. Stack atua como uma memória
de rascunho para pequena data que é geralmente temporária. Data mais extensa como por
exemplo objetos de todos os tipos, é guardada no heap.
Para acessar objetos, nós criamos apontadores no stack, conhecidos como variáveis. Uma
vez que de-referenciemos um apontador, o objeto, que é um valor de referência, é
colocado pelo interpretador no coletor de lixo. Este sistema de coleção de lixo é operado
pelo browser e cada browser tem a sua própria versão.

Valores de type primitivo residem no stack e valores de referência residem no heap.


Para de-referenciar um objeto nós declaramos o apontador (variável) como null.
Para criar um objeto, nós instánciamos-o a partir do objeto Object (Global Object) com
o operador new Object.
Uma vez declarado, um objeto herda propriedades e métodos do protótipo que o criou
assim como do protótipo do protótipo, numa cadeia que vai até ao objeto Global.
Quando declaramos um variável que contem strings em pares de chave-valor, a data é
guardada no heap em vez de no stack como se faz com um string simples. Esta data é
acessível a partir do Stack e através de um símbolo (um variável) que aponta para a
localização da data. Depois de feita esta ligação, podemos chamar cada valor utilizando
uma sintaxe de ponto ou a sintaxe de colchetes [“data”].
Porque tudo em JavaScript é objeto, funções e arrays também o são, e por conseguinte
todos estes elementos herdam funcionalidade do objeto Object.
Quando declaramos variáveis ou funções, o seu nome é içado (hoisted) para o cimo do
Scope dando sinal de vida ao interpretador de JavaScript. Mas as suas expressões não
são hoisted, elas apenas serão avaliadas na altura de runtime quando o script lá chegar,
embora JavaScript já saiba que elas existem devido à lista do topo.
Uma função anônima é uma função atribuída como expressão a um variável. Funções
anônimas são muito úteis porque podem ser colocadas em qualquer lado do script para
enriquecer a funcionalidade do mesmo.
Uma função nomeada é uma função declarada como function x() em vez de declarar
primeiro um variável e atribuir uma função ao mesmo. Ela é listada no topo do scope
como função, e não simplesmente como um variável que aponta para algo desconhecido.
O ato de uma função se chamar a si própria é conhecido como recursão. Muitas vezes
recursão substitui mecanismos de ciclo (loops).
O Intocável Object
Lembra-se onde reside um objeto?
Objetos residem no heap porque são valores de referência.

E como acessamos a um objeto??


Nós acessamos a um objeto atribuindo-lhe um símbolo no stack que aponta para o objeto.

O que acontece ao objeto quando lhe removemos o variável?


O objeto é posto automaticamente no coletor de lixo para ser removido pelo browser.

Poderemos tocar e modificar o objeto diretamente sem usar o apontador?


Um grande Não! Temos que realmente utilizar o apontador (variável) para poder acessar e
manipular o objeto. Através do apontador e de várias técnicas a partir daí, podemos manipular ou
modificar o objeto.
Neste momento já sabemos como um novo objeto herda certa funcionalidade de seu pai objeto, o
modelo Object. Mas podemos também adicionar novos métodos ou modificar para nosso proveito
os métodos já existentes. Teremos oportunidade de praticar técnicas diferentes nas nossas sessões
de laboratório.
Em revisão, objetos são criados por JavaScript quando atribuímos um variável a uma instância
do Object. O variável reside no stack e aponta para o endereço no heap onde se encontra o objeto.
Sem esta corda umbilical que conduz o programa para o objeto, não existe objeto. Se cortarmos
esta corda umbilical fazendo um de-referencing ao variável (declarando-o null), o objeto deixa
de existir.
Mas espere! O objeto deixa de existir se este objeto foi realmente criado do nada. E o que
acontece a objetos permanentes, tais como objetos nativos, objetos construídos pela plataforma
anfitriã ou o Objeto Global em si?
Estes objetos existirão sempre. Eles estão em standby esperando por uma chamada direta ou
através de cálculos de script. A biblioteca permanente nunca vai embora.
O seguinte conceito é importante: JavaScript não é só ECMAScript. JavaScript é a combinação
de ECMAScript com o ambiente onde está sendo aplicado. Um dos exemplos é o browser onde
ele faz interface com objetos do navegador, tais como o DOM e o BOM. O ECMAScript é
implementado pelo motor de JavaScript, o interpretador. Existem vários motores a serem
utilizados neste momento. Uma curta discussão sobre motores ou engines de JavaScript pode ser
lido no Wikipedia. E uma versão mais completa pode ser lida aqui: Versão Inglesa.
Objetos Nativos
Objetos nativos são os objetos que vêm de fábrica, isto é, do standard ECMAScript. Eles estão
sempre presentes, prontos a serem chamados. Objetos nativos ajudam a especificar e a definir
outros objetos. Estes objetos são chamados Objetos Globais Standard.
Alguns dos objetos standard prefabricados e os mais conhecidos são os seguintes:
Array, Boolean, Date, Function, Math, Number, Object, RegEx, String.
Uma lista dos Objetos Globais Standard pode ser vista no Mozzila Developer Network.
Infelizmente esta lista está em Inglês mas poderá também ir ao índex deste livro e selecionar seu
método em Português com uma explicação muito mais acessível, produto de muitas horas
meditando em cada tópico.
É preciso não confundir o termo Objetos Globais Standard com o termo Global Object (o pai de
todos os objetos, o objeto Object). Este objeto é o modelo ou protótipo que já mencionamos
anteriormente no capítulo Variáveis versus Valores de Referencia. Na verdade nós nem podemos
nos referir a esse nome diretamente porque o nome muda dependendo do ambiente onde
ECMAScript está sendo utilizado. Por exemplo, no browser ele assume o nome de window.
window é o primeiro objeto, (a raiz de JavaScript) e todas as declarações globais (no topo do
escopo) como por exemplo var x;, são ao nível de escopo de window, isto é, sobe o ambiente de
window ou seja ao nível do objeto Global. Experimentaremos com isto no próximo trabalho de
laboratório.
Alguns dos objetos nativos, tais como String e Math, permitem acesso aos seus métodos e
propriedades instantaneamente sem ter que instanciar um novo (new) objeto. Outros objetos
nativos, como por exemplo Date, requerem que criemos uma instância do objeto, antes de
podermos utilizar seus métodos e propriedades.
Objetos Hospedados, Hosted Objects
Outros objetos são provenientes to ambiente que implementa ECMAScript, o host environment
que faz interface com ECMAScript para completar o que chamamos de funcionalidade JavaScript.
No browser, ou navegador de internet, outros objetos são por exemplo o DOM (o ambiente do
documento) e o BOM (o ambiente do browser).

BOM - Browser Object Model: é uma coleção de objetos que define a janela do browser e o seu
conteúdo. Através da utilização do BOM, programadores podem customizar funcionalidade que
não é diretamente relacionada com a data do documento em si, como por exemplo mover a
window, ou mudar o texto na barra de status. Infelizmente o BOM não foi feito standard até à
chegada de HTML5 e cada browser usa sua própria implementação. Com o advento de HTML5 a
indústria de browsers está agora a implementar configurações standard e de futuro poderemos
tirar melhor proveito do BOM, mas ainda é cedo para isso.

DOM - Document Object Model: este é um objeto que define o documento quando se mostra no
ecrã. Dom é uma implementação standard e é um objeto dentro do escopo do objeto window ou
Global Object.
Para além de ser utilizado em browsers e servidores, interpretadores de JavaScript são também
embutidos num grande numero de ferramentas digitais. Cada uma destas implementações produz
seu próprio object model, que faz interface com ECMAScript. O base de JavaScript mantém-se
geralmente o mesmo para cada aplicação. O objeto Global toma uma nova forma em cada um
destes casos, servindo de liaison entre a linguagem e seu ambiente anfitrião. Um exemplo de tais
implementações é o Adobe Acrobat e Adobe Reader que suportam JavaScript em ficheiros PDF.
Outras ferramentas que utilizam JavaScript são Photoshop, Illustrator e Dreamweaver. Não
esquecer também Flash que implementa ECMAScript sobe o nome de ActionScript.
Figure 6 – Quando abrimos uma nova janela no browser, a janela pertence ao browser. Estamos utilizando sintaxe do
BOM quando abrimos uma nova janela. O objeto é window. Em window.open("url"); .open é um método que vem do
BOM.
Vamos então tirar mais uma camada da casca desta cebola…
O que é uma propriedade?
Em JavaScript uma propriedade é uma associação entre um nome (o variável) e um dos valores que
pertencem ao objeto em questão, o que significa que propriedades são os blocos de construção de um
objeto.
O que é um variável?
Um variável é uma “propriedade” atuando dentro de um contexto de execução.
O que é um contexto de execução?
Um contexto de execução é um escopo dentro do qual algo é executado. Um variável declarado
dentro de uma função, tem um escopo limitado à função em si, incluindo alguma subfunção que esteja
dentro da mesma (isto é uma subfunção tem acesso aos variáveis da função mãe). No entanto, em termos de contexto
de execução, cada vez que chamamos uma função, o escopo deste variável é diferente das outras
execuções anteriores, nenhuma tem acesso à outra execução. Isto é o que se chama contexto de
execução.
Quando o interpretador se inicia, só existe um contexto de execução, o contexto global. No contexto
global, podemos visualizar o escopo de uma forma estática e mais compreensiva. Depois, cada
execução de função cria seu próprio e único contexto, e como JavaScript só faz uma coisa de cada
vez, a cada momento o contexto de execução é diferente.
Quando JavaScript está sendo utilizado num browser, o contexto global é o objeto window.

Tudo começa com o objeto window (o objeto Object). Depois podemos subdividir os escopos em
funções, que são objetos que agrupam código funcional, que por sua vez também poderão ter os seus
próprios ambientes de escopo, se forem funções dentro de funções. O contexto de execução de uma
função atua cada vez que chamamos (executamos) a função, e depois, quando o programa sai da função,
este contexto é destruído pelo browser.

Quando por exemplo declaramos var x = "tony"; no ambiente de escopo global (do browser), x
torna-se uma propriedade do objeto Global, conhecido neste ambiente de browser como window. x
torna-se uma propriedade de window.

Se no nosso console depois escrevermos x; o resultado será “tony”.

Se em vez de x; escrevermos window.x; o resultado continuará a ser “tony”. “tony” é um valor do


objeto window e x aponta para ”tony”.
Se por outro lado tivermos uma função como por exemplo:

Figure 7

Agora o variável z é uma propriedade da função y e não de window. No entanto não podemos
esquecer que a função y é uma função do objeto global (window).
Permissão de acesso a elementos vem de dentro para fora e não de fora para dentro.
Desenvolveremos este tópico de escopo e contexto mais a fundo em breve.
Segunda Revisão
Valores de referência residem no heap.
Para podermos chamar ou modificar um objeto, teremos que ter um variável no stack
apontando para o objeto no heap.
JavaScript é a composição do seu núcleo (ECMAScript), mais os objetos do ambiente
onde o ECMAScript é implementado.
No ambiente browser, o objeto principal é window. ECMAScript faz o interface com o
DOM (modelo do objeto documento) e o BOM ( modelo do objeto browser).
O Document Object Model (DOM) já está standardizado. O Browser Object Model
(BOM) continua a ser único em cada marca de browser embora isso venha a mudar nos
próximos tempos.
ECMAScript vem com seus próprio objetos nativos. Estes objetos estão sempre
disponíveis. Os principais objetos nativos são o Object Global, Array, Boolean, Date,
function, Math, Number, RegEx e String.
O ambiente onde JavaScript é implementado (tal como no browser) adiciona seus
próprios objetos a que chamamos Objetos Hospedados, ou Hosted Objects. Num
browser, o Object Global transforma-se em objeto window. Depois temos o Document
Object (DOM) e uma coleção de objetos proprietários que fazem o grupo BOM.
Um variável é um nome dado a um apontador e dentro de um escopo específico.
Uma propriedade é um variável + a data para onde este variável aponta.
Ao contrário de algumas linguagens populares, não existe proteção de escopo dentro de
um bloco de programação, exceto se esse bloco é uma função. Isto poderá mudar no
EcmaScript 6 com a introdução do “let”. Em JavaScript as funções protegem seus
variáveis, mas só os protegem se forem predefinidos com o prefixo var na altura de sua
declaração.
Embora no escopo global, o elemento “var” possa ser omitido porque o variável está
disponível para toda a programação no interior do seu escopo, é uma boa prática sempre
incluir var na altura da declaração para evitar problemas secundários. var cola o
variável ao seu escopo imediato. Na última versão ECMAScript 5, a omissão de “var”
dará erro de sintaxe.
O Objeto Window – Intro
Como já foi mencionado antes o objeto Global torna-se objeto window quando JavaScript é utilizado
no navegador de internet, ou seja no browser.
Vamos fazer um pequeno teste para ilustrar este conceito.
Os variáveis no objeto window.
Ligue o seu JavaScript console (no Chrome é CTRL+SHIFT+j) e escreva o código que se mostra em
baixo a verde. Verifique cada resultado e leia os comentários:

1. var meuTexto = "Olá Mundo!";


2. meuTexto; // retorna "Olá Mundo!"
3. window.meuTexto; // retorna "Olá Mundo!" Isto resulta porque meuTexto é um
variável que pertence ao objeto window.

4. console.log(meuTexto); // retorna "Olá Mundo!"


5. window.console.log(meuTexto); // retorna "Olá Mundo!"
6. this.meuTexto; retorna "Olá Mundo!"
O this substitui (aponta para) o objeto de quem o variável está sobe controle (em escopo). Neste
caso em especial, substitui o objeto window. Falaremos mais sobre isso em breve.

7. this.console.log(meuTexto); // retorna "Olá Mundo!"


As várias possibilidades acima demonstradas ilustram a relação entre um variável ao nível de
escopo global e o objeto a quem ele pertence, neste caso window.

As funções no objeto window.


8. Codifique a seguinte função no seu editor de texto ou utilize este (editpad.org) editor online,
e depois coloque no console. (Pode copiar também, através do link de ficheiro raw
colocado no rodapé da figura de baixo:
Figure 8 arquivo raw. icontemp.com/p3/9.txt

Depois de colocar o script no seu console, experimente as seguintes opções:

9. x; // retorna function(){var texto2 = "Olá JavaScript";}; isto acontece porque não


chamamos a operação da função que seria com o parentêses à direita, mas sim o conteúdo
de x.

10. window.x; // retorna function(){var texto2 = "Olá JavaScript";};


11. texto2; // retorna texto2 is not defined. (o variável texto2 não existe no escopo
global. Apenas existe no escopo da função. O prefixo var dentro de uma função, faz com
que este variável seja privado e só a função e seu escopo têm acesso ao mesmo).

12. window.texto2; // retorna undefined. Este é o mesmo problema que o teste anterior.
Embora window reconheça a função x porque lhe pertence, esse objeto não tem acesso aos
variáveis dentro de x. E então, como chamamos diretamente o objeto, em vez de nos dar
um erro com no exercício anterior, o objeto window criou uma nova propriedade
chamada texto2 que nada tem a ver com o nosso variável em questão.
Agora veremos outro aspecto da utilização de funções, não só para isolar código, como também para
facilitar a administração de memória.
1- Considere o seguinte loop onde i é usado como um contador temporário:
( ficheiro raw ) (icontemp.com/p3/f1.txt) coloque-o no console.
for (var i = 0; i<5; i++){ console.log(i); }
// retorna 0,1,2,3,4
Quando o ciclo termina e JavaScript sai da loop, o variável i deixa de ser necessário, certo?
2- Chame i:

i; retorna 5
Isto não é bom, não é? serve apenas para diminuir a capacidade de memória desnecessariamente.
Embora o loop já não exista, JavaScript continua a manter este variável que era suposto ser
temporário, vivo na execução do programa . E isto é porque i está no escopo global.
3- Agora tente codificar o mesmo loop mas desta vez coloque-o dentro de uma função:
Copie do ficheiro em raw.( icontemp.com/p3/f2.txt) Coloque no console. Aqui vamos utilizar y em vez de
i só para não nos confundirmos com o i anterior.
4- Uma vez introduzido o novo script chame a função x para correr o ciclo:

x( );
5- Uma vez que o loop esteja terminado, verifique se y ainda existe como fizemos da última vez
com i:

y; // retorna ReferenceError: y is not defined.


A função efetivamente isolou e destruiu o variável temporário. Nós ainda temos o variável x para
nos preocuparmos porque aponta para uma função e se não a iremos utilizar é um desperdício de
memória, mas x é mais óbvio para nós e poderemos (se quisermos) atribuir-lhe o valor de null que o
enviará para o coletor de lixo. Mas o variável i ficou perdido no tempo.
Uma outra questão relacionada: Se tivessémos declarado y dentro da função mas sem utilizar o prefixo var, esse y seria global em
vez de privado e nesse caso, teríamos o mesmo problema que estamos a ter com i. O y não seria destruído quando a função fizesse o
seu return.

6- Chame i uma vez mais só para verificar:

i; // retorna 5. Continuará a lá estar até ao fim ou até nós o desqualificarmos manualmente.


Em todo o caso, a ideia aqui é a de ilustrar como uma função pode isolar variáveis e pode ser
aplicada não só para funcionalidade, como também para eficiência programática.
O objeto window não só é o Object Global que vem da ECMAScript, como também é o objeto
central do browser, o BOM.
Cada window representa uma instância do browser em si. O objeto window é o interface entre o
núcleo da língua JavaScript e o objeto browser. Ele, o window, representa o escopo global para
cada variável e função de uma página web.
Nós podemos adicionar propriedades ao objeto window à vontade. Mas como window é um objeto
interno estas propriedades adicionadas só têm validade durante a execução do nosso programa. Por
outras palavras, não podemos modificar permanentemente objetos nativos ou hospedados, apenas
podemos modificar objetos que criamos nós próprios ( mais sobre isso em outros capítulos).

Tente o seguinte para ver como funciona:


1- window.cor = "verde";
Note: Acima estamos declarando um variável com nome de “cor”, o que é o mesmo que quando
declaramos um variável só por si sem incluir window porque window é assumido pelo JavaScript.
No entanto, porque estamos simplesmente a falar de conceitos por favor escreva como está indicado
para cimentar a nossa compreensão do tópico.

2- window.humor = "contente";

3- window.idioma = "Português";

4- cor; // retorna “verde”.

5- humor; // retorna “contente”.

6- idioma; // retorna “Português”.

7- this.cor; // retorna ”verde”. (O this substitui genericamente o objeto a que este variável
pertence. Continuaremos a explorar “this” mais a fundo).

8- window.cor; // retorna ”verde”.


Estudaremos as várias propriedades e métodos de objetos mais à frente. Esta informação serve para
facilitar a compreensão do que virá a seguir sem ter que assimilar tudo ao mesmo tempo.
Um exemplo de escopo
Só para ter a certeza de que compreendemos o conceito de escopo no ambiente de objeto window (o
escopo global) e de escopo de função (o escopo local), vamos programar um pouco mais. Existem
conceitos importantes neste pequeno exercício.
1- Declare um variável com nome carro e uma função x onde existirá um outro variável com o
mesmo nome de carro (soa a conflito, não é?):

Figure 9 ficheiro em raw. icontemp.com/p3/10.txt

2- Chame a função: x();


Deverá devolver o seguinte output: meu carro é um Subaru "O outro carro é um Ford"
Porque foram ambos os variáveis processados sem haver conflito?
Ambos os variáveis têm o mesmo nome mas estão em escopos diferentes. O primeiro variável
carro está no escopo global (window). Como declaramos outro variável com o mesmo nome
dentro da função (o que não é uma boa ideia mas serve para ilustrar), JavaScript não poderá
utilizar o variável que se encontra ao nível global porque utiliza apenas o primeiro que encontrar
e como o interpretador lê de dentro para fora, o carro de dentro é o que JavaScript utilizará. Por
outras palavras, normalmente este seria o resultado:
meu carro é um Subaru "O outro carro é um Subaru"
A maneira para poder utilizar ambos os variáveis do mesmo nome, como fizemos no nosso script
acima, é chamar o variável exterior com o seu “path” completo, isto é, ligando o objeto através
de sintaxe de ponto, ao variável que queremos apontar para o exterior (ver linha 6). Assim não
haverá confusão e desta vez o JavaScript utiliza Ford em vez de Subaru.
Poderíamos ter utilizado o this em vez de window? Assim: this.carro?
3- Tente este script para ver o que acontece:

Figure 10 ficheiro em raw. icontemp.com/p3/11.txt

A resposta é: Em JavaScript this refere-se sempre ao dono da função que está sendo
executada, a não ser que faça um redirecionar forçado. Quem é o dono desta função x? O
objeto Global, window. “this” substitui o objeto genericamente. Neste caso substitui window.
No entanto há que manter em mente que conforme vamos instanciando outros objetos, estes objetos
passarão a ser donos de funções em seus métodos e mesmo que estes objetos estejam sob
window, eles serão os donos se e quando forem eles a chamarem o variável de que têm posse,
isto é, veremos que não é assim tão simples como parece. Tudo depende do contexto de execução.
this poderá ter um dono diferente se o contexto de execução assim o determinar. Continuaremos a
explorar este assunto e como diz o ditado, “de vagar se vai ao longe”.
Mais Valores Primitivos e Valores de Referência
Agora como ilustração, vamos ver se podemos atribuir diretamente a um variável type string, uma
propriedade daquelas que se atribuem a objetos. Lembra-se como valores primitivos, tais como
um string são guardados no stack, e valores de referência são guardados no heap?

1- Declare um variável: var x = "ninja";


2- Adicione-lhe uma propriedade chamada cor:

x.cor = "verde";
O console devolve “verde” (e por isso deve ter aceitado a propriedade, certo?) Vamos então
verificar se sim ou se não:

3- Entre x.cor; devolve “undefined”.


O que aconteceu? Não a guardou, fingiu que sim mas não o fez! Na verdade, para se poder
adicionar e guardar uma propriedade em JavaScript, nós temos que a enviar para o heap como
referência. No stack não existem propriedades, só existem valores primitivos. Vamos então ver
como isto se faz.
4- Declare outro variável mas desta atribua-o a um objeto:

var y = { }; As chaves indicam a JavaScript que isto tem que ser um objeto.
5- Tente adicionar uma propriedade como fizemos antes: y.cor = "verde";

6- Chame a propriedade: y.cor; // devolve “verde”. Ok, agora sim!!


7- Chame-a outra vez com o “path”completo que inclui window só para ter certeza:

window.y.cor; … // devolve “verde”.


O que pensa que aconteceu?
Se apontarmos um variável para um valor de referência, podemos adicionar propriedades ao
variável, isto é, ao objeto para quem o variável aponta. Quando, ou se, apagarmos ou
dereferenciarmos tal variável, o objeto e suas propriedades serão colocados automaticamente no
coletor do lixo implementado pelo browser.
Em suma, acabamos de criar um objeto dentro do escopo do objeto window. Este objeto herda
todas as propriedades e métodos disponíveis por window, mas podemos adicionar nossas
próprias propriedades que serão numeráveis. Veremos mais sobre este assunto à frente. Não
podemos adicionar novas propriedades a um variável primitivo, mas podemos adiciona-las se
esse variável apontar para um valor de referência.

Vamos agora considerar um outro conceito importante:


Passar data por valor, versus passar data por referencia.

O nosso primeiro variável x contem o valor de “ninja”. Vamos atribuir este valor de “ninja” a um
outro variável:
8- Se está recomeçando de novo declare o variável x com “Ninja” outra vez:

var x = "ninja";
9- Em seguida declare um novo variável z e atribua-lhe o valor de x:

var z = x;
10- Teste z: z; // devolve “ninja”

11- Agora mude x para samurai: x = "samurai";

12- Teste x: x; // devolve “samurai”.

13- E teste z: z; // devolve “ninja”.


O que pensa que aconteceu nesta troca de valores?
Se em vez de string primitivo, x fosse um apontador para um objeto, quando atribuíssemos x a z (z
= x), ambos x e z ficariam apontando para o mesmo objeto. Mas como x é um variável type string
localizado no stack, z não ficou fazendo referencia para o mesmo valor porque z copiou o valor de x
duplicando valores primitivos. Quando atribuímos variáveis primitivos a outros variáveis
primitivos, nós estamos copiando valores e cada um é independente do outro. Assim, quando
finalmente mudamos o valor de x para samurai, z ficou com o seu próprio ninja e não foi afetado
pela mudança.

Isto chama-se passar data por valor e é o que acontece com valores primitivos. Sempre que
reatribuímos um valor a outro variável, este valor é copiado para o próximo variável, porque no
stack, um variável e sua data é tudo a mesma unidade. Para ajudar a se lembrar deste termo
“passar por valor”, pense em “adicionar valor” porque quando copiamos estamos adicionando mais
data no sistema.
Por outro lado, no que diz respeito a valores de referência (os que estão no heap), a coisa funciona
de maneira diferente. A razão porque se chamam valores de “referência” é porque só existem se
algo se refere a eles. Neste caso é muito mais eficiente dar autoridade a outro variável para apontar
para a data no heap do que estar a criar uma segunda cópia do mesmo valor. Isto é obviamente
chamado passar data por referência (apontando em vez de copiando).

Vamos ver como isto funciona:


Você deve ainda ter o objeto y no console (se não tem porque já limpou, crie um novo objeto y
seguindo as etapas 4 & 5 acima indicadas). Em seguida faça o número 14:
14- Teste y para ter a certeza de sua existência:

y; Deve devolver Object {cor: "verde"}


15- Atribua y a um novo variável b (assim teremos dois apontadores para o mesmo objeto):

var b = y;
16- Teste b:

b; devolve Object {cor: "verde"}.


Agora tanto y como b apontam para o mesmo objeto, certo?
17- Adicione uma nova cor a y para ver se b também a recebe por referência:

y.cor2 = "vermelho";
18- Teste y:

y; // devolve Object {cor: "verde", cor2: "vermelho"}


19- Teste b:

b; // devolve Object {cor: "verde", cor2: "vermelho"}


Como vemos, valores de referência não são copiados quando atribuímos o valor de um variável a
outro. Porque são de referencia, cada apontador pode modificar o valor do objeto em comum.
Aqui o variável atua como apontador e um valor de referência pode ter muitos apontadores. Se
um dos apontadores modificar a data do objeto, os outros apontadores refletirão a mesma data
modificada porque apontam para o mesmo objeto. Isto é muito eficiente mas devemos também ter
cuidado se desejarmos dereferenciar o objeto (cancelar apontamento) porque não podemos
apenas anular um apontador, temos que anular todos os apontadores que mantêm o objeto vivo se
queremos cancelar o objeto.
O que acontecerá a b se nós reatribuirmos y a outro objeto?
Vamos experimentar:
20- Atribua um novo objeto a y:

y = {"cor": "violeta"};
21- Teste-o:

y; // devolve Object {cor: "violeta"}

22- Teste b:
b; // Object {cor: "verde", cor2: "vermelho"}. b continua apontando para o primeiro objeto.
23- Agora vamos praticar dereferenciar objetos, mas primeiro declaramos outro objeto c e
atribuímos-lhe b para que o objeto tenha dois apontadores em vez de um só:

var c = b;
24- Teste c; // devolve Object {cor: "verde", cor2: "vermelho"}
25- Agora dereferencie b (corte a corda umbilical):

b = null;
26- Teste c:

c; // devolve Object {cor: "verde", cor2: "vermelho"}


27- Dereferencie c:

c = null;
28- Teste c:

c; // devolve null
E assim finalmente o objeto foi enviado para o Coletor de lixo ficando à espera de apagamento
pelo browser porque já não existe nenhum apontador no stack para o objeto.
Nota: Existem várias maneiras de nulificar variáveis ao mesmo tempo. Um exemplo é o seguinte:

x = y = z = null; //
Como passar data de stack para o heap
Uma das formas de passar data do stack para o heap é através de um argument que se atribui a
uma chamada de função.

Figure 11

Em JavaScript, data primitiva do stack pode ser copiada como argumento para uma função no
heap, através de um interface conhecido com o nome de parâmetro. Podem-se ter até 255
parâmetros e estes são programados dentro dos parênteses da função e separados por virgulas. A
ordem da data a copiar tem que corresponder à ordem de parâmetros, porque o programador
utilizará essa ordem para dar instruções do processamento de data à função.
Por outras palavras, a data do variável no stack é independente da data entregue à função, porque
uma é a copia da outra, ou seja uma duplicação.
Acima, x aponta para a função e (33) é um número que irá ser copiado pela função.
Note que embora a função resida no heap (o apontador x reside no stack), o interface parâmetro
num (nome arbitrário) tira um facsímile da data que lhe queremos fornecer. Esta é uma
característica dos parâmetros de função quando aceitam argumentos vindos do stack. Nunca tocam
no original. Por outras palavras, esta passagem de data é por valor, tal e qual quando um variável
é atribuído a outro.
Na verdade, estes parâmetros são variáveis temporários. E a atribuição de valores é através de
cópia, ou passagem por valor. Esta transação é singular e está independente do que possa vir a
acontecer ao remetente, ou ao destinatário.
Nota: Se por acaso o remetente (o argumento para uma função) vier do mesmo lado da memória,
isto é, proveniente de outra função ou objeto no heap, esta passagem de data é feita por
referencia. Isto é importante saber porque qualquer mudança feita dentro da função nesta data, irá
afetar a data original se ela vem do heap como por exemplo de um array ou outro objeto. A razão
é porque estamos a dar permissão à função para agir na data do objeto. Neste caso, o que entra na
função não é a data em si, é a autorização para servir de apontador para a data original.
Este contraste entre data vinda do stack para a função, e data vinda do heap para a função, tem
resultados de funcionalidade diferentes. O primeiro é uma cópia da data, o segundo é apenas uma
referencia com autorização para editar o original.
Parabéns na sua leitura e compreensão deste material.
Vamos seguir para a parte dois e desvendar mais mistérios de JavaScript.
A informação coberta até agora será bastante útil nas próximas sessões.
Cinturão negro à vista no horizonte…
agradeço o seu tempo despendido!
:)(-
PARTE 2
=====

“Aquilo que temos de aprender a fazer, aprendemos fazendo. "

--- Aristóteles, Da ética a Nicómaco

Uma boa palavra deixada no Amazon sobre o que já leu até aqui

é um bom incentivo para o autor continuar a escrever.

Por favor faça-o agora


2.1. Strings como Objetos em JavaScript
Até este ponto, temos estado a cobrir strings de JavaScript (como palavras e frases) como valores de
type primitivo. Sabemos também que os strings são imutáveis (valores fixos) e residem na seção
de memoria a que chamamos o Stack. Se editarmos um string, o conteúdo do variável é trocado
por uma versão mais nova e o string anterior é automaticamente apagado.

No entanto, existe realmente um objeto chamado String. O protótipo está lá na biblioteca de


JavaScript, esperando que seja chamado a qualquer hora. Na verdade JavaScript chama muito
frequentemente o objeto String quando necessita de o utilizar para processar os strings primitivos.
Lembra-se da Figura 3?
Todos os métodos e propriedades do objeto String estão automaticamente disponíveis às ordens
dos valores primitivos. Nem é necessário instanciar um objeto para os poder utilizar.
Antes de continuar em frente, vamos definir dois termos no nosso vocabulário.
O termo “literal” é utilizado para designar valores simples que podem ser expressos como texto
do programa. Um exemplo seria “maçãs e bananas”. Um literal de type string é composto por
zero ou mais caracteres encapsulados entre aspas (simples ou dobradas). Embora em JavaScript
não exista diferença entre aspas simples ou dobradas, as aspas dobradas são mandatórias numa
subseção de JavaScript conhecida como JSon (JavaScript Object Notation) e muitos
desenvolvedores começam a estandardizar este formato em tudo o que programam com
JavaScript. É um hábito que eu tenho tentado adotar.
O outro termo é método. Um método é o que programadores chamam a um agrupamento de
funcionalidade específica que atua em nome de um objeto. Um método é normalmente composto
por uma função, ou uma coleção de funções que têm uma finalidade definida dentro do objeto.
Em JavaScript um literal type string é normalmente um primitivo. Quando um método é chamado
para atuar num string literal primitivo, o string é temporariamente e automaticamente encapsulado
num objeto para que possa ser processado pelo método.
Em baixo introduzo um exemplo de um string primitivo para ser utilizado nos nossos exercícios
que se seguem, onde iremos demonstrar algumas propriedades e métodos existentes no objeto
String. Como na primeira parte deste livro, a seção em verde corresponde ao que escrevemos no
console de JavaScript:
Ligue o seu console de JavaScript, eu estou utilizando o Google Chrome, e introduza o nosso
primeiro variável, x:

var x = "bananas";
Quando um primitivo é encapsulado num objeto String, herda automaticamente várias (a)
propriedades, e vários (b) métodos.
Vamos primeiro ver algumas das propriedades herdadas:

a) Propriedades de String tais como length, prototype, construtor:


1- length
O length significa comprimento e devolve o número de caracteres do string, incluindo espaços em
branco:

x.length; // devolve 7. (7 caracteres em banana). Note que as aspas não fazem parte do string.
2- prototype
A propriedade prototype é um comando que adiciona propriedades e métodos a um objeto já
existente. prototype pode também ser visto como um menu onde se listam todos os métodos
disponéveis ao objeto. Falaremos mais a fundo sobre isto nos próximos capítulos.
Vamos adicionar temporariamente uma propriedade ao objeto String para que nossos variáveis a
possam utilizar, pois eles herdam-na automaticamente. Estou assumindo que ainda tem o x
declarado no seu console:

String.prototype.gostos = "adoro bananas";


(note que o S do String é capitalizado. Isto devido ao facto de que objetos nativos têm nomes
próprios).
Aqui a ordem de esquerda para a direita é com de pais para filhos. String é o topo da árvore,
prototype vem a seguir e finalmente escrevemos o nome do novo método.

Como lembrança da sintaxe eu utilizaria esta mnemônica: “Senhor String, prototype-me esta
propriedade chamada “gostos” com a seguinte informação “adoro bananas”. (E eu visualizaria
esta propriedade como um par de chave-valor, que no nosso exemplo seria x.gostos).
Agora testemos o nosso x:

x.gostos; // devolve "adoro bananas".


A propriedade gostos tornou-se parte do string x e pode ser chamada utilizando a sintaxe de
ponto. O variável x continua a ser um string primitivo, e você podemos confirmar que o é
chamando o typeof, que nos devolve o type string (em letra minúscula), não o objeto.

typeof x; // devolve "string".


Então resumindo, quando olhamos para a nossa sintaxe, nós vemos uma propriedade chamada
“gostos’ que foi prototipada (criada) no protótipo do objeto String. “gostos” faz agora parte de
uma lista de propriedades disponíveis a todos os strings primitivos desta seção atual do
programa, ou seja neste contexto de execução.

Se eu declarar outro variável, será que herdará automaticamente a nova


propriedade?
Vamos verificar. Declare o seguinte variável:

var y = "Laranjas";
Chame a propriedade gostos para o variável y:

y.gostos; // devolve “adoro bananas”


Então a resposta é sim, qualquer variável tipo string herdará esta propriedade.

E se o variável for de type number em vez de string?


Introduza um outro variável mas de type number:

var z = 123;
Agora chame a propriedade gostos aplicada a z:

z.gostos; // devolve undefined.


Com certeza que já desconfiávamos disso porque esta propriedade pertence ao objeto type String,
não ao objeto type Number.
Mas cuidado porque esta nova propriedade é temporária, só se aplica a esta execução. O objeto
String, que é nativo de JavaScript, não pode ser permanentemente modificado. Isto é feito de
propósito por questões de fidelidade programática e segurança.
Métodos herdados serão cobertos mais abaixo. Mas por outro lado, e se quisermos adicionar um
novo método ao objeto String para podermos utilizar nos nossos variáveis atuais?
Vamos criar um método insignificante só para ver como isto functiona. Este método duplica o
string (veja o ficheiro raw se não quiser escrever manualmente):

Figure 12 ficheiro raw. icontemp.com/p3/13.txt

Depois de colar o script no console, chame o método ao variável x. Não se esqueça dos
parenteses porque um método é uma função:

x.repetir(); // devolve "bananasbananas".


Agora chame-o ao variável y:

y.repetir(); // devolve "LaranjasLaranjas".


Com vemos, também é possível adicionar métodos a objetos de String e aplicá-los a string
primitivos.
Nós podemos ver a lista de propriedades e métodos, utilizando um truque que não é standard. Esta
lista não mostra métodos internos, apenas os que nós desenhamos:

x.__proto__; // qualquer variável dá para ver a lista. Pode tentar y também:


y.__proto__;
devolve " String {gostos: "adoro bananas", repetir: function} ".
O termo a utilizar é proto e mais 2 subtraços na esquerda depois do ponto e 2 subtraços na direita.
__proto__ não foi estandardizado. No novo ECMAScript 5 este método será trocado pelo seguinte
método que pode ainda não estar disponível no seu browser:
Object.getPrototypeOf(x); // onde x é o objeto que estamos a investigar (o nosso x).
Para praticar, adicione algumas novas propriedades e métodos ao objeto String através da
propriedade prototype e chame x para cada um deles. Pratique, pratique e pratique.
E não esquecer também que x é uma propriedade do objeto window. Bem sabemos que x é um
string que herda métodos do objeto String, mas x é também uma propriedade do objeto window.
Poderiamos ter codificado todos os nossos scripts utilizando window como prefixo. Assim:
window.x.gostos;.
Antes de deixar este tópico vale a pena manter em mente o seguinte:
Quando criamos um método de protótipo para um objeto desenhado por nós, este método é
guardado na lista de protótipos do objeto. Isto significa que qualquer instaciamento deste objeto
hoje, amanhã ou depois, terá acesso ao novo método. Isto não se aplica a objetos nativos porque
nós não podemos modificar permanentemente um objeto nativo. O que prototipamos manualmente
num objeto de fábrica (nativo), apenas se aplica ao momento atual. Uma vez que o programa deixe
de executar, o método desaparece do sistema. Isto é feito por razões de segurança.

3- Construtor

A terceira propriedade do objeto String disponível ao string primitivo, é o construtor. (As outras
propriedades eram prototype e length).
O construtor contem a referência para a função que constrói instantes (replicas) deste objeto.

O construtor cria objetos com suas propriedades e métodos, enquanto que o prototype só cria
propriedades e métodos. Por questões de eficiência, é melhor deixar a criação de métodos para o
mecanismo de prototype, porque o construtor duplica a data quando gera uma nova instância de
objeto. Teremos oportunidade de explorar este assunto mais a fundo.
Esta informação serve apenas como introdução e não é necessário memorizar os termos acima
mencionados. Apenas compreenda por alto e continue a ler pois tudo fará sentido mais à frente.
b) Métodos do objeto String tais como: charAt, charCodeAt, concat,
fromCharCode, indexOf, lastIndexOf, match, replace, search, slice, split, substr,
substring, toLowerCase, toUpperCase, trim, valueOf
2.1.2 charAt( ) e charCodeAt( )
Ambos os métodos têm a ver com o acesso aos caracteres de um string. O primeiro método devolve
o caractere em si, e o segundo método devolve o Unicode do caractere.

charAt( ) significa o caractere na localização(número da localização);.


charCodeAt( ) significa o código de caractere na localização(número da localização);.
Vamos ver alguns exemplos:
1- Declare a variável x:

var x = "bananas";
2- Chame o método charAt( ):

x.charAt(2); // devolve “n” ( começa contando do zero à esquerda para a direita).


3- O método acima demonstrado dá o mesmo resultado que quando chamamos a posição do
caractere utilizando a sintaxe de chaves como em arrays. Tente:

x[2]; // devolve “n” .


charAt( ) é um novo método e pode não funcionar em browsers com versão já expirada.
4- Tente o outro método de String:

x.charCodeAt(2); // devolve o Unicode de “n” que é 110.


Os pontos em Unicode variam de 0 a 1.114.111, e os primeiros 128 pontos de Unicode coincidem
com os caracteres em ASCII. pt.wikipedia.org/wiki/ASCII
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre estes métodos:

· 15.5.4.4 String.prototype.charAt. ecma-international.org/ecma-262/5.1/#sec-15.5.4.4


· 15.5.4.5 String.prototype.charCodeAt ecma-international.org/ecma-262/5.1/#sec-15.5.4.5
2.1.3 fromCharCode( )
O método fromCharCode( ) é o inverso do método charCodeAt().
Este método é bem simples. Devolve o caractere baseado no código de Unicode que lhe dermos
como argumento:

String.fromCharCode(110);
// devolve o caractere n. Pode-se atribuir este método variáveis como por exemplo:
var x = String.fromCharCode(110); // x é agora “n”.
Podemos também chamar vários números de código Unicode ao mesmo tempo:

String.fromCharCode(109,110,111,112);
// devolve mnop.
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método:

· 15.5.3.2 String.fromCharCode. ecma-international.org/ecma-262/5.1/#sec-15.5.3.2


2.1.4 concat( )
O método concat( ), que significa concatenar ou juntar, substitui por vezes o operador “+” para
completar frases ou gerar um novo string mais completo.
Eis um exemplo:
1- Declare o seguinte variável se já não o tem co console:

var x = "bananas";
2- Declare outro variável combinando dois strings (não se esqueça do espaço ante de são):

var w = x.concat(" são boas para si!");


3- Chame w:

w; // devolve " bananas são boas para si!".


Concat( ) não altera o valor do variável original “x” a não ser que chamemos o método ao
próprio x, como por exemplo (não necessita fazer) este script:
x=x.concat(" são boas para si!"); o que é o mesmo que utilizar += em si próprio em vez de
concat().
4- O método concat é pratico em situações como por exemplo quando temos que juntar vários
variáveis para completar um outro string:

var h = "Note: ";


h = h.concat(x,w); // devolve “Note: bananas são boas para si!”.
A maneira mais eficiente de concatenar em JavaScript é utilizando os operadores + ou += No
entanto, o + é mais vagaroso do que += porque o interpretador de JavaScript cria temporariamente
um novo string para cada dois strings que estejam separados por um + e isso leva o seu tempo.
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.5.4.6 String.prototype.concat. ecma-international.org/ecma-262/5.1/#sec-15.5.4.6


2.1.5 indexOf() e lastIndexOf( )
Tradução: índice de e último índice de. Por esta lógica, o indexOf deveria ter sido chamado
primeiro índice de.

O método de String indexOf, assim como o método lastIndexOf, devolvem a localização


numérica de um item no string, baseado no valor especificado ao aplicarmos o método.
O primeiro método começa a sua pesquisa no primeiro valor à esquerda do string, isto é, valor na
localização zero, e devolve o primeiro exemplo que coincide com o que pesquisamos. O segundo
método começa a pesquisa no último valor à direita e avança da direita para a esquerda,
devolvendo o primeiro exemplo que se aplica ao critério de busca.
Porquê a diferença dos dois métodos? Em strings extremamente longos, começar pela direita é
por vezes mais rápido do que começar a busca pela esquerda, dependendo onde se encontra o que
procuramos.
Pontos a considerar.
Se o caractere é único, ambos os métodos resultarão na mesma resposta. Se perguntarmos pelo
‘índice de “n” em “bananas” onde vários “n”s coexistem, indexOf devolverá a posição 2
indicando o primeiro n que encontra. Por outro lado, o resultado de lastIndexOf será diferente,
devolvendo a posição 4 porque é a primeira que encontra vindo da direita para a esquerda.
O número de posição cronológica é o mesmo para ambos os métodos. Quer isto dizer que tanto a
posição 2 como a posição 4 têm o mesmo significado para ambos os métodos embora pesquisem
em direções opostas. O caractere b é posição zero para ambos os métodos, assim como o
caractere s que é posição 6 para ambos os métodos.
Para uma busca mais completa pode-se também utilizar o método search() que falaremos mais à
frente. No entanto, indexOf é mais simples e mais rápido.

Exemplos de scripts:
1- Se o nosso velho x já não está definido, por favor defina-o outra vez como var x =
"bananas"; Depois experimente com os seguintes scripts:
x.indexOf("n"); // devolve 2 como número de posição.
x.lastIndexOf("n"); // devolve 4 como número de posição.
2- Vamos tentar com outro exemplo diferente:
var aba = "Verde amarelo branco azul marinho.";

aba.indexOf("amarelo"); // devolve 6 que é a posição onde a palavra amarelo começa


contando de zero.
3- Se não existe a palavra que pesquisamos, ambos os métodos devolverão -1.

aba.indexOf("amarelos"); // devolve -1.


Este último exemplo pode vir a ser útil para decisões condicionais:
if(aba.indexOf("amarelo") !== -1) Se o termo amarelo não existe em aba, siga este caminho. else,
siga aquele caminho. Ver exemplo aqui: ficheiro em raw. icontemp.com/p3/indexof.txt

Se a sua intenção é a de trocar a palavra em vez de pesquisar o termo, veja o método replace()
discutido um pouco mais abaixo.
Se a intenção é encontrar vários elementos iguais, utilize match() que será demonstrado em
seguida.
Por favor repare na sintaxe destes métodos que é do tipo “camelo” onde palavra ligadas começam
em maiúsculo a partir da segundo termo.
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.5.4.7 String.prototype.indexOf. ecma-international.org/ecma-262/5.1/#sec-15.5.4.7


· 15.5.4.8 String.prototype.lastIndexOf. ecma-international.org/ecma-262/5.1/#sec-15.5.4.8
2.1.6 match( )
Tradução: corresponde a ( ), igual ou semelhante a.
Este método pesquisa um string `a procura de um elemento que corresponda ao critério a pesquisar.
match() utiliza expressões regulares para auxiliar a busca e devolve um array com o resultado.
Exemplo de scripts:

var xyz = "As maçãs e bananas são deliciosas";

xyz.match(/n/g); // devolve ["n", "n"]


Os símbolos / / delimitam a expressão a pesquisar. O g indica que a pesquisa é global, isto é,
procura todos os caracteres que correspondam a n e não apenas um só.

Outros exemplos:
xyz.match(/banana/g);
Poderíamos por exemplo atribuir a um variável um array com "maçãs e bananas":
var frutas = xyz.match(/maçãs e bananas/g);
Ou então adiciona toString() para coverter o variável a string em vez de um array:
var frutas = xyz.match(/maçãs e bananas/g).toString();
Chame frutas:
frutas; // devolve "maçãs e bananas".
Expressões Regulares são um assunto para além do intuito desta primeira edição. Para uma leitura
mais profunda por favor dirija-se aos seguintes links:
Wikipedia | Mozzila | Ferramenta de Regex.
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

String.prototype.match (regexp). ecma-international.org/ecma-262/5.1/#sec-15.5.4.10


2.1.7 replace( )
Tradução: troca
replace() é outro método de String da categoria pesquisa. replace() devolve-nos uma cópia do
string mas modifica (troca) o termo indicado na especificação do primeiro parâmetro pelo que é
especificado no segundo parâmetro. Expressões Regulares podem também ser utilizadas na pesquisa.
Do nosso exemplo anterior:
var xyz = "As maçãs e bananas são deliciosas";
Podemos trocar deliciosas por saudáveis:

xyz = xyz.replace("deliciosas","saudáveis");
// devolve "As maçãs e bananas são saudáveis".
Repare que modificamos o nosso próprio variável. Poderíamos ter dado esta data a um outro novo
variável e ter mantido o original intacto.
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

String.prototype.replace (searchValue, replaceValue). ecma-international.org/ecma-262/5.1/#sec-


15.5.4.11
2.1.8 search( )
Tradução: busca, pesquisa

O método search( ) devolve um index negativo (-1) se não encontrar nenhum equivalente ao elemento
que procura. Se tal elemento existe, então o resultado será um index positivo indicando a posição
sequencial do elemento.
Exemplos de scripts utilizando o nosso exemplo anterior:
var xyz = "As maçãs e bananas são deliciosas";
Procurando bananas:

xyz.search("bananas");
// devolve 11 (começa contando de zero e b está na posição 11).

xyz.search("na");
// devolve 13 ( de 0, n está na posição 13).
search() é um método sensível a letras maiúsculas e minúsculas:

xyz.search("A");
// devolve position 0 de "As".

xyz.search("a");
// devolve posição 4 (de maçãs)

xyz.search(/a/i);
// devolve posição 0. Aqui utilizamos uma flag (marcador) da biblioteca de Expressões Regulares,
i, para indicar a JavaScript que não importa se o caractere que procuramos é maiúsculo ou
minúsculo, isto é insensível à capitalização. Assim, o primeiro caractere que for encontrado é o que
JavaScript deve devolver.
Para saber mais sobre Expressões Regulares pode visitar os seguintes sítios:
Wikipedia | Mozzila | Ferramenta de Regex.
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.5.4.12 String.prototype.search. ecma-international.org/ecma-262/5.1/#sec-15.5.4.12


2.1.9 slice( )
Tradução: cortar pedaço. O termo em si deveria ser copiar pedaço em vez de cortar.

O método slice( ) copia um pedaço de texto de um string e devolve outro string com a cópia do
texto copiado. O string original não é afetado. No entanto se copiarmos o string para si mesmo,
perderá a data original que não fizer parte da cópia.
Este método aceita dois parâmetros. O primeiro parâmetro indica o primeiro caractere a ser
copiado (contagem a partir de zero). O segundo parâmetro indica o primeiro caractere a não ser
copiado.

Exemplos de scripts:
1- Declare um variável:

var cores = "preta, vermelha, amarela";


2- Atribue a outro variável a cor "vermelha" do variável cores:

var corPreferida = cores.slice(7,15);


3- Chame corPreferida; // devolve "vermelha"
O v de vermelha está na posição 7 (inclusivo), e a virgula no final da palavra está na posição 15
(não inclusiva).

Variações do método slice().


a) Quando o Segundo índice é negativo.
Se inserirmos um índice negativo no segundo parâmetro, JavaScript cortará respectivamente um
número de caracteres da direita para a esquerda baseado no índice, e copiará tudo o resto.
4- Por exemplo, para remover a última cor amarela, assim com o espaço e a vírgula à sua
esquerda, utilizaríamos um índice negativo de -9:

var duasCores = cores.slice(0,-9);


5- Chame o variável duasCores:

duasCores; // devolve "preta, vermelha".


Figure 13

b) Quando se usa um só índice.

Se usarmos apenas um parâmetro com slice, o resultado entre um número positivo e um negativo
é inverso entre um e outro.
6- Número positivo: Deixa tudo até ao índice indicado e copia o resto do string.

var x = cores.slice(3); // devolve "ta, vermelha, amarela". Deixou o "pre".


7- Número negativo: copia o número de caracteres indicado no índice, do fim para o principio,
isto é, da direita para a esquerda, e deixa tudo o resto.
var x = cores.slice(-3); // x devolve "ela" de amarela.

Extraindo caracteres de uma palavra com slice():


8- Extrair o e de ecmascript (esta técnica é bem útil para capitalizar a primeira letra):

"ecmascript".slice(1); // devolve "cmascript".


Nota: Ver também mais abaixo o método substr.
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.5.4.13 String.prototype.slice. ecma-international.org/ecma-262/5.1/#sec-15.5.4.13


2.1.10 split( )
O método split() é bastante útil e por isso devemos ter a certeza de que compreendemos o seu
mecanismo. Split converte um string em um array. Arrays serão cobertos no próximo tópico. Nota:
Para converter um array para string veja join( ).
1- Como exemplo, vamos declarar um novo variável com palavras separadas por um espaço
(sem vírgulas).

var abc = "verde amarelo vermelho preto";


Vocabulário: Em informática, um delimitador é um símbolo (ou sequência de caracteres) que marcam o
principio ou o fim de uma unidade de data, ou separação de tokens (símbolos).
A primeira decisão a tomar quando queremos quebrar um string tornando-o num array, é a escolha
do tipo de delimitador que iremos utilizar para criar a separação de termos. Isto é, na palavra
fictícia de stuibacaitumako, se decidirmos separa em cada i, teremos um resultado de stu baca
tumako. Cortando todos os is criamos a separação desejada. Então os is desaparecem nesta
quebra.
No nosso caso utilizaremos um espaço em branco para separar as palavras. O que isto quer dizer
é que o método split( ) irá excluir todos os espaços em branco (os delimitadores). Tudo o resto no
string será convertido em um array de palavras.
2- Vamos fazer o split ao string abc convertendo-o em um array onde a separação do string é
feita nos espaços em branco (espaços são os delimitadores). Vamos colocar este novo array
num variável com nome de abc2:

var abc2 = abc.split(" ");


3- Chame o variável: abc2; // devolve ["verde", "amarelo", "vermelho", "preto"].
O espaço em branco serviu de delimitador e cada palavra foi convertida em elemento individual
num novo array. Lembre-se que o delimitador é excluído do novo array.
Por outro lado, o método split() aceita também um segundo parâmetro. O primeiro parâmetro é o
delimitador, o segundo parâmetro determina quantos elemento queremos transferir para o novo
array. Isto é, se o segundo parâmetro é 1, apenas a primeira palavra será incluída no novo array.
Vamos experimentar:

4- Declare o variável: var abc3 = abc.split(" ",3);


5- Chame abc3:

abc3; // returns ["verde", "amarelo", "vermelho"], não incluiu o “preto”.


Note: Quando utilizamos split() temos que passar pelo menos um argumento, o delimitador. Se
não declararmos um delimitador na função split, o resultado será a totalidade do string mas sem
separação de elementos, isto é, tudo será uma só unidade. De certa forma isto é uma maneira de
converter um string para array, mas provavelmente não será muito útil sem a separação dos
elementos do string.

Expressões Regulares tornam split num método muito poderoso. Vale a pena investir algum
tempo aprendendo RegEx. Aqui vai um link relacionado com esse assunto: Wikipedia.

Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.5.4.14 String.prototype.split. ecma-international.org/ecma-262/5.1/#sec-15.5.4.14


2.1.11 substr( )
O método substr() é um alternativo do método slice(). A diferença está no significado dos
parâmetros indicados. Enquanto que slice() aceita o índice da posição de começo e o índice da
primeira posição a ser excluída, os dois parâmetros do substr() indicam o começo e o numero de
caracteres a serem incluídos, isto é, o segundo parâmetro é o comprimento, ou length do string a
ser incluído no extrato.

Quando utilizar slice versus quando utilizar substr?


Utilize slice() quando sabe de antemão a posição do primeiro caractere a incluir e a posição do
primeiro caractere a excluir. Utilize substr() quando sabe o comprimento (length) do string a ser
incluído no extrato. Com ambos os métodos necessita de saber a posição do primeiro caractere.
Num substr(), os parâmetros (4,9) indicam uma extração que começa na posição 4 (a contar de
zero e contando espaços em branco, isto é, 4 é o quinto caractere). A extração acaba no caractere
12 (inclusivo) o que significa o décimo terceiro caractere: 4,5,6,7,8,9,10,11,12.

Exemplo (o mesmo exemplo utilizado anteriormente em slice):


1- Declare o seguinte variável:

var cores = "preta, vermelha, amarela";


2- Vamos extrair (copiando) a cor vermelha que se encontra na posição 7 e tem um comprimento
de 8 caracteres:

var corPreferida = cores.substr(7,8);


// A posição 7 é realmente o oitavo caractere porque posições começam a contar de zero.

corPreferida; // devolve "vermelha".


Note: Em substr, o segundo digito, 8, representa o numero de caracteres a serem extraídos. Em
slice, o segundo digito representa a posição do primeiro caracteres a ser excluído do extrato.

Figure 14

Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :


· String.prototype.substr (start, length) ecma-international.org/ecma-262/5.1/#sec-B.2.3
Substr não tinha sido publicado no ecma-262. Mas hoje em dia já se mostra num anexo da
publicação: Annex B (link acima)
2.1.12 substr( ) vs substring( )
Aqui é onde existe alguma confusão porque os nomes substr e substring são bastante parecidos.
Na verdade os métodos não são idênticos e hoje em dia este último método, substring() tem sido
substituído pelo novo método slice.
A certa altura programadores de JavaScript queriam implementar números negativos como
maneira de se contar da direita para a esquerda, ou seja do ultimo elemento para o primeiro. O
problema que se fazer tal mudança era a compatibilidade com programação já implementada em
sistemas existentes e então resolveu-se inventar um novo método, slice(), mantendo o método
antigo, substring() intacto.
Além de não aceitar números negativos, substring não liga importância à ordem dos parâmetros. O
que significa que assume sempre o numero menor como sendo o pimeiro parâmetro. Assim se
codificarmos (5,4) significa o mesmo que (4,5). O método slice() é mais estrito, a ordem é
significante e aceite tal como ela se apresenta.
O que fazer? Utilize slice() mas esteja ciente da existência de substring() para que não seja
confundido com substr().
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.5.4.15 String.prototype.substring. ecma-international.org/ecma-262/5.1/#sec-15.5.4.15


2.1.13 toLowerCase() and toUpperCase()
O método toLowerCase() transforma todos os caracteres de um string para letra minúscula.
Assim “ÁFRICA” transforma-se em “áfrica”.

O método toUppercase() transforma todos os caracteres para letra maiúscula. Desta forma,
“Maçã” transforma-se em “MAÇÔ.

Exemplos de código:
1- Declare e chame o seguinte variável txt:

var txt = "ECMASCRIPT";


2- Converta a letra minúscula: txt.toLowerCase(); // devolve "ecmascript".

3- Converta a letra maiúscula: txt.toUpperCase(); // devolve "ECMASCRIPT".


4- Eis uma maneira de converter só o primeiro caractere baseado em técnicas aprendidas até
agora:
txt.charAt(0).toUpperCase() + txt.slice(1).toLowerCase();
// devolve "Ecmascript". O primeiro caractere é selecionado com charAt(0) e convertido a
maiúsculo com toUpperCase(). Depois concatenamos a string através do método slice (que
retira o primeiro caractere, slice(1) e em seguida aplicamos toLowercase() transfomando o
resultado de slice para letra minúscula. Lembre-se que se utilizarmos slice só com um parâmetro,
slice retira os primeiros caracteres baseado no numero do parâmetros e devolve todos os outros
da esquerda para a direita.
5- Por outro lado, em vez de utilizar charAt poderiamos chamar o primeiro caractere utilizando
a syntaxe de chavetas:

txt[0].toUpperCase() + txt.slice(1).toLowerCase(); // devolve "Ecmascript".


Não esquecer que podemos também utilizar CSS para capitalizar a primeira letra de um
parágrafo:
p:first-letter { text-transform:capitalize; }
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.5.4.16 String.prototype.toLowerCase. ecma-international.org/ecma-262/5.1/#sec-15.5.4.17


· 15.5.4.18 String.prototype.toUpperCase. ecma-international.org/ecma-262/5.1/#sec-15.5.4.18
2.1.14 trim( )
O método trim() que significa podar ou aparar, foi introduzido no último standard ECMAScript 5.
Este método poda os espaços em branco do principio e do final do string, criando uma cópia mais
limpa. Como o método cria uma cópia, se nós desejarmos modificar o original em vez de atribuir
o resultado a outro variável, teremos que aplicar o resultado ao próprio variável.
Exemplos:
1- Declare um string com bastante espaço no principio e no final do mesmo:

Figure 15 ficheiro em raw. icontemp.com/p3/15.txt

2- Chame o variável só para ver como se mostra no monitor:

str1; // devolve o string com espaços no princípio e no final, certo?


3- Declare um segundo variável e aplique-lhe o primeiro variável filtrado com trim():

Figure 16

4- Chame o variável str2 para ver o resultado:

str2; // devolve “teste 123” sem espaços laterais, certo?


5- Chame str1 para ver como se parece.

str1; // devolve o original com espaços em branco.


Como foi dito mais acima, se quisessemos limpar o original teriamos que atribuir o resultado ao
próprio variável como indica na imagem a baixo:

Figure 17
6- Agora se fosse a chamar str1 outra vez os espaços teriam desaparecido.

Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.5.4.20 String.prototype.trim. ecma-international.org/ecma-262/5.1/#sec-15.5.4.20


2.1.15 valueOf( )
O método de String valueOf() converte um objeto para um primitivo. Isto é feito frequentemente e
automaticamente pelo JavaScript. No entanto por vezes necessitamos de chamar este método de
propósito embora não aconteça muitas vezes. Vamos ver como ele funciona.
Todos os objetos, incluindo String, descendem do objeto Object, e todos os objetos herdam
propriedades e métodos do Object.prototype a não ser que estes sejam trocados por métodos ou
propriedades locais. O método valueOf() é herdado do Object mas todos os objetos nativos de
JavaScript tal como String, substituem ou modificam este método para que devolva um resultado
mais apropriado ao type que representam.
Quando chamamos valueOf ele devolve um valor da seguinte forma:
Num Array, um instante de array; Num Boolean, um valor Boolean; Em Date, a data preguardada
de meia noite em Janeiro 1, 1970 UTC; Em Function, a função em si; Em Number, o número
numerico; Em String, o valor de string; Em objetos Math e Error nada é devolvido porque estes
dois objetos não têm método valueOf; Por último, em objetos com valores primitivos, o objeto em
si como um objeto Object.
O sintaxe é o seguinte: nomeDoObjeto.valueOf( ). Quando chamamos valueOf em um variável
tipo string, JavaScript encapsula o variável em um objeto e dá-nos o seu valor primitivo que é um
string. Isto é mais utilizado para consumo interno do JavaScript do que para consumo propositado.

Sample code:
1- Declare a variable: var ppp = "amazon";

2- Call valueOf: ppp.valueOf(); // returns “amazon”.


Recapitulando este conceito, o valueOf() devolve-nos o valor primitivo de um objeto. Se um
primitivo não existe, devolve-nos o próprio objeto referente. Cada objeto nativo modifica o
método valueOf para condizer com o o type que representa. No caso de um String, devolve-nos o
valor do string. Este método é frequentemente utilizado por detrás dos bastidores quando
JavaScript necessita do valor do objeto em si.
valueOf() é o método oficial que se utiliza para extrair um valor singular de dentro de um objeto.
Outro método semelhante é o toString() que embora não seja necessário no caso de um valor type
String, torna-se útil para podermos visualizar no output elementos de outros types de objetos, é
uma forma de exibir o valor em si. Como se disse anteriormente, num objeto type Boolean, o valor
será convertido para a palavra em string true ou false. Em alguns dos outros types, o resultado de
valueOf() não terá grande utilidade para nós e não será aplicado. Este tópico será revisto em
outros capítulos mais adiante.
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :.

· 15.5.4.3 String.prototype.valueOf. ecma-international.org/ecma-262/5.1/#sec-15.5.4.3


Sumário: métodos do Objeto String
Em ECMAScript, o construtor de Objetos pode encapsular todos os seus equivalentes primitivos
tornado-os temporariamente objetos com finalidades especificas.
É como dizer que, quando um Object vê um primitivo a tentar ser utilizado como objeto, agarra-o
e veste-lhe a camisa de objeto para que o método que está sendo aplicado funcione com sucesso.
No fim da transação, tira-lhe a camisa outra vez e o primitivo passa uma vez mais a primitivo. Isto
pode ser visualizado assim:
new Object([primitivo]).
Mais tarde, retirando a transformação da seguinte maneira:
[primitivoComoObjeto].valueOf() (valueOf devolve o primitivo para trás).
Iremos utilizar métodos de String mais adiante porque estes métodos são utilizados em todo o
lado. Terá oportunidade de os revisitar mais tarde.
2.2 Array como Objects em JavaScript
Arrays são objetos de listas ordenadas. Em javaScript, a ordem é que faz com que estes objetos
sejam arrays porque os objetos no seu sentido mais comum são tipicamente não-ordenados, isto é,
compõem-se de pares associativos sem ordem especifica.
(Para listas não ordenadas veja o capítulo 2.9 Listas Associativas como Objects.)

Em JavaScript, arrays utilizam um número de índice que aponta para uma localização onde data é
guardada. Em contraste com outras linguagens, em JavaScript não existe algo chamado array
associativo onde o índice é substituído por uma etiqueta em string. Se tentarmos associar um nome
a um elemento de um array, JavaScript fará dessa data uma propriedade do objeto e não uma peça
de data contida no array. Essa data não será listada quando fazemos o output do array. Se
realmente quisermos uma associação entre um nome chave e sua data, devemos utilizar o
construtor de objetos em vez do construtor de arrays, isto é, usamos chaves em vez de parênteses
retos que identificam arrays.
Graças à rigidez ordenada de arrays, existem métodos específicos para inserir data no principio
ou no final do array, assim como em qualquer outra posição do meio.
O construtor do array é o seguinte:

var bcd = new Array("verde","vermelho","amarelo");


O script acima, declara um variável de nome bcd que aponta para uma construção de type array
constituída por três elementos. Repare no termo new. Embora pudéssemos deixar de escrever
“new” quando declaramos um objeto array nesta forma de sintaxe, é recomendável incluir sempre
a termo new quando utilizamos esta forma de expressão declarativa. Repare também na
capitalização da letra A de Array tal e qual Object e objeto String. Em JavaScript, objetos
nativos assim como objetos próprios da plataforma anfitriã como num browser, têm os seus nomes
capitalizados porque são nomes próprios. Como JavaScript é sensível a letra maiúscula e
minúscula, objetos têm que ser chamados tal e qual foram criados, isto é, neste caso a primeira
letra é em maiúscula.
JavaScript tem uma maneira mais rápida e prática de criar arrays, que é a sintaxe de parênteses
retos.
Em vez de var ijk = new Array( );.

1- É mais comum criarem-se arrays desta forma: var ijk = [ ];


// cria um array vazio. Os parenteses retos são um macro que substitui o new Array.
Ao contrário de outras linguagens, não há necessidade de declarar o número de elementos do
array porque JavaScript pode variar o número dinamicamente qando adicionamos novos
elementos, e tal e qual como acontece com strings, JavaScript copia a data existente mais a nova
data, criando um novo array como o mesmo nome. O array antigo fica sem validade e é apagado
automaticamente.
2- Depois de ter declarado o array acima indicado no seu console, ijk, comece a adicionar
elementos tais como:

ijk[0] = "vermelho";
// o primeiro elemento começa na posição zero.

ijk[1] = "branco";
ijk[2] = "azul";
3- Chame o array no console assim:

ijk;
// devolve-nos ["vermelho", "branco", "azul"].
4- Agora podemos também chamar elementos individuais, como por exemplo:

ijk[0];
// devolve "vermelho".
E tal como o objeto String, o objeto Array herda certas propriedades e métodos do objeto Object.
Vamos em seguida ver algumas das propriedades e métodos mais importantes.
a) Propriedades de um array: length, prototype e constructor.

O constructor já foi demonstrado qundo falamos em String. Cobriremos construtores mais a fundo
num dos próximos capítulos.
O comprimento do array, ou length (soa aproximadamente como lengf), funciona tal e qual o
length de um string. Como sabemos, um string não é mais nada do que um array de caracteres em
sequencia, certo? No entanto, existem razões para utilizar strings e razões para utilizar arrays. Nós
podemos mostrar ou imprimir um string, mas para fazer um output dos elementos do array
necessitamos de iterar por cada um deles. Por outro lado nós podemos mudar um elemento de um
array, mas para mudar um caractere de um string é um pouco mais complicado. E esta é uma das
grandes razões porque às vezes necessitamos de converter um array para type string e outras vezes
necessitamos de converter um string para type array. Se você se lembra, nós utilizamos split( ) para
converter um string para array. O oposto é conseguido através do método join() que será coberto
neste capítulo de métodos de Array.

1- Num string var xyz = "bananas"; // xyz.length; // devolve 7.

2- No nosso array anterior, ijk.length;


// devolve 3 por é ["vermelho", "branco", "azul"].
Length é muito útil quando temos que iterar por um array, o que significa inspecionar cada um
dos elementos para poder fazer algo específico. O que acontece é que na maioria dos casos não
sabemos o comprimento do array, e a propriedade length dá-nos esse valor automaticamente. Daí
a razão de utilizar length em vez de um número especifico. O script torna-se mais portátil. No que
diz respeito a length temos que ter cuidado com o seguinte: O length e a posição de cada elemento
não coincidem porque a posição começa a contar em zero e o length começa a contar em um. A
última posição de um array é sempre o seu length -1. Por vezes este conhecimento é-nos bastante
útil na nossa programação.
Outra propriedade de arrays é prototype. O construtor prototype facilita a adição de novas
propriedades e métodos para um objeto de type Array. Lembre-se que tal e qual o prototype de
String, o prototype de Array adiciona novos métodos e propriedades ao objeto Array() em si, não a
um instante singular de array. Até este ponto e porque ainda não chegamos ao objeto Object, temos
estado a estudar objetos nativos de JavaScript, não objetos criados por nós próprios. Continuaremos
a discutir estes objetos já existentes por algum tempo ainda, porque eles são os mais importantes na
utilização de JavaScript. Depois de cobrir os objetos nativos essenciais falaremos em criar os
nossos próprios protótipos de objetos.
As adições de métodos ou propriedades que criamos nos objetos nativos não são permanentes. Estes
nossos métodos só se aplicam ao momento atual, dentro deste ambiente de execução.
Vamos então inventar um método prototípico que poderemos utilizar com os nossos arrays neste
contexto de execução. O nosso método utilizará o console.log para mostrar os elementos de um array
quando o chamamos. A razão de criar este mecanismo de output é porque arrays, ao contrário de
strings, não faz diretamente um output dos seus elementos. Temos primeiro que os converter para
strings. A razão porque chamo a este nosso método de prototípico é porque será criado não para um
array específico, mas para ser utilizado em todos os arrays existentes nesta execução atual.
1- Para este exemplo utilizaremos o nosso array anterior. Se já não o tem no console copie o
array mostrado abaixo:

var ijk = ["vermelho", "branco", "azul"];


Vamos criar um protótipo com uma função que chamará o length (comprimento) de um array a fim de
iterar por cada elemento do array, e por cada iteração JavaScript fará o console.log de cada
elemento:

Figure 18 ficheiro em raw. icontemp.com/p3/5.txt

A figura de cima utiliza o sintaxe de ponto para ‘colar’ o novo variável listArray à lista de
protótipos, que por sua vez está ‘colado’ ao objeto mãe Array. listArray aponta para uma função
anônima (que atua temporariamente). Este método utiliza um variável temporário, "i", que visita
iterativamente cada elemento do array representado pelo termo genérico “this”. ‘this’ é um termo
genérico que significa o array em questão. Codificando ‘this’ (este, cujo) em vez de um nome
específico do array, torna este script portátil ou universal. O variável “i” cicla através do array
até atingir o número de comprimento (length) do array onde está a atuar. Para cada iteração,
JavaScript imprimirá o elemento de "this" em foco na posição "i", isto é, o elemento do array que
chamou tal método. JavaScript automaticamente substitui o “this” pelo nome do array que está
chamando o método.
2- Copie o método prototípico que se mostra em cima (veja o ficheiro em raw) e coloque-o no
console. Isto adicionará o método listArray() a todos os arrays existentes ou ainda por existir
neste momento de execução.
3- Agora chame o método listArray() aplicado ao nosso array ijk:

ijk.listArray(); // devolve vermelho brando azul.


Você escreveu listArray desta forma listArray( )? métodos são funções e os parênteses são
necessários com algumas excecões que veremos mais tarde.
Só para provar que este método pertence ao objeto mãe Array e não a um array específico, vamos
criar um novo array para ver se o método se aplica ao mesmo:
4- Declare um outro array:

var bcd = ["maçãs","bananas","uvas"];


5- Chame o método listArray() a este novo array:

bcd.listArray(); // devolve maçãs bananas uvas.


Resumindo, sabemos que a propriedade prototype é uma lista onde podemos adicionar
propriedades e métodos para serem utilizados por replicas do objeto a quem o prototype
pertence. Sabemos agora também como se adicionam tais métodos à propriedade prototype. Já o
tínhamos visto aplicado a Strings e agora vimos como se aplicam métodos ao protótipo de Arrays.
Não é necessário memorizar nada disto, aprendemos em camadas. Um elefante come-se dando
uma dentada de cada vez, certo?
Agora vamos aprender alguns métodos preexistentes para manipular arrays.
a) Métodos de Array: concat, join, reverse, sort, pop, push, shift, unshift, slice,
splice
Alguns destes métodos de array já foram discutidos ao falarmos do objeto String e serão
familiares ao os revisitarmos outra vez. Repetição é a mãe da aprendizagem. Mas ao repetir tem
sempre que haver alguma novidade que expanda o conceito que temos sobre o tema em foco.
2.2.1 concat()
O método concat() que significa concatenar (adicionar), adiciona os elementos de um array ao
final dos elementos de um outro array criando assim um terceiro array. O terceiro array não tem
que ser inventado se o nosso intuito é apenas o de fazer um output da combinação de dois arrays.
Vamos ver como isto funciona.
Começamos com os nossos dois arrays anteriores. Se já não os tem no console, siga os primeiros
dois passos do seguinte exercício:
1- Declare um array:

var ijk = ["vermelho", "branco", "azul"];


2- Declare um segundo array:

var bcd = ["maçãs","bananas","uvas"];


3- Agora vamos declarar um terceiro array e atribuir-lhe a soma dos dois arrays anteriores:

var abc = ijk.concat(bcd);


4- Chame o array abc:

abc; // devolve ["vermelho", "branco", "azul", "maçãs", "bananas", "uvas"]


5- Se chamar os dois primeiros arrays verificará que não mudaram em nada. Continuam a ter os
mesmos elementos originais.
É também importante saber que os elementos concatenados foram copiados ou duplicados, isto é,
o terceiro array não é uma referência dos dois primeiros. Todos estes arrays são independentes
uns dos outros.
Se por acaso a nossa intenção fosse a de juntar um array a outro, teríamos codificado do seguinte
modo sem criar um terceiro array: (não faça isto agora pois iremos utilizar estes arrays no próximo exercício.)
ijk.concat(bcd);
ijk; // devolve ["vermelho", "branco", "azul", "maçãs", "bananas", "uvas"]
E deste modo, como não necessitaríamos mais do segundo array, bcd, poderíamos declara-lo
como nulo para limpar a memória do browser: bcd = null;
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.4.4.4 Array.prototype.concat ecma-international.org/ecma-262/5.1/#sec-15.4.4.4


2.2.2 join( )
Join significa juntar. Aqui juntar não significa concatenar como no método anterior. Join resulta
numa junção de todos os elementos de um array, convertidos para um só string.

O método de Array join( ) é o oposto do método de String split( ).


Se ainda tem no console o array abc da nossa última experiência, salte este primeiro passo da
nossa próxima experiência:
1- Declare um array (veja ficheiro em raw. ) icontemp.com/p3/222j.txt :
var abc =["vermelho","branco","azul","maçãs","bananas","uvas"];

2- Declare um segundo array abc2, atribuindo-lhe o resultado de join() com o array abc:

var abc2 = abc.join();


3- Chame abc2:

abc2; // devolve "vermelho,branco,azul,maçãs,bananas,uvas"


Repare como todos os elementos foram separados por uma vírgula. Esta é a opção inicial mas
pode mudar tal opção especificando o símbolo que quer utilizar para fazer a separação, incluindo
espaços em branco entre aspas. Veja os seguintes exemplos:

abc2 = abc.join(" "); // devolve "vermelho branco azul maçãs bananas uvas".
abc2 = abc.join("/"); // devolve "vermelho/branco/azul/maçãs/bananas/uvas". Etc.
Lembrar que o array abc continua intacto na sua forma original.
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.4.4.5 Array.prototype.join ecma-international.org/ecma-262/5.1/#sec-15.4.4.5


2.2.3 reverse( )
O método reverse( ) de um Array inverte a ordem dos elementos contidos no mesmo.

Reverse é permanente, isto é, para voltar ao original terá que aplicar o reverse outra vez.
1- Reverse abc:

abc.reverse( ); // devolve ["uvas", "bananas", "maçãs", "azul", "branco", "vermelho"]


(baseado no nosso array anterior).
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.4.4.8 Array.prototype.reverse ( ) ecma-international.org/ecma-262/5.1/#sec-15.4.4.8


2.2.4 sort( )
O método sort() significa ordenar. No seu padrão original, sort() ordena alfabeticamente. Esta
ordem alfabética não funciona muito bem com números porque por exemplo, o número 20 virá
primeiro que o número 3 pois ordena pelo primeiro algarismo da esquerda. A razão disto é que
sort() converte a data para type string e não reconhece os números pelo seu valor numérico. Para
ordenar numericamente necessitamos de ser mais específicos. Vamos ver como isso funciona.
1- Primeiro teste. (Traga o array do tópico anterior):

abc.sort( ); // devolve ["azul", "bananas", "branco", "maçãs", "uvas", "vermelho"].


2- Até aqui tudo bem. Mas o que acontecerá a um array numérico:

var numA = [5,8,1,3,20];


numA.sort();// devolve [1, 20, 3, 5, 8]
Não faz sentido, não é?
Por causa deste problema de ordenação numérica, JavaScript permite introduzir um parâmetro
que ajuda na seleção numérica dentro dos parênteses do sort(). Existem várias maneiras de
escrever este parâmetro e irei demonstrar a que acho mais simples. O que se introduz no sort( ) é
um exemplo de uma função tipo callback. Não se preocupe muito com o termo neste momento mas
chama-se callback porque JavaScript esta chamando uma função previamente introduzida ( o que
iremos fazer em seguida). (Ver a função na imagem mais abaixo).
O método sort( ) processa a tal função callback com o seguinte critério (continue lendo que fará
mais sentido no final):
Se o resultado da subtração entre dois elementos que estão sendo avaliados pela função for
negativo, o primeiro dos dois elementos a serem avaliados é fornecido ao sorte() porque é menor
do que o outro. Se o resultado da subtração for zero, é porque ambos os elementos são iguais e
cabe então ao sort() decidir qual deles deve ir primeiro. Se o resultado da subtração for positivo,
o segundo elemento é entregue ao sort() e o primeiro passa a ser então subtraído com o próximo
elemento a comparar.
3- Copie esta função para o seu editor:

Figure 19 ficheiro em raw . icontemp.com/p3/19.txt


Ao passar a função compareMe (nome indiferente) como parâmetro do método sort(), estamos
instruindo JavaScript para filtrar cada elemento do array, pela função introduzida como argumento
no sort(). JavaScript filtrará cada dois elementos do array, decidindo depois qual segue para o
sort e qual ficará para trás a fim de ser comparado com o próximo elemento, isto é, no nosso
exemplo, quando num1 é menor que num2, o resultado é negativo. o que faz com que num1 vá
primeiro. Quando a subtração dá zero então os números são idênticos e nesse caso não há troca
de números. Quando num1 é maior que num2, o resultado é positivo. Neste caso JavaScript
mostra num2 primeiro e compara num1 com o próximo número do array. Este critério está
estabelecido numa tábua da biblioteca interna de JavaScript. A função nada tem a ver com a
decisão. A função apenas auxilia JavaScript na sua decisão de execução. O mecanismo de sort()
faz o resto.
4- Agora podemos ordenar os números corretamente:

numA.sort(compareMe); // devolve [1, 3, 5, 8, 20].


5- E se quiséssemos comparar em ordem contrária?

numA.sort(compareMe).reverse(); // devolve [20, 8, 5, 3, 1].


Como sort( ) permite uma função de callback no seu parâmetro, podemos também tirar proveito
para ordenar arrays alfabeticamente, mas baseado no tamanho das palavras, o seu length. Como
os nomes de parâmetros não têm importância eu irei chama-los de a e b no exemplo que se segue.
A figura a baixo mostra um script que poderá utilizar de futuro ou até experimentar agora. Veja o
(ficheiro em raw). Note como o script utiliza muito eficientemente uma função anônima como
callback. Repare também que sendo algumas das palavras de comprimento idêntico, JavaScript
ordena-as alfabeticamente:

Figure 20 ficheiro em raw. icontemp.com/p3/20.txt

Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.4.4.11 Array.prototype.sort ecma-international.org/ecma-262/5.1/#sec-15.4.4.11


2.2.5 pop( ) e push( )
O método de Array pop( ) retira o último elemento do array para fora, diminuindo desta forma o
número de elementos no array em menos 1. Está última ação de diminuir o número do length em
menos um, pode causar um erro quando o número de elementos chega a zero, se estiver utilizando
um loop para sacar os elementos. Preste atenção a essa inconveniência.
Pop pode ser traduzido como um estouro, como faz o milho de pipoca quando salta. Os elementos
saltam para fora do array um a um.
1- Crie o array de frutos outra vez. (ou copie do ficheiro em raw ) icontemp.com/p3/222j.txt :
var abc = ["vermelho","branco","azul","maçãs","bananas","uvas"];

2- Chame o array só para ter a certeza:

abc; // devolve ["vermelho", "branco", "azul", "maçãs", "bananas", "uvas"].


2- Vamos remover o último elemento com pop():

abc.pop(); // devolve "uvas", isto é, retira ‘uvas’.


3- Chame o array outro vez:

abc; // devolve ["vermelho", "branco", "azul", "maçãs", "bananas"].


O elemento “uvas” foi apagado. Vamos traze-lo para trás com push( ):
O método push() faz o oposto de pop(), push() coloca um novo elemento, avançando a última
posição do array.
4- Reinsira o elemento ‘uvas’ de volta:

abc.push("uvas"); // devolve o length de 6 que representa o número de elementos no array


contando com o novo ‘uvas’.
5- Chame o array abc outra vez:

abc; // devolve ["vermelho", "branco", "azul", "maçãs", "bananas", "uvas"].


Como se vê o último elemento ‘uvas’ foi recolocado no sítio.
De certo modo o array está atuando como um stack, restringindo a inserção e exclusão de
elementos no estilo último-dentro – primeiro-fora. Muitas vezes é útil poder inserir e remover
items sem ter que referenciar um local específico onde os colocar, ou de onde os remover.
6- Podemos inserir com push( ) elementos múltiplos (manualmente ou em loop):
abc.push("pêssegos","cerejas", "peras");
7- Agora abc tem 9 elementos:
abc; // devolve ["vermelho", "branco", "azul", "maçãs", "bananas", "uvas", "pêssegos",
"cerejas", "peras"].

Vamos remove-los outra vez com pop() ah, mas espere!!! Embora push() possa inserir vários
elementos de uma só vez, pop() só pode inserir um elemento de cada vez. Teríamos que fazer o
pop() três vezes, certo?
8- Para praticar um pouco, vamos fazê-lo então três vezes. Isto diminuirá o nosso array abc para
o seu conteúdo original. Repare na minha tentativa em remover os items:
abc.pop("pêssegos","cerejas", "peras"); // devolve “peras” ( o último da minha escolha).
Ignorou as minhas instruções como parâmetros e limitou-se a apagar apenas o último elemento do
array.

abc.pop( ); // devolve “cerejas”.


abc.pop( ); // devolve “pêssegos”. Agora devemos já ter o nosso array original de volta:
abc; // devolve ["vermelho", "branco", "azul", "maçãs", "bananas", "uvas"]
Nota: Poderíamos ter utilizado splice() como por exemplo abc.splice(-3,3); (splice será discutido
um pouco mais à frente: 2.2.8 splice ).
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.4.4.6 Array.prototype.pop ( ) ecma-international.org/ecma-262/5.1/#sec-15.4.4.6


· 15.4.4.7 Array.prototype.push ecma-international.org/ecma-262/5.1/#sec-15.4.4.7
2.2.6 shift() e unshift()
Os métodos shift( ) e unshift( ) são semelhantes a pop( ) e push( ), mas atuam no outro extremo
do array, na parte esquerda ou de baixo (conforme queria imaginar o mecanismo), ou seja,
aumentam ou diminuem elementos na posição zero.
Eu imagino um brinquedo de Pez em que quando quero uma bala da parte de cima carrego no
mesmo e salta (pop) a bala para fora. Ou se desejo uma bala da parte de baixo, pego-a com os
dedos e puxo-a para fora (shift) ou então insiro uma bala no fundo fazendo o unshift, ou insiro
uma bala no topo fazendo o push.
Utilizando o nosso array original anterior, ficheiro raw icontemp.com/p3/222j.txt :
var abc = ["vermelho","branco","azul","maçãs","bananas","uvas"];
1- Vamos remover o primeiro elemento com shift:

abc.shift(); // devolve “vermelho” que é retirado.


2- Chame o array abc outra vez:

abc; // devolve ["branco", "azul", "maçãs", "bananas", "uvas"].


3- Agora vamos colocar o primeiro elemento para trás. Aqui temos que especificar o nome do
elemento:

abc.unshift("vermelho"); // devolve 6. Seis é o número de elementos depois da inserção.


4- Chame o array uma vez mais:

abc; // devolve ["vermelho","branco","azul","maçãs","bananas","uvas"].


Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.4.4.9 Array.prototype.shift ( ) ecma-international.org/ecma-262/5.1/#sec-15.4.4.9


· 15.4.4.13 Array.prototype.unshift ecma-international.org/ecma-262/5.1/#sec-15.4.4.13
2.2.7 slice( )
Tal e qual se faz com objetos de type String 2.1.9 slice, o método slice( ) extrai uma cópia específica
dos elementos de um array, e devolve um novo array com os elementos extraídos do primeiro
array. O array original não é afetado pelo extrato a não ser que este extrato seja aplicado ao
próprio array em si (isto é, do original para o original).
Este método aceita dois parâmetros. O primeiro parâmetro indica o primeiro item a ser executado
(a contagem começa em zero). O segundo parâmetro indica o primeiro item a não ser executado.
Vejamos o nosso array outra vez: (ficheiro em raw) icontemp.com/p3/222j.txt.
1- O nosso array abc é neste momento
var abc = ["vermelho","branco","azul","maçãs","bananas","uvas"];

2- Vamos aplicar o método slice( ) criando um novo array onde excluímos os elementos
“bananas” e “uvas”, isto é, incluímos todos os outros elementos:

var abc2 = abc.slice(0,4); // começando no zero (vermelho), 1(branco), 2(azul), 3(maçãs),


4(bananas, excluído).
3- Chame o array abc2:

abc2; // devolve ["vermelho", "branco", "azul", "maçãs"].


O método slice( ) é mais complexo do que acabamos de ver. Por exemplo, utilizando números
negativos podemos ser mais específicos e copiar elementos a partir do fim do array (o length do
array) em direção ao princípio. Vamos ver alguns exemplos para ilustrar como funciona:
4- O nosso array abc é ["vermelho","branco","azul","maçãs","bananas","uvas"].
5- Declare outro array abc3, e atribuindo-lhe um slice de abc com o parâmetro de -2:

var abc3 = abc.slice(-2); // slice copiará os últimos 2 itens de abc e deixará tudo o resto
para trás. Um número negativo em slice seleciona elementos da direita para a esquerda. O número
de elementos selecionados corresponde ao número negativo apresentado. Neste caso copiamos
dois elementos do final do array.

abc3; // devolve-nos ["bananas", "uvas"].


6- Declare outro array abc4, e atribuindo-lhe um slice de abc com 2 parâmetros negativos, (-4,-
2):

var abc4 = abc.slice(-4,-2);


Este exemplo pode ser à primeira vista um pouco confuso . O -4 indica o primeiro elemento a
contar do fim que irá ser copiado. Neste caso o quarto elemento a partir do fim é ‘azul’. O -2
indica o primeiro elemento a contar do fim que irá ser excluído da cópia. Neste caso, tudo o que
vier a partir de ‘bananas’ e até ao final, não será copiado.
7- Chame abc4:

abc4; // devolve ["azul", "maçãs"].


Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.4.4.10 Array.prototype.slice ecma-international.org/ecma-262/5.1/#sec-15.4.4.10


2.2.8 splice( )
O método de Array splice( ) é bem interessante. Você ainda se lembra de push e unshift? ambos
adicionam elementos respectivamente no final e no princípio de um array. O método splice()
adiciona (ou retira) elementos por entre os meios.
Vamos ver como isso funciona.
Dependendo quantos argumentos introduzimos como parâmetros dentro dos parênteses de
splice(), poderemos apagar, adicionar ou trocar elementos.
· Utilizando apenas dois parâmetros (modo remover):
Quando utilizamos apenas dois argumentos como parâmetros estamos dando as posições de
índice de onde a ação irá começar (inclusivamente), e quantos elementos serão apagados.
Como fará mais sentido abaixo, quando temos só dois parâmetros, splice() actua em modo de
remover ou apagar, isto é, não há elementos a adicionar. Nota: Não confundir os parâmetros de
splice em arrays com os parâmetros de slice em strings, os parâmetros têm sentidos diferente.
Por exemplo, splice(0,3) significa que elementos 0, 1 e 2 serão apagados. O número 3 representa
a quantidade de elementos a apagar. Esta versão pode ser utilizada em vez de pop e shift.
· Utilizando mais que dois parâmetros (modo adicionar ou trocar):
Quando inserimos mais que dois argumentos como parâmetros em splice(), JavaScript assume
que iremos adicionar (ou trocar) elementos no array e o critério funciona da seguinte forma:
a) O segundo parâmetro indica quantos elementos irão ser apagados ou trocados. Podemos
também colocar o segundo parâmetro como zero, o que significa que a operação será apenas
de inserção sem apagar ou trocar elementos.
b) O terceiro e outros parâmetros seguintes, indicarão os novos elementos a serem
adicionados ou trocados.
Por exemplo, splice(2,0,"amarelo") significa para inserir "amarelo" na posição 2 (como terceiro
elemento) aumentando o array length por mais um.
splice(2,1, "amarelo") significa para trocar o elemento que se encontra na posição 2 (terceiro
elemento) por "amarelo". O length do array mantém-se na mesma porque o parametro 1 diz que o
amarelo tem que substituir o elemento atualmente existente. A posição 2 refere-se ao terceiro
elemento a contar de zero. O terceio elemento é apagado e o amarelo toma o seu lugar.
Esta versão de slice() pode ser utilizada em vez de push e unshift.
A imagem a baixo ilustra ambos os conceitos.
Figure 21

Vamos experimentar com alguns exemplos para sintonizar bem com este critério.
· Removendo itens com splice( ):
1- Declare um novo array x, ficheiro em raw: icontemp.com/p3/21.txt :
var x = ["azul","vermelho","verde","violeta","castanho"];
2- Apague 3 elementos a partir da posição 0:

x.splice(0,3); // apagou "azul", "vermelho", "verde"


3- Chame o array x:

x; // devolve ["violeta", "castanho"].


· Adicionando itens com splice( ):
4- Vamos adicionar os nossos itens para trás:

x.splice(0,0,"azul","vermelho","verde");
3- Chame o array x:

x; // devolve ["azul", "vermelho", "verde", "violeta", "castanho"]. Começamos na posição zero e


adicionamos todos os itens listados, removendo zero itens.
O que aconteceria se agora repetíssemos o exemplo 4, mas com o segundo parâmetro a 3 em vez
de zero? splice() apagaria os três itens, e depois colocaria os três itens listados que são
exatamente os mesmos. Por outras palavras, nada aconteceria.
Como vemos, o segundo dígito é que faz toda a diferença entre os vários modos de splice(),
exceto no próximo caso onde o primeiro parâmetro muda o modo drasticamente.

· splice() com números negativos:

Lembra-se da nota ao fundo to tópico pop( )?

abc.splice(-3,3);
O número -3 conta três itens do final para o princípio. Estes três elementos estarão em foco para a
ação que será decida nos próximos parâmetros. O próximo parâmetro, o segundo número, diz-nos
para apagar este três itens. Neste exemplo não existem trocas.
Se desejar experimentar este critério, coloque o array abc no console (ficheiro em raw)
icontemp.com/p3/222j.txt. Depois aplique o script mostrado acima. Este splice() apagará "maçãs",
"bananas", "uvas".
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.4.4.12 Array.prototype.splice ecma-international.org/ecma-262/5.1/#sec-15.4.4.12


2.3 Novos Métodos de Iteração com Arrays em JavaScript
2.3.1 forEach()
Não confundir o novo método forEach() com aquele tipo de loop for each… in que já foi
descontinuado em JavaScript moderno.
forEach que se traduz em paraCadaUm: faça isto, é uma função que aceita uma outra função
como input e utiliza os parâmetros deste input para selecionar os valores do array especificado.
Este método forEach( ) foi introduzido com a versão ECMAScript 5 que adicionou nove métodos
ao arsenal de funcionalidade para manipulação de arrays. Estes métodos fazem operações que
previamente teríamos que criar scripts mais complexos como por exemplo loops iterativas. Os
nove métodos são: indexOf, lastIndexOf, every, some, forEach, map, filter, reduce,
reduceRight.
forEach( ) faz uma ação especificada pelo programador para cada elemento do array. Essa ação
específica depende das instruções que se seguem no script depois da declaração do macro
forEach().
forEach( ) aceita uma função como argumento (uma daquelas a que chamamos callback). Os
parâmetros da função inserida farão comunicação (interface) com cada elemento válido do array
onde serão aplicados de uma maneira iterativa, baseada no script que se segue, tal e qual como
faríamos com um for loop. Com um elemento válido quero dizer um endereço de elemento onde
existe data. Todos os índices do array que não tenham um valor ou que sejam undefined (se
houver algum), serão ignorados.
1- Vamos experimentar com este método em incrementos. Comecemos por introduzir no console
um novo array (Estou usando Opera ou Chrome):

var g = ["vermelho", "azul", "branco"];


2- Chame forEach( ) aplicado ao array g usando uma função anônima com apenas um parâmetro,
"i" (ver a figura seguinte) (o i é um nome fictício):
Figure 22 ficheiro em raw. icontemp.com/p3/22.txt

A função anônima utilizada neste método pode conter até três parâmetros, sendo os primeiro dois
os mais populares. O primeiro parâmetro (como no nosso exemplo), aponta para cada valor de
elementos no array. Ainda se lembra quando no tópico Mais Valores Primitivos e Valores de Referência
mencionamos como poderíamos apontar para um valor de type referência como por exemplo um
dos valores de tipo array, através de um parâmetro de função? Reveja a lição desse capítulo se
necessita de se recordar.
Este “macro” forEach() facilita a nossa codificação de scripts, tal como o que costumávamos
fazer com o seguinte for loop:
for (var i = 0; i < array.length; i ++)

No exemplo de forEach( ) na figura de cima, parâmetro i apontará para cada valor existente no
array, e o método forEach fará leitura do valor em si que coincide com o apontamento de i e de
acordo com as instruções no corpo do nosso método. Neste exemplo as instruções são para enviar
cada valor ao console.log em cada posição i. E o resultado é: vermelho, azul, branco (em linhas
separadas porque cada console.lo é independente).
3- Vamos experimentar o mesmo script com dois parâmetros em vez de um só:
Figure 23 ficheiro em raw. icontemp.com/p3/23.txt

Como dantes, o primeiro parâmetro aponta para o valor da data. O segundo parâmetro aponta
para o index em si (ou seja o valor numérico do sítio onde i está visitando no momento). O termo
utilizado como parâmetro não faz diferença, pode utilizar Fernando e Filomena em vez de i e
índice que vai dar ao mesmo; o importante é a posição de sequência de cada um destes dois
parâmetros.
No nosso exemplo console.log fará o output do segundo parâmetro, seguido de um :, e seguido
pelo valor do primeiro parâmetro a cada iteração do forEach.
Notas: forEach chama a função anônima callback uma vez por cada item do array. E chama em
ordem ascendente. Por vezes um terceiro parâmetro é utilizado para especificar o nome do
Array onde o script está sendo implementado.
O método forEach é intencionalmente genérico; não é necessário que o terceiro parâmetro onde
vai atuar seja do type Array. Por isso o método pode ser aplicado a outros tipos de objetos mas
não é tão simples assim: a funcionalidade do método forEach em outros tipos de objetos é
dependente da plataforma onde JavaScript está sendo utilizado.
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.4.4.18 Array.prototype.forEach. ecma-international.org/ecma-262/5.1/#sec-15.4.4.18


2.3.2 map( )
O método map( ) itera por um array visitando cada elemento, tal e qual o método forEach( ) mas
com a exceção de que devolve um valor global (return de função), enquanto que forEach faz
apenas uma leitura e não devolve um total no fim. Como map() devolve um valor real, este pode
ser utilizado para criar um array baseado no original que está iterando. Outra diferença é que
forEach() chama a função para cada item onde itera, enquanto que map() chama a função uma só
vez em todo o processo. O significado disto é que, enquanto forEach() se esquece do elemento
anterior quando passa para o próximo, map() vai acumulando a data para a devolver no final
como um novo array.
Vamos ver um exemplo:
1- Declare um novo array (ver o ficheiro raw por debaixo da imagem):
var primeiroArray = ["amazonas", "nilo", "kwanza"];
2- Declare um segundo array chamdo segundoArray e atribua-lhe o resultado de map() que pega
no conteúdo do primeiro array e aplica-o ao novo array. Só para ter a certeza de que são
realmente independentes e não uma referência para a mesma data, modifique o segundoArray
para que os elementos sejam em letra maiúscula (lembra-se como se faz?). Depois chame o
segundoArray para ver o resultado:

Figure 24 ficheiro em raw. icontemp.com/p3/24.txt

Tal e qual em forEach( ), utiliza-se aqui uma função anônima tipo callback mas com só um
parâmetro que aponta para cada elemento do array a que é chamado, o primeiroArray. Sendo
map() e não forEach(), cada elemento foi copiado para um outro array a que chamamos
segundoArray. A magia desta função está no script interno que JavaScript tem na sua biblioteca
quando endereçamos o mesmo com este macro map(). Tudo o que nós fazemos é simplesmente
escrever os parâmetros que nos interessam e o JavaScript faz o resto.
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.4.4.19 Array.prototype.map ecma-international.org/ecma-262/5.1/#sec-15.4.4.19


2.3.3 every( )
O método every( ) que se traduz em “todos ou tudo”, é outro método de iteração. Chama-se
“every” porque tudo o que for verificado deve ser true para todos os elementos do array ou o
resultado devolvido (return) será false. Tudo ou nada. Este método só faz leitura e relata a
característica do array que está sendo verificado.

Geralmente utiliza-se every( ) para inspecionar o array e tomar decisões baseado na informação
recebida para trás: true ou false.
Eis um exemplo de script que verifica se os elementos são par ou ímpar. Se par, return true, else,
return false:
1- Declare um novo array com números consecutivos:

var abc = [1,2,3,4,5];


2- Chame o array abc com o método every( ), utilizando uma função callback que verifica se os
números são todos pares. Se todos os itens não forem números pares, every ( ) resultará em
“false”:

Figure 25 ficheiro em raw. icontemp.com/p3/25.txt

Lembre-se dos outros métodos anteriores: “item” é um nome genérico para representar cada
elemento do array. Este parâmetro serve de interface entre o array e o script que busca
informação, isto é aponta para cada elemento do array (coloco ênfase no cada (em Inglês each) porque todos
estes métodos são versões modificadas do método forEach( )). Conforme item aponta, e a função faz a sua magia
em classificar quem é par e quem não é, every( ) auxilia a função apanhando todos os elementos,
um a um. No final, every() faz o return baseado no facto de todos qualificarem ou nenhum
qualificar.
Como se vê, every() age no princípio de cada iteração e depois age no final de todas as iterações.
São vários mecanismos trabalhando em conjunto num script da biblioteca de JavaScript.
3- Eis um exemplo de um array que resultará em true:
var xyz = [2,30,40,60];
4- Depois de introduzir o array xyz no console, modifique o método every() para acomodar xyz
em vez de abc. Se tudo correr bem o resultado será true.
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.4.4.16 Array.prototype.every. ecma-international.org/ecma-262/5.1/#sec-15.4.4.16


2.3.4 some( )
No que diz respeito a tudo ou nada, o método some( ) é o oposto de every( ). Some traduz-se em
“alguns” ou “uns tantos”. Este método devolverá true se algum dos elementos qualificar para o
critério estabelecido no corpo do método. Tal como every( ), não modifica em nada o script,
serve apenas de investigador e faz a reportagem da classificação. Fica a nosso critério manipular
tal data em questão.
Aqui vai um exemplo baseado na mesma data do últimos exercício:
1- Declare um array abc com números consecutivos:

var abc = [1,2,3,4,5];


2- Chame o array abc com o método some( ), utilizando uma função callback que verifica se
alguns dos números são pares. Se houverem números pares de volta a classificação de “true”:

Figure 26 ficheiro em raw. icontemp.com/p3/26.txt

Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.4.4.17 Array.prototype.some ecma-international.org/ecma-262/5.1/#sec-15.4.4.17


2.3.5 filter( )
O método de array filter( ) funciona do mesmo modo que some( ) mas em vez de reportar true ou
false, ele devolve um array com os elementos que qualifica como true ou seja, verdadeiros. De
certo modo faz lembrar map() devido à criação de um novo array.
Vamos utilizar o mesmo array abc como exemplo.

1- Declare o array abc se já não o tem no console:

var abc = [1,2,3,4,5];


O que queremos fazer aqui como exemplo, é extrair uma cópia de todos os elementos numéricos
que sejam par e colocá-los em outro array.
2- Então declare um novo array abc2 e use filter( ) para investigar todos os elementos do array
abc, copiando para abc2 todos aqueles que qualificarem como par:

Figure 27 ficheiro em raw. icontemp.com/p3/27.txt

3- Chame o array abc2 e verifique o resultado que deve ter sido [2, 4].
Temos agora dois arrays abc e abc2. O abc array não foi afetado porque filter() fez simplesmente
uma cópia de elementos escolhidos sob o critério que estipulamos.
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.4.4.20 Array.prototype.filter ecma-international.org/ecma-262/5.1/#sec-15.4.4.20


2.4 Novos Métodos de Redução e Localização para Arrays em JavaScript
2.4.1 O que é Redução
Em ciência de computação, redução é um algoritmo que transforma um problema em outro problema
mais simples, isto é, a conversão de uma expressão ou equação para a sua forma mais simplificada.
ECMASCript 5 introduz dois métodos de redução: reduce( ) e reduceRight( ). A diferença entre um
e outro é a direção ou o sentido em que eles operam. O primeiro começa no princípio do array, o
segundo começa do fim para o princípio.
Ambos os métodos de redução aceitam uma função anônima como valor de base opcional:

Figure 28

Informação preliminar
Antes de mostrar algum exemplo destes métodos vamos dispender um pouco tempo tentando
compreender a sintaxe destes dois mecanismos.
Parâmetros que modificam o resultado dos métodos reduce/reduceRight:

O valorInicial – Sendo este valor opcional, a iteração da função começará no valor de valorInicial
se for apresentado.
Nos métodos de redução, quando o valorInicial é dado, o primeiro parâmetro da função anônima a
que eu chamarei nos nossss exemplos de valorPrevio, começa no valor de valorInicial. Neste caso,
o segundo parâmetro da função a que eu chamarei nos nossos exemplos de valorCorrente, começa
na posição do primeiro elemento do array.

Figure 29
Normalmente o valorInicial não é incluído. Neste caso, o primeiro parâmetro, valorPrevio,
começa a atuar na localização do primeiro elemento do array onde estamos a aplicar este método,
e o segundo parâmetro, valorCorrente, começa no segundo elemento do array.
Nos próximos dois exemplos veremos como tudo isto funciona.
2.4.2 reduce( )
O método reduce( ) atua baseado em uma função de tipo callback que é inserida pelo
programador e que aceita até 4 argumentos em seus parâmetros. Os argumentos, meus nomes
aleatórios, são:
a) valorPrevio – O valorPrevio (nome aleatório) é o valor do cáculo anterior, ou o valor do
primeiro elemento antes da atuação do método, ou o valor do valorInicial se este existir.
b) valorCorrente – O valor do elemento na iteração atual (posição atual) que irá ser processado
com o valorPrevio, ou o valor do segundo elemento do array no princípio do algoritmo (mas
aqui, quando o valorInicial está presente, o valorCorrent passa a ser o primeiro elemento
porque o valorPrevio assume o valor da declaração valorInicial).
c) index (índice corrente) ou localização atual da função no objeto sendo iterado. Pode excluir
este parâmetro porque não é essencial, ou incluir se o necessita para o seu output.
Vamos ilustrar estes conceitos com um exemplo, declarando um array numérico. Depois
declaramos um variável para guardar o resultado da multiplicação de todos os números do array
utilizando o método reduce( ).
1- Declare um array com nome de meuArray:

var meuArray = [2,4,6,8];


2- Declare um variável de nome aleatório reduzido e atribua-lhe o resultado da aplicação de
reduce() ao meuArray, onde cada dois valores serão multiplicados um pelo outro.

Figure 30 ficheiro em raw. icontemp.com/p3/30.txt

3- Chame reduzido; // devolve 384.


Na primeira iteração o valorPrevio é 2 (primeiro elemento) e o valorCorrente é 4 (segundo
elemento): 2 x 4 = 8, depois 8 x 6 = 48, depois 48 x 8 = 384.
Por outro lado, se tivéssemos incluído o valorInicial, que iria aqui: }, valorInicial); o
valorPrevio teria começado no valor dado em valorInicial, e o valorCorrente teria começado no
primeiro elemento do meuArray em vez de no segundo elemento. O resultado total teria sido
diferente porque o valorInicial teria influenciado a operação. Veja o próximo exemplo.
4- Por exemplo, declaremos um outro variável reduzido2 para guardar o resultado de um
método reduce() aplicado ao meuArray. Desta vez iremos incluir um valorInicial de 10:
Figure 31 ficheiro em raw. icontemp.com/p3/31.txt

5- Chame reduzido2; // devolve 3840. Uma diferença enorme do script anterior.


Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.4.4.21 Array.prototype.reduce ecma-international.org/ecma-262/5.1/#sec-15.4.4.21


2.4.3 reduceRight( )
O método de array reduceRight( ) funciona da mesma maneira que o método anterior, reduce( ).
A única diferença é que reduceRight() começa a processar a partir do último elemento do array,
enquanto que reduce() começa a processar a partir do primeiro elemento do array. Um funciona da
direita para a esquerda, o outro da esquerda para a direita. Tudo o resto que foi descrito para
reduce( ) no tópico anterior aplica-se também a reduceRight( ).
Se aplicarmos os scripts anteriores (multiplicação) a reduceRight( ), o resultado será idêntico,
384 e 3840. Se quiser experimentar, troque “reduce” por “reduceRight” na linha 1 dos exemplos
anteriores (ver figuras a cima).
Para o propósito de ilustrar onde diferem estes métodos, vamos criar um novo script. Desta vez
subtraímos os valores em vez de os multiplicar:

1- Use o meuArray anterior. Se está a recomeçar o seu console de JavaScript, declare o array
indicado a baixo:

var meuArray = [2,4,6,8];


2- Depois copie ou codifique o seguinte método:

Figure 32 ficheiro em raw. icontemp.com/p3/32.txt

3- Chame subReduz; // devolve -16.


4- Agora modifique o método para reduceRight:

Figure 33 ficheiro em raw. icontemp.com/p3/33.txt

5- Chame uma vez mais subReduz; // devolve -4.


No exemplo acima, subReduz devolveu -4 quando utilizando o método reduceRight, e -16 quando
usando o método reduce.
Como se pode ver, o resultado de subtrair todos os elementos é consideravelmente diferente entre
um e outro método. Quando desejar aplicar um destes métodos em um projeto seu, estas diferenças
serão importantes na sua decisão de qual método utilizar.
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.4.4.22 Array.prototype.reduceRight ecma-international.org/ecma-262/5.1/#sec-15.4.4.22


2.4.4 Métodos de Localização
Para além dos métodos de iteração e redução, JavaScript tem dois outros métodos que podem ser
utilizados para localizar elementos em um array: indexOf( ) e lastIndexOf( ). IndexOf começa da
esquerda para a direita, e lastIndexOf começa da direita para a esquerda. Ambos funcionam do
mesmo modo e ambos devolvem a mesma posição de referência numérica, mas a posição escolhida
por cada um destes métodos pode variar dependendo das circunstâncias, isto é, se houver duplicação
de elementos o lastIndexOf devolverá o último elemento duplicado, enquanto que o indexOf
devolverá o primeiro elemento (por primeiro e último refiro-me à direção de esquerda para direita
ou seja, de princípio para o fim).
2.4.5 indexOf( ) versus lastIndexOf( )
Se tudo o que queremos é o índice de um elemento único, indexOf e lastIndexOf dão o mesmo
resultado. No entanto, em arrays muito compridos um poderá ser mais eficiente do que o outro,
dependendo onde se encontra o elemento que procuramos: se na primeira metade ou se na segunda.
No caso que haja mais do que um elemento idêntico, escolher um método em vez do outro devolverá
resultados diferentes.
1- Vamos declarar um novo array no console. (ficheiro em raw) icontemp.com/p3/245.txt
var x1 = ["amendoim", "amendoas", "nozes", "castanhas"];
2- Chame o index de “nozes” usando indexOf( ) :

x1.indexOf("nozes"); // devolve 2 porque conta 0,1,2.


3- Chame o index de “nozes” outra vez, mas utilizando lastIndexOf( ):

x1.lastIndexOf("nozes"); // devolve 2. Embora faça a pesquisa a partir da direita, o


resultado numérico é o mesmo que o exemplo anterior porque se baseia na posição oficial de
esquerda para direita. Por outras palavras, faz uma decrementação em ordem inversa como por
exemplo 3,2,1,0.
4- Vamos tentar com “amendoim” em ambos os casos:

x1.indexOf("amendoim"); // devolve posição 0.


x1.lastIndexOf("amendoim"); // devolve posição 0.
Do ponto de vista dos quatro testes que fizemos a cima, não existe diferença no resultado de um ou
outro método.
No entanto, se existirem dois elementos com valores idênticos, o resultado será diferente.
Considere o próximo exercício:
5- Adicione um segundo elemento “nozes” no fim do array utilizando o método push( ):

x1.push("nozes"); // devolve o índice de 5 elementos. Se chamar o array x1 será:


["amendoim", "amendoas", "nozes", "castanhas", "nozes"].
6- Agora chame o index de “nozes” com indexOf( ) :

x1.indexOf("nozes"); // devolve posição 2.


7- Chame o index de “nozes” usando lastIndexOf( ):

x1.lastIndexOf("nozes"); // devolve posição 4. Encontra o último elemento “nozes”


primeiro e é este que devolve.
Nota: Se o elemento que procuramos não for encontrado, estes métodos devolvem um -1. Isto é
importante porque pode vir a ser muito útil como veremos em outras ocasiões.

Como são os elementos comparados?


Os métodos de índex comparam os elementos introduzidos na pesquisa com os elementos no array,
usando um sistema que se chama igualdade estrita, que é o mesmo método utilizado pelo operador
=== (o operador triplo de igualdade). Isto é, se os elementos diferirem em sintaxe, ou em type, não
serão reconhecidos como idênticos e o algoritmo devolverá um -1 que significa “não encontrado”.
Segundo parâmetro (opcional): Onde iniciar pesquisa.
Existe um segundo parâmetro que aceita um argumento opcional nestes dois métodos indexOf( ) e
lastIndexOf( ). Este parâmetro é conhecido como fromIndex ou seja aPartirDeIndex.
Este parâmetro especifica a localização onde iniciar a pesquisa (inclusivamente). Isto significa que
em logos arrays, é possível saltar uma certa quantidade de elementos para pesquisar mais além,
poupando algum tempo de processamento.
fromIndex começa a contar em zero, o que significa que o primeiro elemento conta como 0 e depois
1,2,3, etc.
Este é o exemplo que temos neste momento no console:
["amendoim", "amendoas", "nozes", "castanhas", "nozes"];

8- Vamos experimentar com o parâmetro fromIndex. Use um argumento de 2:

x1.indexOf("nozes",2); // devolve posição 2 (encontrou o primeiro elemento “nozes” que


por coincidência estava na posição onde a busca se iniciou. Se estivesse um pouco mais a trás só
teríamos encontrado o último ‘nozes’ como iremos ver em seguida.

x1.indexOf("nozes",3); // devolve posição 4 (nunca chegou a ver o primeiro ‘nozes’ porque


a pesquisa começou depois, na posição 3 (castanhas), e então encontrou o segundo elemento
contendo o mesmo nome.
Agora vamos ver como atua o método lastIndexOf em circunstâncias idênticas:

x1.lastIndexOf("nozes",2); // devolve 2 (Não se apercebeu do elemento nozes mais


chegado ao fim porque só começou a pesquisa na segunda posição do array e em sentido
decremental (2,1,0). Lembre-se que este método busca da direita para a esquerda.
9- Um outro exemplo:

x1.lastIndexOf("nozes",4); // devolve 4. Como 4 coincide com o final do array, este


método encontrou o elemento ‘nozes’ mais chegado ao fim que coincidentemente era o último
elemento (ou o primeiro a ser investigado da direita para a esquerda).
Critério de pesquisa - sumário.
O sumário incluído em baixo contem algumas especificações que ainda não tínhamos coberto. Este
sumário serve de referência para uso futuro. Não tente memorizar estas regras para não ficar
confundido. Quando necessitar de tomar uma decisão volte a esta página para escolher o método
mais apropriado. Se for algo que fará constantemente então com tempo ganhará experiencia sem ter
que voltar a consultar esta página. O mais importante é compreender as diferenças entre uns métodos
e outros assim como saber que eles existem.
· Critério de pesquisa para o método indexOf( ) em relação ao fromIndex:
a) O argumento fromIndex é opcional e é representado como segundo parâmetro. Se ele não for
incluído, JavaScript assume posição zero para iniciar a sua pesquisa. Se por outro lado o
fromIndex for maior ou igual ao comprimento do array, a pesquisa não será implementada
porque já ultrapassou o array e o resultado de -1 será devolvido pelo método.
b) Um fromIndex positivo indica onde iniciar a pesquisa (inclusivamente) e a busca do
indexOf() é feita da esquerda para a direita. Exemplo: um fromIndex de 1 começa a busca no
segundo elemento (inclusivamente) porque este índice é base zero, o que faz com que o
primeiro elemento seja na posição zero.
c) Por outro lado, se o fromIndex for um número negativo, será utilizado para fazer o offset do
primeiro elemento a ser pesquisado. Este offset baseia-se no comprimento do array + o número
negativo isto é, num array de 5 elementos, a busca começa na posição 4 e para a frente, o que
inclui apenas 4 e 5 no nosso exemplo. (offset significa "fora do lugar", deslocado).
Exemplo:
1- O nosso array x1 é ["amendoim", "amendoas", "nozes", "castanhas", "nozes"]

x1.indexOf("nozes", -2); // devolve a posição 4 para ‘nozes’. O critério é que -2 irá iniciar a
pesquisa no elemento ‘castanhas’ (segundo a contar do fim), seguindo depois para a direita e
descobrindo ‘nozes’ na última posição do array.
· Critério de pesquisa para o método lastIndexOf( ) em relação ao fromIndex:
a) O argumento fromIndex é opcional e é representado como segundo parâmetro. Se ele não for
incluído, JavaScript assume a posição última do array, isto é o número assumido é o
comprimento do array menos 1 (devido à base zero). Isto faz sentido porque o lastIndexOf()
começa a pesquisa no último elemento e move-se da direita para a esquerda.
Num array com 5 elementos, o fromIndex assume automaticamente a posição no.4 que
corresponde ao quinto elemento: 0,1,2,3,4. Se por acaso o fromIndex for maior que o
comprimento do array, isso não fará diferença pois é como se não tivesse sido incluído. Num
array de 5 elementos, um fromIndex de 5 ou de 6, etc. terão o mesmo efeito como se fossem
um fromIndex de 4 (o normalmente assumido).
b) Um método lastIndexOf( ) com um fromIndex negativo começará a pesquisa numa posição
offset baseada no comprimento do array mais o número negativo (como descrevemos para o
outro método) e depois move-se da direita para a esquerda. Um array com 5 elementos e um
fromIndex de -1 começará como seria normalmente na posição 4 que corresponde ao ultimo
elemento do array.
2- No exemplo em baixo, dado este array ["amendoim", "amendoas", "nozes", "castanhas",
"nozes"], a busca escolherá o último ‘nozes’:

x1.lastIndexOf("nozes",-1); // devolve posição 4.


Do mesmo modo, o array com 5 elementos e um fromIndex de -2 começará na posição no.3, ou
seja o quarto elemento (inclusivo).
3- No exemplo abaixo baseado neste array ["amendoim", "amendoas", "nozes", "castanhas",
"nozes"], a busca começará em ‘castanhas’, devolvendo o ‘nozes’ da posição no. 2
(coincidência de números).
x1.lastIndexOf("nozes",-2); //devolve posição no.2. Começou a pesquisa depois de ter
passado o primeiro ‘nozes’ a contar do fim e da direita para a esquerda na posição de
‘castanhas’, e devolveu ‘nozes’ da posição no.2 (terceiro elemento a partir do principio).
c- Num método lastIndexOf( ), um fromIndex positivo determina a posição onde se iniciar a
pesquisa (inclusivamente) que depois move da direita para a esquerda. Exemplo: um
fromIndex de 0 só pesquisará o primeiro elemento da esquerda porque é posição no. zero e a
pesquisa move-se da direita para a esquerda. No nosso exemplo seria amendoim. Um
fromIndex de 1 pesquisará o segundo e o primeiro elemento, por essa ordem. Etc.
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

· 15.4.4.14 Array.prototype.indexOf ecma-international.org/ecma-262/5.1/#sec-15.4.4.14


· 15.4.4.15 Array.prototype.lastIndexOf ecma-international.org/ecma-262/5.1/#sec-15.4.4.15
Parabéns por ter investigado todos este métodos. Este conhecimento ser-lhe-á muito útil. Não se
esqueça de repetir a leitura de vez enquanto e também utilizar esta informação como referencia. Se
houver alguma modificação eu chamarei atenção nos ficheiros em raw.
Em seguida exploraremos um pouco mais sobre funções.
Vamos então?
2.5 Funções de JavaScript e Argumentos como Objetos
Num outro capítulo mencionamos que em JavaScript todas as funções são atualmente objetos.
Vamos explorar esse conceito um pouco mais além.
2.5.1 O objeto arguments
Em ECMAScript 5 os argumentos deixaram de ser propriedades da função para se tornarem num
objeto chamado arguments. Este objeto foi estabelecido à semelhança de arrays, embora o
número de propriedades herdadas do Array tenha sido limitado a apenas um: length
(comprimento).
Length é uma propriedade importante porque facilita a iteração de cada argumento através de
loops (ciclos).
Um objeto arguments atua como um variável local da função. Este objeto arguments só funciona
mesmo com funções, não tem vida própria fora deste ambiente. Ele é posto em ação pela função
em si ou alguma subfunção existente se houver um binding (colagem) apropriado para isso
(veremos o tópico de binding mais à frente). Nós não podemos criar um objeto arguments
diretamente porque este só passa a existir na altura de execução da função. Este objeto arguments
cria um quase array com capacidade de 255 elementos.
Se se lembra da nossa introdução a funções, podemos introduzir argumentos através dos
parâmetros codificados dentro dos parênteses da função, que atuam como interface entre o mundo
exterior e o interior da função. No entanto, nós não temos que realmente declarar estes parâmetros
(como se faz entre parênteses) para poder passar informação (argumentos) à função. Tudo
depende do que for codificado dentro da função em si, isto é, depende do que o script pede para
inserir quando chamamos a função.
Considere o seguinte exemplo:
1- Declare a função x sem nenhum parâmetro mas que devolva o objeto arguments:

Figure 34 ficheiro em raw. icontemp.com/p3/34.txt

2- Chame a função x incluindo os seguintes valores como argumentos:

x("zebra","girafa"); // devolve-nos todos os argumentos que introduzimos: ["zebra",


"girafa"]
3- Chame a função com outros valores diferentes para solidificar o conceito:

x(1,2,3,4,5,6,7,8,9); // devolve [1, 2, 3, 4, 5, 6, 7, 8, 9]


Embora não tenhamos programado nenhum parâmetro formal para fazer o interface entre o mundo
externo e a função, esta função aceita toda a nossa data, e cria um objeto chamado arguments
com toda esta data. Isto significa que os parênteses da função são uma porta aberta a data in
mesmo que não exista uma ordem de entrada estipulada.
Embora o objeto arguments não seja bem um array completo, depois de ele ter sido criado
através dos valores que introduzimos ao chamar a função, poderemos copiar a data contida no
arguments para um novo array, utilizando por exemplo o método slice( ). Uma vez que tenhamos
um verdadeiro array com a data do objeto arguments, será então possível utilizar ferramentas de
Array para processar estes elementos de acordo com as nossas necessidades. (Se desejar, reveja
este método no capítulo 2.2.7 slice( ) ).

Como exemplo, vamos utilizar alguns dos conhecimentos já adquiridos para multiplicar todos os
argumentos inseridos, utilizando o método de Array reduce( ). Para isso teremos que copiar a
data do objeto arguments para um array utilizando slice(), e depois aplicar ao array o método
reduce() porque é uma das ferramentas disponíveis a arrays:
4- Escreva (ou copie) a seguinte função no seu editor (lines 1 – 8), e depois cole no console.
Chame a função x(2,3,4,5); como se mostra na linha 10:

Figure 35 ficheiro em raw. icontemp.com/p3/35.txt Trabalhando com o objeto arguments. Introdução a call().

· Se se sentir perdido nesta próxima explicação não se preocupe, leia até ao fim e volte
outra vez numa outra ocasião para reler uma vez mais, especialmente depois de ter acabado
a leitura do livro. Compreensão vem em camadas, pelo menos é como me aconteceu a mim
e continua a acontecer todos os dias.
· Na linha 1 a função x foi declarada sem parâmetros formais.
· Na linha 3 declaramos um variável com o nome aleatório de gts. A este variável
atribuímos os elementos contidos no objeto arguments. Mas antes disso, copiamos e
convertemos a data do arguments para um array através do método slice( ). Se não
tivéssemos convertido gts a um array e tentássemos o próximo método diretamente
utilizando arguments, teríamos tido este erro:
TypeError: Object #<Object> não tem método 'reduce'.
Para poder converter gts a um array tivemos que chamar o path completo até ao objeto
Array porque estamos a chamar um método externo, não um método do objeto Function.
Nota: como atalho poderíamos também ter programado da seguinte forma:
var gts = [ ].slice.call(arguments);

· A linha 3 introduz algo novo neste livro: .call( ). call() é um método do objeto Function.
Discutiremos este mecanismo um pouco à frente num outro tópico mas deixamos aqui uma
introdução. O método call() é uma maneira de chamar um objeto que não podemos chamar
diretamente porque JavaScript pode ficar confuso e chamar um outro objeto (nem sempre temos
um ambiente ideal). call() é utilizado quando o placeholer "this" pode ser ambíguo dando um
resultado que não era nossa intenção. Ao utilizar call(isto), fazemos o binding (colagem)
entre o que está à esquerda de call() e o objeto que se encontra dentro dos parênteses (isto).
É como dizer: “JavaScript, desta função onde me encontro inserido, chame o objeto
arguments”.
No nosso caso, o que significa .call(arguments) ?
“Senhor JavaScript, desta função onde me encontro inserido (eu o ‘call’), chame o
objeto arguments desta função”.
· Agora que já temos um array (gts, linha 3) podemos chamar métodos pertencentes ao type
Array.
· Na linha 5 chegamos finalmente à nossa intenção original, chamar o método reduce() para
multiplicar todos os elementos do array gts, devolvendo o resultado do cálculo através do
mecanismo return. Para fazer uma revisão deste método pode seguir o seguinte atalho: 2.4
Novos Métodos de Redução e Localização para Arrays em JavaScript.

· Linha 10 (não está no ficheiro em raw) chama a função com alguns argumentos como exemplo.
Estes argumentos são copiados pela função x e processados pelos scripts das linhas 3 -6
para nos dar um resultado de 120.
O método call() será explorado mais a fundo na secção 2.6 Propriedades e Métodos de Função.
5- Se necessita de mais um exemplo de cal( ) tente o próximo exercício.
Figure 36 ficheiro em raw. icontemp.com/p3/36.txt Propósito: compreendendo call().

· Na linha 1 declaramos o variável z com um valor type string.


· Nas linhas 3 a 6 criamos a função b onde declaramos um variável apanheZ a que foi
atribuído o valor do string z mas em formato de array. Esta conversão dos valores do string
z para array foi feita pelo método slice(). Para poder apontar o método slice a z tivemos
que utilizar o método call(z). Lembre-se que call() faz o redirecionamento de “this”, caso
contrário teríamos um resultado undefined porque JavaScript não entenderia o que
procurávamos. Call() permite-nos ser mais específicos.
· A linha 4 representa a nossa requizição do método de Array slice(). Para isso, como
apanheZ ainda não é um array e está dentro de outro objeto (objeto Função), temos que
codificar o path completo do método, que é Array.prototype.slice.
· Na linha 8 chamamos a função b() que atua em todo este mecanismo.
· Na linha 9 mostramos o resultado.
Regressando ao tema do objeto arguments numa função… Se podemos aplicar argumentos
sem parâmetros formais numa função, porque será então que continuamos a introduzir
parâmetros formais nos parênteses de uma nova função?
Uma das razões mais óbvias é que ao formalizar parâmetros numa função, estamos a estabelecer
uma sequência de eventos, o que nos permite ser mais específicos no script que metemos dentro
da função pois temos argumento1, argumento2, argumento3, etc.
Vamos agora fazer um teste criando uma função com parâmetros:
6- Declare uma função que aceita dois argumentos respectivamente através dos parâmetros x e y,
depois devolve-os para trás (supérfluo mas serve para ilustrar):
Figure 37 ficheiro em raw. icontemp.com/p3/37.txt Propósito: O papel de parâmetros numa função.

7- Tentemos os seguintes testes:

aba(7,11); // devolve "x= 7, y= 11". Data in, mesmo resultado para fora.
aba(7); // devolve "x= 7, y= undefined". x foi devolvido, y não existe mas não foi definido.
aba(7,11,9); // devolve "x= 7, y= 11". O último parâmetro não foi mostrado porque o
mecanismo return não tem maneira de o agarrar, mas existe.
8- Agora vamos mudar a função para que o terceiro e outros argumentos possam ser processados
embora só existam 2 parâmetros formais:

Figure 38 ficheiro em raw. icontemp.com/p3/38.txt Propósito: Como objeto arguments processa output, em comparação
com argumentos formais.

Mudando a linha 2 para return arguments como se mostra no ficheiro em raw e na imagem de
cima, podemos fazer um output de qualquer número de argumentos (até 255).
9- Faça um teste:

aba(7,11,9,45,57,89); // devolve [7, 11, 9, 45, 57, 89].


10- Em baixo temos outro exemplo que acede a um número ilimitado de argumentos através de
um for loop que tem o comprimento de arguments (length) como guia:
Figure 39 ficheiro em raw. icontemp.com/p3/39.txt Propósito: acedendo a um número ilimitado de argumentos usando um
for loop.

11- Chame a função com frutos (o ficheiro em raw já contem esta chamada na lihna 7):

f("banana","maçã","uva","pêssego");
// devolve banana é um fruto, maçã é um fruto, uva é um fruto, pêssego é um fruto.
Em sumário, o novo objeto de função arguments abre imensas portas para novas possibilidades.
Use parâmetros formais quando necessitar de uma estrutura onde os inputs têm que ser
consecutivos, e utilize o objeto arguments quando quiser ir para além do formato standard.
Os últimos dois exercícios podem ter sido um pouco avançados para alguns leitores mas por
favor não pare por aqui. Tudo fará mais sentido nos próximos tópicos. Dê uma oportunidade ao
tempo.
2.5.2 Funções dentro de Funções
Funções dentro de funções são conhecidas popularmente como funções aninhadas. Estas funções
internas têm acesso a toda a data da sua função mãe, o que lhes oferece um poder imenso. O
propósito deste tópico é o de desenvolver uma compreensão básica de algumas das características
de funções internas e externas.
2.5.3 Uma Introdução Gentil a Closures
1- Suponha que temos um array atribuído a um variável de nome ara:

var ara = [1,2,3,4,5];


2- E que depois atribuímos ara a ujo e depois, ujo a tony:

var ujo = ara;


var tony = ujo;
O que acabamos de fazer?
Nós acabamos de criar 3 variáveis que apontam para um array algures no heap, certo? Releia o
capítulo O Conceito de Memória se não se lembra do heap.
Vamos tirar a ‘prova dos nove’ só para ter a certeza:

3- ujo; // devolve [1,2,3,4,5].

4- tony; // devolve [1,2,3,4,5].

5- ara; // devolve [1,2,3,4,5].


6- Se agora decidirmos declarar o variável original ara como null:

ara = null;
7- O mesmo array continua a existir sob o nome de ujo e tony, certo?

tony; devolve [1,2,3,4,5]


O conceito é que, desde que o array continue a ter um variável apontando para ele, o array não
será demovido e atirado para o coletor de lixo do browser.
2.5.4 O princípio de closure
“Knowledge is closed under entailment”. Entailment significa “consequência lógica”. “o
conhecimento é fechado sob implicação estrita”. Se A compreende B e B compreende C, então A
compreende C. O que terá isto a ver com closures? Possivelmente nada. Mas se lhe alertou um
pouco já serviu o seu propósito! Vamos então falar de JavaScript.
No último array que apresentamos, quando o variável ara se tornou null, deveria ter tido a
consequência de JavaScript rotular o array como inválido, passando-o para o coletor de lixo.
Mas isso não aconteceu porque como se diz em JavaScript, os variáveis ujo e tony tinham
“closure” no array e por isso o array sobreviveu a perca de ara.
Em JavaScript, closure é geralmente referido a funções porque quando uma função de JavaScript
faz o return, ela deixa de existir e todos os seus elementos são apagados. Não que fisicamente a
função desapareça, mas aquela operação, ou o contexto da operação com valores correntes, é
posto no lixo.
Mas por outro lado, se existe uma função interna ainda em operação dentro da função que acaba
de fazer o seu return, os valores da função externa não serão apagados. JavaScript mantém a lista
de valores até não haver nenhuma ligação para com eles.
Antes de atacarmos alguns exemplos funcionais, vamos analisar uma imagem (em baixo) só para
ter a certeza de que compreendemos o princípio por detrás de closures porque não existe muita
literatura sobre este assunto, o que existe são muitas cópias da mesma explicação que nem sempre
é a mais ideal.
Figure 40

1- Vamos criar uma função simples para experimentar com closures:


Figure 41 ficheiro em raw. icontemp.com/p3/41.txt

2- Chame a função com o argumento de menino


Papagaio("ele"); // devolve "segura papagaio".
“ele” devolve o variável menino que contém o valor “segura papagaio”.
3- Chame a função com "ela" como argumento:
Papagaio("ela"); // devolve "segura papagaio".
“ela” aciona else, que aciona a função interna menina( ), que por sua vez devolve o valor do variável
menino, que é “segura papagaio”. Aqui está a magia: Quando menina( ) reage, papagaio( ) já fez o
seu return, mas o variável menino continua a existir (como exceção à regra) porque menina() tem
direitos de closure e o variável menino da função papagaio() não desaparece até a função interna
menina() fazer o seu próprio return.

Explicação:
A função papagaio() tem uma função interna, menina(), e dependendo do argumento que chama a
função, papagaio() devolve quem segura papagaio: menino da função externa, ou menina da função
interna.
Porém, como sabe, quando normalmente uma função faz o return, a sua execução atual é apagada
instantaneamente. Neste nosso caso isso não acontece quando a função devolve a opção “else”, que é
uma outra função e que usa valores contidos na função externa. No seu processo de apagar,
JavaScript decide manter os valores e esperar até a função interior fazer o seu próprio return. Só
depois é que ambos os contextos de execução são apagados para dar lugar a outros.
A pergunta é: Como é que isto funciona?

Isto é o que acontece:


1- JavaScript olha para a função externa na altura de chamada e faz um inventário:
Função externa, variável menino, “segura papagaio”
2- JavaScript olha também para a função interna e tira um inventário:
Função interna, mapeamento de variável menino (um presente grátis da função externa),
“segura papagaio”.
Depois não interessa o que acontece à função externa. Desde que a função interna ainda esteja
processando, JavaScript mantém um apontador para os variáveis que estão relacionados no seu
ambiente de execução tal como menino = “segura papagaio”. E tudo devido à lista de inventário.

Funções de JavaScript não são só pedaços de código que pode ser executado, elas são closures.
Closure, tal como dreamcatchers, simbolizam união. Um inventário tipo closure mantém não só o
código que uma função tem que processar, mas também o ambiente onde ele foi gerado. Uma
função interna tem acesso à sua função externa, e à função externa da sua função externa, e assim
por diante até chegar a topo onde o objeto Global existe.

Figure 42

Às vezes lemos na web como closures têm “free variables”. Isso está a se referir aos variáveis
declarados noutros sítios externos mas que pertencem ao elo de execução da função que faz closure.
Na ilustração de cima, func2 tem os seguintes free variables: A, B, e C. ( D, não é free ou seja,
grátis, porque pertence realmente à func2).
Em baixo temos uma outra maneira de ver esta ilustração baseado no conceito de duas pessoas
segurarem um cordel de balões. Aqui demonstra-se quem tem acesso aos balões na altura de
execução da function1 (quando a função é chamada):

Figure 43

Levando o conceito das ilustrações 42 e 43 como exemplo, podemos aproveitar para fazer dos
variáveis da função externa func2 uns variáveis mais privados, isto é, sem acesso direto da parte
exterior, a parte global. Isto é um técnica comum e merece ser vista. Nós podemos criar este
ambiente privado fazendo com que todo o output seja processado através da função interna, isto é, a
função interna serve de intermediário entre a função externa e o mundo exterior. Considere o exemplo
seguinte:
Figure 44 ficheiro em raw. icontemp.com/p3/44.txt

No exemplo a cima, conseguimos isolar do público a data da função bankCheck (o variável


clientBalance). Para isso criou-se uma função interna (bankTransaction) que atua como um
interface (intermediário) entre a função bankCheck e o mundo exterior. Este processo funciona
devido ao princípio de closure, que mantém um cordel no ambiente léxico (próximo tópico),
mesmo quando a função externa faz o seu return antes da função interna acabar o seu trabalho, o
que é o caso aqui. A função externa faz o seu output chamando a função interna, que por sua vez
devolve os resultado da transação; Só que o resultado desta transação encontra-se na função
externa que acaba de fazer o seu return. A data da função externa não se apaga durante os
microssegundos em que esta função faz o return da função de dentro e se fecha, porque a função
de dentro ainda aponta para a data da função de fora.
1- Para testar o script de cima copie o ficheiro raw e depois chame a função do seguinte modo:

bankCheck(2000);
// devolve "Perdão, não tem fundos suficientes!"
bankCheck(500);
// devolve "aqui está o seu dinheiro: 500"
Toda esta funcionalidade e valores encontram-se na função externa, mas são fornecidos ao
público pela função interna. Isto é um método de prevenção. Como não há acesso público direto
ao variável clienteBalance, ninguém poderá modificar este valor porque não é visto de fora
devido ao var que o faz um variável privado. A única maneira de acessar a este variável é
criando-se um método interno que o faça indiretamente, o que é o caso da função
bankTransaction. Veremos outros métodos semelhantes mais à frente.
2.5.5 Escopo Léxico
Léxico simplesmente dito significa “palavras que se referem a coisas” ou seja, um “menu de
elementos”. Em linguagens sem closures, a vida de variáveis acaba quando a execução do escopo
onde o variável está declarado, termina. Mas em linguagens com closures, tal como JavaScript, os
variáveis continuam a existir muito para além da vida de execução, desde que hajam closures
apontando para eles.
E porque o escopo em JavaScript é desenhado e determinado por funções, funções são deste modo
os ambientes que criam closures, que agem como pontes ou ligamentos entre variáveis e
argumentos referentes aos vários processos de execução.
Como se deve lembrar do tópico anterior, o fenômeno a que chamamos closure acontece quando
uma função interna aponta para data num escopo exterior (outra função acima desta ou mesmo o
ambiente global), o que evita com que JavaScript apague os valores de uma determinada execução
onde existe data que pode ser potencialmente necessária. Este método de persistência é
normalmente executado pelo mecanismo conhecido como coletor de lixo. O coletor de lixo é
implementado pelo navegador, o browser. O desenho deste mecanismo varia entre os vários
browsers e continua a ser aperfeiçoado com cada nova versão proprietária dos fabricantes de
navegadores.
A imagem em baixo ilustra uma coleção de funções aninhadas e os seus escopos iniciais
conhecidos como escopo léxico (ou estático) , o menu de ponto de arranque. Se reparar, e como
já sabemos do que lemos em outros tópicos, cada nível interno de função tem acesso a tudo que
que se encontra no seu exterior:
Figure 45

Na figura a cima, se chamarmos o return diretamente da function3 (a função mais interna) a partir
de function1 (a função mais externa), receberemos o seguinte erro: “ReferenceError: Function3
is not defined”, ‘function3 não está definida’. É que embora function3 veja function1, function1
não vê function3.
Para function1 ter acesso à function3, temos que fazer o return de 3 para 2, e finalmente de 2 to 1.
Só assim é que function3 poderá ser lida por function1. A razão disto é porque o output de uma
função interna só pode ser lido pela próxima função acima dela. O mesmo se aplica quando uma
função é externa, isto é, o seu output só pode ser lido por mecanismos que se encontrem no
ambiente global. Não confundir ler com utilizar. A utilização só acontece de dentro para fora,
não de fora para dentro.
No entanto e ao contrário (como foi dito na última linha anterior), Function3 tem acesso a todo o
seu ambiente externo que vai até ao objeto global Window. É uma estrada com uma só direção.
Funções apontam (veem) de dentro para fora.
Eis um conceito chave: Sempre que chamamos uma função para processar um argumento,
estamos a criar uma nova função com uma nova lista completa de variáveis disponíveis e
outros recursos relacionados. Quando esta função faz o seu return, esta lista é normalmente
apagada (a não ser que hajam closures relacionados).
Pesquisa de variáveis: Para cada escopo diferente, uma lista é gerada. Esta lista é um objeto que
se chama activation object. Um objecto de ativação é uma lista de todos os variáveis disponíveis
para a execução. Esta lista é guardada no heap em vez de no stack que serve apenas para data
temporária. Isto permite-lhe ter uma vida tão longa como necessário que seja.
Eis a sequência de cadeia que o interpretador atravessa ao procurar um variável:
Começa no escopo local que é o escopo mais interno de onde o script está atuando; se o variável
não se encontra no escopo interno, o interpretador sobe um nível e procura outra vez; depois sobe
outro nível e assim por diante até encontrar o que busca ou chegar ao topo do escopo global. O
primeiro variável que encontrar com o nome dado, é o variável que utilizará. Mesmo que hajam
outros variáveis com o mesmo nome acima deste escopo, o interpretador nunca lá chegará porque
pega no primeiro qualificador que encontra.
Todas as funções podem atualmente ser consideradas funções de closure porque todas as funções
têm acesso a variáveis externos a si mesmas. O que é um closure se não a combinação de uma
função e todos os variáveis disponíveis na totalidade de seu escopo? Tenha a certeza de fazer o
return de suas funções (closures) quando já não as necessitar, para que o coletor de lixo possa
limpar resíduos que preenchem a memória do sistema. De qualquer modo todas as funções fazem
um return automático ao acabarem, se não houver um return especificamente formulado. A única
pergunta é, quando é que JavaScript decide que uma função já não tem validade se não houver um
return no seu script? Programar é parte ciência parte arte e por isso existem sempre duvidas no
que diz respeito à melhor maneira de se codificar algo em referencia ao que rodeia o script em
questão. Quando mais cientes estamos de como tudo isto funciona, melhor chance temos de fazer
um trabalho mais perfeito.
Nota de lembrança: Num outro capítulo foi mencionado que quando a data de um variável é
atribuída ao parâmetro de uma função, esta data é copiada e por conseguinte, independente do
variável original em questão. Isto nada tem a ver com closures porque o ‘elo’ de closure para
com o variável não acontece via parâmetros de função. Funções têm closure em variáveis
externos porque estes estão automaticamente disponíveis às ordens da função. Existe um elo de
parentesco entre uma função e todos os variáveis do seu escopo total. E porque será isto
importante? Uma das razões é que uma função tem poderes para modificar o valor de um
variável global, ou de variáveis em funções onde esta função se encontra aninhada. Em suma,
existe diferença entre data que seja passada (do stack para o heap) a uma função como argumento
via seus parâmetros, e data apresentada a uma função através de uma chamada direta da função
para o variável externo. O primeiro exemplo é uma cópia da data, o segundo exemplo é
simplesmente um apontamento e quem pode apontar tem poderes para modificar.
1- Eis um exemplo para ilustrar. Teste os exercícios da imagem e leia os comentários para uma
explicação do que se passa. Apanhe o ficheiro em raw por debaixo da ilustração.
Figure 46 ficheiro completo em raw. icontemp.com/p3/46.txt Ver resto da imagem a baixo.
Figure 47

Nota:
Se o variável x dentro da função na linha 27 tivesse sido codificado como var x = x * num, o var
teria criado um novo variável interno totalmente alheio ao x externo e o x externo (global) nunca
teria sido afetado. Por outro lado também não teríamos o valor do x global pois ambos os
variáveis seriam independentes.
2.5.6 O objeto arguments versus funções internas
Uma função interna tem acesso aos variáveis e parâmetros de uma função externa a que esteja
aninhada e tem também acesso aos variáveis globais. No entanto, esta função interna não tem
acesso direto ao objeto arguments da função mãe. É certo que uma função interna tem acesso aos
argumentos estipulados nos parâmetros da função mãe (os que vêm dentro dos parênteses), mas
não ao objeto arguments em si. Isto faz sentido e a razão será mencionada em seguida, mas pense
um pouco no assunto antes de ler o que vem a seguir, para ver se lhe faz sentido também a si. Isto
é importante manter em mente porque pode-o confundir se não estiver ciente deste conceito.
Porque será que uma função interna não tem acesso ao objeto arguments da função mãe?
A razão é que a função interna vem com o seu próprio objeto arguments, mesmo quando não o
utilizamos diretamente. Então quando chamamos arguments qual deles estaremos nós a chamar, o
de dentro ou o de fora? Quando dizemos a uma função interna para chamar arguments ela devolve
os seus próprios arguments, mesmo que seja um objeto vazio.
Se desejar rever arguments, refira-se ao tópico 2.5.1 O objeto arguments.
Vamos então criar um script para provarmos que isto é verdade, e para ver como se pode chamar
o objeto argumentos externo adicionando uma pequena modificação à chamada.
1- Crie uma função chamada mx que devolve o seu arguments e teste-a chamando-a com (88) e
depois com (88,89,100) (ver linhas 5 e 6 da imagem).

Figure 48 ficheiro em raw. icontemp.com/p3/48.txt

Como se vê, tudo funciona bem porque não há obstáculos no script a cima.
2- Em seguida crie uma função my dentro da função mx que faz o return do objeto arguments.
Isto devolverá um objeto vazio porque a função interna não tem valores neste momento. Não se
esqueça de codificar uma chamada para a função interna a partir da função externa, caso
contrário não poderemos testar my. Veja a imagem em baixo e o ficheiro em raw para que isto
faça mais sentido.
Figure 49 ficheiro em raw. icontemp.com/p3/49.txt

3- Agora chame mx(88);


Devolve [ ] o que significa um array vazio. Lembre-se que arguments é um objeto parecido com
arrays mas só contem a propriedade length.
4- Chame mx(88, 89, 100);
Devolve [ ] outra vez. Em ambos os casos temos o resultado do objeto arguments da função my.
Se a nossa intenção é a de ler o objeto arguments da função externa mx, teremos que ser mais
específicos para conseguir tal proeza.
A próxima figura e ficheiro em raw mostram como devemos chamar o objeto arguments da função
exterior. Lembre-se, JavaScript gosta de especificidade.

Figure 50 ficheiro em raw. icontemp.com/p3/50.txt

5- Agora chame mx(88);


Devolve [88], o que é o resultado de dos arguments de mx.
6- Chame mx(88, 89, 100);
Devolve [88,89,100], o que é o resultado dos arguments de mx.
Ao fazer o binding (colagem) da função mx ao objeto arguments na chamada da função my,
conseguimos ultrapassar a barreira que JavaScript depara quando existem objetos ou variáveis de
nomes idênticos. Lembre-se que o interpretador de JavaScript utiliza sempre o primeiro símbolo
que encontrar com o nome que busca, a não ser que sejamos mais específicos no endereço de tal
objeto ou variável.
Nota: Em nenhum destes exemplos estamos a chamar diretamente o parâmetro num, apenas o
objeto arguments que apanha todos os valores de todos os parâmetros introduzidos na função. A
função interna my não teria problemas em apanhar o parâmetro num diretamente porque num é um
variável da função externa e my tem closure nesse variável. num não foi utilizado diretamente nos
nossos exemplos. Claro que se houvesse um outro num dentro da função interna, teríamos o
mesmo problema de especificidade.
Em resumo, para uma função interna aceder ao objeto arguments de uma função mãe, tem que ser
específico no endereço, utilizando o sintaxe de ponto para colar o objeto (a função externa) ao
alvo que pretendemos (o seu objeto arguments).
2.5.7 O variável “this”
É altura de explorar o símbolo this um pouco mais.
Num outro capítulo mencionamos que this pode ser imaginado como quando verbalmente
utilizamos o pronome “cujo” ou ‘este’. Nós podemos pensar no “this” como um variável genérico
que representa o nome do objeto chamando ou controlando o script onde ‘this’ existe. Vamos
experimentar um pouco mais com esta ideia do ‘this’:
1- Crie um variável global x com o valor de 345, e uma função y cuja função devolva a adição
de x a um parâmetro chamado m:

Figure 51 ficheiro em raw. icontemp.com/p3/52.txt

2- Chame a função passando-lhe o valor de 10:

y(10); // devolve 355 (tudo normal).


Vamos ver como poderemos aplicar this neste contexto. Eu sei que este script é um exagero mas
por favor siga em frente porque existe um ponto a fazer no final. Nós sabemos que x é um variável
global e todos os variáveis globais são propriedades do objeto Object que num browser se chama
window.
3- Para ilustrar, antes de aplicar ‘this’ vamos editar a função de maneira a que mostre o path
completo do variável x quando o chamamos dentro da função:

Figure 52 ficheiro em raw. icontemp.com/p3/53.txt

4- Chame a função y passando-lhe o valor de 11:

y(11); // devolve 356 ( porque 355 + m = 356, certo?)


Como nós podemos chamar o variável global x pelo seu nome curto ou pelo seu path completo
(window.x), sabemos de leituras anteriores que poderemos também substituir o objeto window
pelo pronome ‘this’, correto?

5- Vamos então modificar a última versão da função y para refletir ‘this’:

Figure 53 ficheiro em raw. icontemp.com/p3/54.txt

6- Chame a função y passando o valor de 20:

y(20); // devolve 365 (e funciona como tínhamos previsto)


7- Agora este próximo teste é um pouco mais complexo mas ilustra a razão de todo este trabalho.
Adicione um variável dentro da função y com o mesmo nome do variável global x. Sabemos
que quando existem dois nomes idênticos JavaScript apanha o primeiro que encontrar. Neste
caso, o tal primeiro seria este novo variável x que estamos codificando dentro da função,
certo? Bem, se aplicarmos o ‘this’ quando chamámos x, isso não acontecerá porque estamos a
ser específicos na designação de qual x desejamos processar. Vamos então ver:

Figure 54 ficheiro em raw. icontemp.com/p3/55.txt

8- Chame a função y passando-lhe o valor de 20:

y(20); // devolve 10365. Adicionou o x global + 20 + o x interno.


Como vemos, “this” é apenas um atalho ou um macro que chama o objeto pai, ou seja, o dono do
script. Na maioria dos casos, desde que mantenhamos este conceito em mente não correremos o
perigo de receber gato em vez de lebre. A razão para utilizar “this” em vez do nome do objeto em
si é para promover portabilidade. Permite-nos criar script genéricos que poderemos utilizar em
qualquer situação ou fazê-los mais dinâmicos, isto é, independentes de quem possa chamar o
script a qualquer momento do dia.
Sempre que uma propriedade (um variável) é referida sem um objeto como prefixo (ou sem um
‘this’ como prefixo), é assumido que tal objeto dono do script é primeiro que tudo um objeto
local, ou se o objeto local não existe, então o seu dono é o objeto global.
No que diz respeito ao nosso exemplo em referência ao “this”, mesmo que tivéssemos usado uma
outra função interna dentro de y, (veja o exemplo a baixo), o this.x continuaria a se referir ao x
global que é propriedade do objeto window:

Figure 55 ficheiro em raw. icontemp.com/p3/56.txt

NOTA: Este conceito é simples mas não é tão simples como parece porque o variável “this” só é
atribuído ao objeto que o chama quando o script entra em ação, isto é, na altura de execução.
Isto pode-se tornar um pouco mais complexo porque tudo dependerá da origem de tal chamada, ou
seja, em que contexto de execução está o script a ser chamado. Como podemos movimentar
funções aplicando-as em pontos e situações diferentes, um ‘this’ que normalmente se refere a
window pode vir a se referir a um outro objeto na altura de execução. Então a pergunta é: Quem é
que está chamando o script? Esse alguém é o objeto que será implementado no ‘this’ corrente.
Este processo é conhecido como “late binding”, colagem atrasada, isto é, não acontece na altura
do primeiro passe do interpretador. Esta atribuição acontece quando o interpretador passa uma
outra vez para executar o script. Até agora nos nossos exemplos tudo funcionou porque a nossa
função y está colada ao objeto window. Se formos a analisar o path completo da nossa chamada
de função , ela é a seguinte:

window.y(20); // y(20) é apenas um atalho, ou um macro.


Se, num contexto de execução diferente do que onde um script é estaticamente criado, nós
queremos chamar uma função dentro do objeto atual, a representação de “this’ pode-se tornar
ambígua e por isso temos que ter a certeza de que não estamos chamando o objeto errado por
acidente. Devido a esta complexidade, existem outros métodos de implementação onde se
substitui o ‘this’ por métodos tal como call(), bind () ou apply (), especialmente quando
implementamos funções tipo callback com quem já tivemos oportunidade de experimentar. Estes
métodos serão explorados brevemente mais a fundo e o conceito do “this” será expandido. Vamos
continuar em frente?
2.5.8 Funções como Construtores de Objetos
Nós podemos utilizar funções para construir os nossos próprios objetos que poderão depois servir
de protótipos para outros objetos. Se funções são coleções de scripts que se agrupam para
fornecer um certo resultado, objetos são coleções de funções que se agrupam para criar uma
determinada funcionalidade mais completa do que funções individuais, isto é, uma coleção de
dados e comportamento.

Um construtor de objetos é um agrupador de funcionalidade.


Para arquitetar um construtor de objetos começamos por criar uma função como outra qualquer.
No entanto é convenção nomear esta função com a primeira letra em maiúsculo. Isto é não é
obrigatório mas serve de lembrança visual para sabermos que esta função é um construtor e não
uma função normal. Assim quando vemos uma função onde o nome começa em maiúsculo,
reconhecemos imediatamente a ‘abelha mestre’. A que vai reproduzir outras abelhinhas.
De certo modo e para ilustrar, o construtor de objetos é como um bloco de formulários de onde
vamos sacando página a página formulários idênticos. Cada vez que preenchemos um novo
formulário declaramos ao JavaScript que queremos um new Formulário.

Figure 56

A estrutura básica de uma função construtora é a seguinte:


Figure 57 (ficheiro raw só na proxima imagem).

A opção no.2 a cima vem ao encontro da maneira como temos iniciado todas as nossas funções até
agora, embora já tivesses discutido a primeira opção. Pessoalmente prefiro a segunda opção para
funções normais mas neste caso prefiro seguir a primeira opção porque é a mais comum como
construtora, e também porque me relembra que estou a implementar um construtor. Seguirei em
frente com a primeira opção.
Note que a primeira opção não utiliza uma declaração de variável e por conseguinte o ponto e
vírgula final não é necessário.
Só para revisitar este tópico, mantenha também em mente que esta construção será hoisted como
função para o cimo do menu de escopo (veja Funções com Nome vs. Funções Anônimas ).
Aplicação é o nome aleatório da função que acabamos de criar. É também o nome do protopype
deste objeto.
Ao declaramos a função a cima, acabamos de criar um modelo ou padrão para este formulário a
que chamamos Aplicação. Como ainda não temos nada dentro deste construtor vamos continuar
com a construção do formulário modelo para que faça mais sentido. Neste momento o nosso
construtor de objetos é representa um bloco de páginas em branco com apenas o título, ou seja, um
contentor vazio.
1- Vamos reconstruir a nossa aplicação de emprego com uma das propriedades que queremos
obter do aplicante (a sua posição de emprego desejada). O aplicante representa o objeto a se
instanciar:

Figure 58 ficheiro em raw. icontemp.com/p3/58.txt


Nota: Se o seu computador não aceita acentos em palavras como Aplicação, etc, escreva as
palavras sem eles. O resultado será idêntico mas tenha a certeza de editar o script se o copia do
ficheiro em raw para condizer com a sua mudança.

Aqui criamos um formulário que permite a um aplicante preencher a posição de emprego


desejada. O nosso primeiro aplicante chega ao escritório e preenche um formulário arrancando-o
do bloco e entregando-o à recepcionista. Ao arrancar o formulário do bloco quero dizer que
instanciou uma nova aplicação criando um novo instance.
2- Agora para criar um novo instance ou seja uma nova aplicação com nome de tonyDeAraujo,
fazemo-lo da seguinte maneira:
var tonyDeAraujo = new Aplicação("programador");
O variável tonyDeAraujo foi gerado e uma nova Aplicação é agora atribuída a este variável. A
posição desejada foi passada para o novo objeto ou seja uma nova aplicação, através do
parâmetro posição.
3- faça o teste no console:

tonyDeAraujo; // devolve Aplicação {posição: "programador"}.


O símbolo new, cola o modelo Aplicação ao variável tonyDeAraujo. Com esta colagem,
tonyDeAraujo herda uma coleção de propriedades preconfiguradas do objeto. No entanto neste
caso a única propriedade disponível é “posição” que reflet a posição da aplicação de
tonyDeAraujo.
Como será que JavaScript reconhece qual posição é a de tonyDeAraujo? Reconhece-a através do
genérico variável this que liga tonyDearaujo ao valor inserido no parâmetro posição. “this”
representa o objeto com o nome declarado, isto é, o objeto que chama a função.

Será tonyDeAraujo um objeto?


4- Vamos ver o que é tonyDeAraujo:

typeof tonyDeAraujo; // devolve "object".


Recomeçando do princípio.
Agora que já temos mais experiência vamos recomeçar do princípio com este formulário e faze-lo
um pouco mais complexo.
1- Criemos a versão 2 deste construtor (não há nada como praticar não é?). Para além da posição como
parâmetro, vamos introduzir primeiroNome, ultimoNome e idade. Veja a figura a baixo:
Figure 59 ficheiro em raw. icontemp.com/p3/59.txt

Repare como o “this” cola cada propriedade vinda do input parâmetro ao dono do novo objeto
(tonyDeAraujo).
2- Copie o script para o seu console e volte a criar um novo instace da aplicação de
tonyDeAraujo. Repare que agora temos que dar mais informação para além da posição
desejada:
var tonyDeAraujo = new Aplicação("programador", "Tony", "deAraujo", 99);

3- Chame o aplicante:

tonyDeAraujo; // devolve
Aplicação {posição: "programador", primeiroNome: "Tony", ultimoNome: "deAraujo", idade:
99}.
4- Vamos introduzir outro novo aplicante criando um variável laurindoAlmeida a quem
atribuímos um new Aplicação:
var laurindoAlmeida = new Aplicação("guitarrista", "Laurindo", "Almeida", 99);

5- Chame o aplicante:

laurindoAlmeida; // devolve
Aplicação {posição: "guitarrista", primeiroNome: "Laurindo", ultimoNome: "Almeida", idade:
99}.
6- Não se esqueça de se introduzir a si próprio como aplicante só para praticar um pouco.
E agora vamos criar alguns métodos para os nossos aplicantes. Sabemos do que já cobrimos no
passado com prototypes, que se misturarmos os métodos com as propriedades do objeto
construtor, duplicaremos estes métodos cada vez que instanciámos uma réplica de objeto com o
símbolo new. Isto não é ideal por causa da eficiência de memória.
Nós queremos criar métodos que se apliquem a todos os instances sem haver duplicação, isto é,
queremos aceder a métodos por referência.
Em ordem para que estes métodos sejam apenas criados uma vez, temos que os incluir no menu
protótipo, isto é, adicioná-los à propriedade prototype. Nós já o fizemos antes mas iremos agora
revisitar o assunto.
Para adicionar nossos métodos à lista prototype não temos que os incluir dentro do construtor,
isso seria duplicação fatal. Podemos criar estes métodos fora do construtor. Mas se insistir
devido ao hábito de outras linguagens, não se preocupe porque mais tarde mostrarei também
maneiras de os incluir dentro do construtor em caso que assim o deseje.
Uma vez criados, estes métodos estarão sempre disponíveis à mercê de cada novo aplicante que
preencha uma nova Aplicação. É quase como dizer a um novo aplicante: “Grato pelo seu
registro. Como aplicante pode agora usufruir destes privilégios. Veja a nossa lista
prototípica”.
7- Vamos criar um método para ver como isto funciona. Criemos um método chamado
introdução que automaticamente mostrará uma mensagem cada vez que chamemos um aplicante
e sua introdução.
Aqui vão dois exemplos da nossa introdução:
Meu nome é Tony deAraujo. Tenho 99 anos de idade e estou a aplicar para a posição de programador.

Meu nome é Laurindo Almeida. Tenho 99 anos de idade e estou a aplicar para a posição de guitarrista.

8- Como faremos isto? Nós fazemo-lo criando o seguinte prototype (copie a ficheiro em raw
se assim o desejar):

Figure 60 ficheiro em raw. icontemp.com/p3/60.txt

Na linha 1, Aplicação.prototype.introdução significa adicionar ao menu de protótipos do objeto


Aplicação, um método chamado introdução. Lembre-se que hierarquicamente começamos na
esquerda com o nome do objeto padrão, depois o nome do que queremos ativar e finalmente o
novo nome que iremos dar a este método.
Na linha 2 definimos o método que obviamente é uma função. Aqui pense que estamos
adicionando mais um método a uma lista já existente para este tipo de modelo de objeto, e que
depois este novo método poderá ser partilhado por todos os filhos do objeto padrão cuja
funcionalidade herdam automaticamente.
9- Agora, no nosso exemplo, cada vez que queremos introduzir um aplicante, chamamos o
método introdução da seguinte forma:

tonyDeAraujo.introdução(); // devolve
Meu nome é Tony deAraujo. Tenho 99 anos de idade e estou a aplicar para a posição de
programador.

laurindoAlmeida.introdução(); // devolve
Meu nome é Laurindo Almeida. Tenho 99 anos de idade e estou a aplicar para a posição de
guitarrista.
10- Vamos adicionar mais um método a que chamaremos listeAplicante: Uma maneira de listar
uma aplicação completa do aplicante.

Figure 61 ficheiro em raw. icontemp.com/p3/61.txt

11- Chame o método a um dos aplicantes:

tonyDeAraujo.listeAplicante();
// devolve
Nome: Tony deAraujo
Idade: 99
Posição requerida: programador
Meu nome é Tony deAraujo. Tenho 99 anos de idade e estou a aplicar para a posição de programador.

Sabemos agora o poder e conveniência de “this” quando usado em funções. Nos exemplos de
cima nós criamos uma aplicação de emprego que poderá ser utilizada por um número infinito de
aplicantes. Espero que tenha tido a chance de praticar com o seu e outros nomes, ou adicionado
novas possibilidades. Se não o fez, por favor pratique um pouco. Só se aprende uma linguagem
praticando a mesma como se estivesse conversando com alguém. Vamos rever os pontos chave
deste tópico:
· Sabe como declarar um novo método no protótipo de um objeto existente?
nomeDoObjeto.prototype.nomeDoMetodo =
· Um método é composto de uma ou mais funções. Nós incluímos “this” em vez do nome do
novo objeto para que o script seja genérico e se aplique a todos os objetos.
· Embora possamos criar métodos protótipos dentro do construtor de objetos, escolhemos
não o fazer para evitar duplicação de métodos idênticos.
Vamos então seguir em frente, desbravando mais caminho e descobrindo mais magia no mundo
de JavaScript.
2.6 Propriedades e Métodos de Função
2.6.1 apply( ) e call( )
Muitas vezes desejamos chamar um objeto externo à execução atual de uma função e como o
“this” se refere ao objeto a quem a função pertence nesta altura de execução, não nos permitirá
chamar diretamente o objeto externo de nossa intenção. É nestas ocasiões que os métodos call( ) e
apply( ) se tornam bem úteis. Estes dois mecanismos de função permitem-nos pedir objetos
emprestados, o que nos facilita a vida pois não temos que os reprogramar porque já existem
algures no sistema. É quase como importar funcionalidade de uma fonte externa para o contexto
de execução atual.
Prelúdio: O primeiro parâmetro incluído em call( ) ou apply( ) funciona da mesma maneira em
ambos os métodos e é o que se utiliza mais frequentemente. Se por outro lado temos que incluir
vários parâmetros, então call( ) aceitará argumentos individuais que afinam a especificidade do
método, enquanto que apply( ) aceitará um array de argumentos que pode ser mais apropriado em
certas ocasiões.
Vamos começar por um exemplo simples para ilustrar como isto funciona.
Neste exemplo teremos dois objetos e um método externo que não pertence a nenhum destes dois
objetos. Os dois objetos são, ClientePorCorreio e ClienteLocal. O nosso exemplo de método é
uma mensagem que enviaremos a todos os clientes que tenham feito ordens por correio ou em
pessoa.
1- Vamos criar o objeto ClientePorCorreio:

Figure 62 ficheiro em raw. icontemp.com/p3/62.txt

2- Vamos criar o objeto ClienteLocal:

Figure 63 ficheiro em raw. icontemp.com/p3/63.txt

3- Crie uma pessoa diferente para cada tipo de cliente (isto é, instancie um novo objeto para
cada objeto previamente criado):

Figure 64 ficheiro em raw. icontemp.com/p3/64.txt

4- Crie um método independente de nome mensagem que envia uma nota de agradecimento ao
cliente:

Figure 65 ficheiro em raw. icontemp.com/p3/65.txt

Nós não podemos chamar diretamente de cada tipo de cliente o método mensagem porque o “this’
de cada cliente não aponta para a mensagem. Tal tentativa resultará no seguinte erro:

Figure 66

Para isso poderemos utilizar os métodos call( ) ou apply( ) para colar (bind) o “this” do método, ao
objeto que representa o nosso cliente.
Utilizando call( )
5- Chame o método mensagem para cada cliente, usando call( ):

Figure 67

Repare que call() foi mesmo ler os dados do objeto tony porque o nome que colocou tem o t em
maiúsculo, o que corresponde ao nome dentro o objeto tony.
Faça o mesmo para a Alice:

mensagem.call(alice); // devolve "Olá, Alice! Muito obrigado pela sua escolha dos nossos
produtos."
Utilizando apply( ):

6- Chame o método mensagem para cada cliente, usando apply( ):

mensagem.apply(tony); // "Olá, Tony! Muito obrigado pela sua escolha dos nossos produtos."
7- Faça o mesmo com Alice.
Como foi visto, quando utilizamos só um argumento, ambos os métodos call( ) e apply( )
funcionam identicamente. Os exemplos a cima indicados são suficientemente simples para se ter
uma ideia básica sobres estes métodos.
Ambos os métodos podem aceitar mais do que um argumento:
call( ) aceita argumentos individuais.
apply() aceita um array de argumentos.
NOTA: O próximo tópico será baseado nos scripts que acabamos de colocar no Console. É
preferivel seguir para o proximo tópico sem apagar o nosso último trabalho.
2.6.2 Adicionando mais argumentos a call( ) e a apply( )
Vamos adicionar mais funcionalidade ao nosso método mensagem introduzindo a classificação sexo
que representa masculino ou feminino e que permitirá tratar cada nome de senhor ou senhora quando
enviamos mensagem a clientes.
Vamos modificar a função mensagem para acomodar um segundo argumento adicionando o
parâmetro sexo. Dispense alguns segundos analizando o script e depois coloque-o no console:

Figure 68 ficheiro em raw. icontemp.com/p3/68.txt

8- Agora podemos chamar o método mensagem para cada cliente de uma maneira mais formal.
Ao escrever o script abaixo, repare na diferença entre este call() e a maneira como chamamos
call() no exemplo anterior. O primeiro parâmetro aponta para o objeto onde se irá aplicar o
método, e o segundo parâmetro aplica-se ao argumento sexo:

mensagem.call(alice, "Senhora"); // devolve


"Senhora Alice! Muito obrigado pela sua escolha dos nossos produtos."

mensagem.call(tony, "Senhor"); // devolve


"Senhor Tony! Muito obrigado pela sua escolha dos nossos produtos."
9- N`ão podemos testar o método apply( ) da mesma forma porque o segundo argumento tem que
ser um array. Mas no entanto poderemos imitar um array só para esta nossa experiência e para
ver como é a sintaxe:

mensagem.apply(tony,["Senhor"]); // devolve
"Senhor Tony! Muito obrigado pela sua escolha dos nossos produtos."

Sumário: O primeiro argumento aponta para o objeto que está sendo processado (tony ou alice). O
segundo e consecutivos argumentos têm como alvo as propriedades do método (mensagem). A
sequência dos argumentos tem que condizer com a sequência dos parâmetros da codificação no
método. Ao aplicarmos call() ou apply() estamos a fazer um ligamento temporário entre o método
(mensagem) e o objeto em alvo (tony ou alice), permitindo que “this” seja aplicado corretamente de
acordo com nossas intenções.

Exercício opcional.
E se quiséssemos simplificar a implementação do método mensagem para que uma pessoa não
técnica a pudesse processar?
Como exemplo poderíamos simplificar o processo criando uma função que faria a implementação
automaticamente. Isto é, em vez de se ter que escrever
mensagem.apply(tony,"Senhor");
poderíamos criar um formulário onde o nosso assistente entrava alguns dados e JavaScript faria o
resto:
Nota: Para que este exercício funcione deverá ainda ter no console um dos objetos (figura 62 ou 63),
e um dos clientes aplicado a esse objeto (figura 64). Deverá também ter o método da figura 68 para
ser chamado a partir do script abaixo indicado. Como exemplo utilize um dos clientes que ainda está
declarado (figura 64).

Figure 69 ficheiro em raw. icontemp.com/p3/69.txt

Tudo o que o nosso assistente teria que fazer agora era chama a função:
novaMensagem();
JavaScript perguntaria o nome: tony
Depois pedia para escrever m ou f para masculino ou feminino.
Em seguida o script decidiria o que colocar em cal( ) quando fizesse a chamada de n e s.
A linha 2 atribui a entrada do nome escolhido a quem enviaremos mensagem. prompt( ) é um método
que processa input do teclado. Este imput vem em forma de String e por vezes tem que ser
convertido para o type correcto que pretendemos.
Na linha 3, devido ao facto de que o nome viria em forma de string e por isso entre aspas, isso não
funcionaria porque JavaScript não iria atribuir o nome "tony" ao objeto tony. Devido a isso
atribuímos ao variável n o valor de uma propriedade de window com o mesmo nome que, como
sabemos existe um objeto chamado tony. Para isso utilizamos window[propriedade] que devolve o
nome de tony.
Na linha 5 escolhemos a opção de "senhor" ou "senhora" dependendo se a escolha foi m ou f.
Na linha 6 convertemos a entrada da linha 5 para letra minuscula para que tenhamos a certeza de que
o variável s seja em minúsculo na próxima etapa de processo (linha 7 a 12).
Linhas 7 a 12 servem para escolher o output que desejamos: "senhor " ou " senhora ".
E finalmente na linha 14 devolvemos o formato correto para chamar o método mensagem.
Se tentou este mini projeto mas não funcionou, verifique o sintaxe. Tenha também a certeza de que os
dados dos exercícios anteriores ainda estão no console. Caso contrário este script não servirá de
nada.
2.6.3 Mais prática com call( ) e apply( )
Devido à importância destes métodos, vamos praticar mais alguns exemplos para cimentar o conceito
destes dois mecanismos.
1- A função que se segue faz o output de um número de identificação baseado nos parâmetros
que lhe introduzimos (o nome da pessoa que substituirá ‘this’, e o número de identificação que
substituirá ‘id’). Como verá em seguida, podemos chamar este método aplicando-o a quem
desejarmos e sem restrições seja um objeto ou um string (nome), utilizando o auxilio do
método call( ):

Figure 70 ficheiro em raw. icontemp.com/p3/70.txt

2- Chame a função aplicando-a ao nome de uma pessoa como "Tony" em type string (com
aspas), e com identificação 34567:

print_id.call("Tony","34567");
// devolve "Tony tem a identificação No. 34567".
Com vimos a cima, “this” foi aplicado ao primeiro argumento do método call(), e o número de
identificação “id” foi aplicado ao segundo argumento.
Claro que o script é simples e poderíamos utiliza este método para algo muito mais complicado
não é?
3- Vamos adicionar um terceiro parâmetro para aceitar outro argumento, validade, que
representa o dia em que a identificação expira. Repare que toda a nossa data tem sido em type
string incluindo o número de identificação porque não existem cálculos a fazer e serve apenas
para mostrar no monitor do computador. Mais tarde visitaremos o objeto Date onde veremos
como utilizar datas em JavaScript:
Figure 71 ficheiro em raw. icontemp.com/p3/71.txt

4- Chame a função print_id2 e inclua o nome, número de id e dia em que o id expira:

print_id2.call("Tony","34567","Janeiro 5, 2016");
// devolve "Tony tem a identificação No. 34567 que expira em Janeiro 5, 2016 ".

Podemos deduzir desta experiência que call( ) aplica os argumentos na sequencia em que são
apresentados à função e temos que codificar o output de acordo com esta sequencia.
Os argumentos apresentados a call() podem ser objetos, strings ou até funções.
Adicione ao console esta função que chama um nome interno qualquer, só para ilustrar o conceito
de incluir uma função em call():

Figure 72 ficheiro em raw. icontemp.com/p3/72.txt

Agora chame o script da figura 70 ( o mais simples dos dois últimos script apresentados
anteriormente) mas em vez de “Tony” como nome, substitua com uma chamada para a função z:
print_id.call(z(),"34567");
// devolve "Tony de Araujo tem a identificação No. 34567"

Antes de passar para outro tópico vamos visualizar uma função call() sob um ponto de vista
diferente do que temos mencionado mas bastante importante.
Considere o seguinte script que será explicado a baixo:
Figure 73

· Linhas 1 a 3 representam a função x com um parâmetro, num.


· Linha 5 chama a função x com um argumento de 3, e o resultado é num + 1 = 4.
· Na linha 8 tentamos aplicar o número 3 utilizando a função call() mas como JavaScript
assumiu que 3 era o primeiro parâmetro de call(), isto é o “this”, não viu “nada” como
segundo parâmetro (o que seria aplicado ao num), e por isso devolveu o erro NaN, que
significa ‘Não é número’, isto é “o ‘nada’ não é um número).

· Na linha 11 chamamos a função x outra vez aplicando-lhe o método call() mas desta vez
preenchemos o primeiro parâmetro com o objeto global (window) a quem a função x
pertence. Deste modo, o número 3 foi positivamente aplicado ao parâmetro ‘num’ por ter
sido o segundo argumento apresentado no call().
Conclusão: Desta experiência vimos que x(3) é atualmente um atalho para a expressão
x.call(window, 3). Melhor ainda, relembrando as nossas primeiras lições e para ser mais específico,
x(3) é um atalho para a seguinte expressão mais completa:
window.x.call(window, 3);
Nos últimos exercícios experimentamos com funções para testar o método call( ) onde o objeto era
um string (“Tony”), uma função, e também o objeto window (o valor natural por defeito).
Em suma, as nossas experiências deste capítulo mostram que funções não têm uma consciência fixa
sobre quem é o “this” pretendido, porque o “this” é determinado na altura de chamada da função,
baseado em quem (ou o que) está chamando essa função. Esta flexibilidade dá grandes
possibilidades a JavaScript. Nós poderíamos ter chamado x deste modo: x.call("y", 3) para ter a
certeza de que 3 era aplicado ao segundo parâmetro da função. Neste caso especifico "y" serviria
apenas para preencher um vácuo e não teria valor algum para além de validar a sintaxe.
Revisitaremos este ponto outra vez mais à frente.

Qual método será melhor, call( ) ou apply( )?


Quando sabemos de antemão que argumentos iremos chamar, call( ) é mais apropriado.
Quando existe um número indeterminado de argumentos a chamar, apply( ) é mais apropriado porque
utiliza um array como segundo argumento e este array pode depois se adaptar ao ambiente.
Em ambos os casos, call( ) ou apply( ) permitem chamar métodos que nada têm a ver com o objeto
onde estes métodos serão implementados. Isto abre portas para possibilidades imensas.
Espero que esta introdução a call e apply tenha-o inspirado a investigar mais sobre o assunto.
Embaixo pode encontrar a referencia oficial da ECMASCRIPT 5 sobre este método :

15.3.4.4 Function.prototype.call (thisArg [ , arg1 [ , arg2, … ] ] ) ecma-international.org/ecma-


262/5.1/#sec-15.3.4.4

15.3.4.3 Function.prototype.apply (thisArg, argArray) ecma-international.org/ecma-262/5.1/#sec-


15.3.4.3

Abaixo poderá encontrar uma ilustração de sumário sobre this aplicado a call( ) em diferentes
cenários:
Figure 74 SUMÁRIO
2.7 O objeto Math
O objeto Math é um dos objetos mais úteis da biblioteca de JavaScript. Ele é predefinido e estático,
contendo vários métodos e constantes que podem ser chamados a qualquer altura. Estático neste caso
significa disponibilidade na sua forma original, pronto a ser chamado à ação.
A biblioteca de Math não é só conveniente mas também muito mais rápida do que criar outras
alternativas porque é programada em linguagem mais chegada à máquina.
Diz-se que o objeto Math de JavaScript é mais poderoso do que uma calculadora de bolso. No
entanto temos que ter em consideração a precisão da mesma porque é limitada a 16 dígitos, o que é
mais do que suficiente para a maioria do trabalho que poderá ser feito em JavaScript.
Vamos praticar com exemplos no nosso laboratório para nos familiarizarmos com os métodos mais
comuns desta biblioteca. Depois deixarei um atalho para uma lista de todos os métodos disponíveis,
para referência futura.
Recomece o seu console de JavaScript e experimente com os exemplos que serão explicados
individualmente.
2.7.1 Math.random( ), floor( ), ceil( ), round( )
Random significa ‘acaso’. Experimente o seguinte método no console. Repare que o objeto Math
vem em primeiro lugar, seguido do método pretendido e colados por um ponto:

Math.random( );
// Devolve um número ao acaso entre zero (inclusivamente) e 0,9999 (isto é, 1 exclusivamente). A
base deste número aleatório é o relógio do computador.
1- Escreva no console (se ainda não o fez) Math.random( ); Uma vez que obtenha um resultado,
pressione a tecla com a seta indicando para cima, a fim de duplicar o método outra vez. Tente
por várias vezes este método e observe os resultados.
Devido ao facto de que Math.random( ) nos dá um resultado abaixo de 1, se necessitarmos
números maiores que 1 teremos que adicionar um número base ao resultado do método, para que nos
dê um resultado acima de 1. Por exemplo, se adicionarmos 5, teremos números entre 5
(inclusivamente) e 6 (exclusivamente), tal como 5.0767:

Math.random()+ 5; // teste - o umas poucas de vezes. Conseguimos números como por exemplo
5.2907, etc.
E se quiséssemos um número aleatório entre 1 e 10? Multiplicaríamos o resultado de Math.random()
por 10:

Math.random()* 10 + 1; // um exemplo de output seria 7.784083819948137


A razão para adicionar 1 é porque queremos números a partir de 1 e não abaixo de 1. Se fosse entre
0 e 10 não necessitaríamos 1.
Isto traz-me para um tópico relacionado. Num dos meus testes recebi um resultado de
10.575064114760607. Isso é devido ao facto de que o multiplicador 10 faz com que o resultado
possa ser acima de 10 e menor do que 11. Poderemos remover a parte decimal e obter um resultado
mais limpo se adicionarmos um outro método à nossa receita de números aleatórios:
Math.floor( ) ou Math ceil( ). Floor significa chão e este método arredonda o número para o
número inteiro de baixo. Ceil é uma abreviação de ceiling, significa teto, este método arredonda
para o número inteiro de cima.
Como se combinam um Math.floor( ) com um Math.random( )?

Aninhamos o random dentro do floor, isto é, cercamos o mecanismo completo de Math.random()


dentro de Math.floor():

Math.floor(Math.random()*10+1); // arredonda para baixo, como por exemplo 1,7, 8, 4,10


etc

Math.ceil(Math.random()*10+1); // arredonda para cima, como por exemplo 2, 8, 9, 5,


11etc.
Humano contra máquina, um exemplo de script:
O próximo script é um pequeno jogo de adivinhas entre homem e máquina. Poderá ser a semente para
um jogo mais sofisticado se você quiser expandir o script. O propósito é apenas o de ilustrar uma
operação com Math.random e Math.floor.
Quando chamamos a função com um número entre 1 e 5, JavaScript compara-o com um outro número
introduzido aleatoriamente através do mecanismo que iremos contruir. Quem tiver um número maior
ganha o jogo, o ser humano ou o computador:

Figure 75 ficheiro em raw. icontemp.com/p3/75.txt

Depois de copiar o ficheiro em raw, chame o jogo uma variedade de vezes para testar os resultados.
Exemplo:

game(3); // devolve (por exemplo) “humano ganha com 3 versus 2”.


Ok, já chega de jogo, vamos seguir em frente?

Math.round( ).
Na verdade como Math.floor arredonda sempre para baixo e Math.ceil arredonda sempre para
cima, por vezes necessitamos de um terceiro método que arredonde para cima ou para baixo baseado
na parte decimal do número.

Em JavaScript existe o Math.round( ). Não confundir o termo round com random, pois embora
tenham o mesmo som, eles nada têm um a ver um com o outro.
Math.round( ) arredonda para cima se o valor for >= .5, ou para baixo se o valor for menor que
meio.
2.7.2 Math.max( ) e Math.min( )
O Math.max( ) que é abreviatura para máximo, devolve o número maior de uma lista de números
introduzidos nos parâmetros do método, como por exemplo:

Math.max(6,9,23,57,3); // devolve 57
Math.max(5,10); // devolve 10
Math.max(-5,-10); // devolve -5
Poderemos sacar o número maior de um array se utilizarmos a nossa ferramenta favorita apply():
Codifique o seguinte array x:

var x = [3,6,9,1];
Math.max.apply(null,x); // devolve 9. Null foi só para preencher o primeiro parâmetro para
que JavaScript conseguisse ler o segundo. Como estamos debaixo do objeto window, em vez de
(null, x), poderíamos ter escrito (window, x) ou mesmo (x,x). O resultado seria o mesmo. Em resumo,
é importante incluir um primeiro parâmetro de forma a que JavaScript consiga aplicar o segundo
parâmetro que é o que nos interessa neste caso. A condição é que o primeiro parâmetro terá que ser
algo válido para evitar um erro de sintaxe. Como por exemplo, y não funcionaria, mas "y" já
funcionaria porque o console faria de "y" um string válido. É importante reparar que isto é um truque
para enganar JavaScript e força-lo a ler o segundo parâmetro sem morrer pelo caminho.

O oposto de max é min:

Math.min(6,9,23,57,3); // devolve 3.
Math.min.apply(null,x); // devolve 1 ( do nosso array x anterior)
Estes métodos são muito úteis. Eles podem substituir scripts muito mais complexos.
Um exemplo seria o script a baixo indicado onde um loop faz uma iteração para conseguir o valor
maior do meuArray:
Figure 76 ficheiro em raw. icontemp.com/p3/76.txt

Nós podemos simplificar este script utilizando Math.max com o auxílio de apply().

O seguinte script substitui o loop de cima a partir das linhas 4 a 8), aplicando max () ao variavel
maior (ficheiro em raw - icontemp.com/p3/76b.txt):

maior = Math.max.apply(null,meuArray); // devolve 75.


2.7.3 Math.pow( ), Math.sqrt( ), Math.abs( )
Math.pow( base, exponente ) devolve um resultado baseado no exponente:

Math.pow(2,2);
// devolve 4. Porque (2 x 2 = 4).

Math.pow(2,3);
// devolve 8. Porque (2 x 2 x 2 = 8).
Math.sqrt(num) devolve a raíz do número apresentado como num:

Math.sqrt(9);
// devolve 3.
Math.abs(num) devolve o valor absoluto de um número:

Math.abs(-2);
// revolve 2.

Math.abs(null);
// devolve 0.
2.7.4 Constantes no Math, PI
Math.PI( ) devolve um constante de 3.14159 que é o quociente do valor de uma circunferência pelo
raio.
Um exemplo do uso de PI é quando calculamos a área de um circulo:

var area = Math.PI * raio * raio;


No exemplo de cima tudo o que necessitamos de saber é o valor do raio. O PI é dado
automaticamente por JavaScript. Se, var raio = 10; a área será calculada em 314.159
Reparar que o método PI é em maiúsculo e JavaScript considera um termo em maiúsculo diferente
do mesmo termo em minúsculo.
2.7.5 Referências úteis: Objeto Math
· Mozzila Developer Network.- A full list of Math’s constants and methods.
(developer.mozilla.org/en-US/docs/tag/Math).
· msdn Microsoft (pt).
(msdn.microsoft.com/pt-br/library/ie/b272f386%28v=vs.94%29.aspx).
· Funções matemáticas - mspc.eng.br (mspc.eng.br/info/jscriptMath.shtml).
· Sylvester – Uma coleção de métodos para vectors, matrix e geometria.
(sylvester.jcoglan.com).
· Accounting.js – Uma coleção de métodos para valores numéricos, dinheiro e formatos
relacionados. (jster.net/library/accounting-js).
· Numeral.js – concorrência, percentagens, tempo, e muito mais. (jster.net/library/numeral-
js).
· JSter – Um catálogo de bibliotecas de JavaScript. (jster.net/category/math-libraries).
O seguinte é uma tentativa de mostrar o que JavaScript trará de futuro sobre matemática:
ECMAScript Language Specification 6th Edition (ECMA-262).
(people.mozilla.org/~jorendorff/es6-draft.html#sec-math-object)
2.8 O objeto Date
Date( ); // Chamando este objeto só por si devolve-nos a data de hoje, como por exemplo:
"Wed Jan 22 2014 11:22:34 GMT-0500 (Eastern Standard Time)"
Repare que Date começa em letra maiúscula porque é um nome oficial de um objeto integrado no
JavaScript.
Podemos ligar-lhe outro método, como now():

Date.now( ); // devolve-nos em milissegundos a data em que foi executado.


Quando chamamos Date( ) devolve-nos um objeto completo. Este objeto pode ser chamado a
qualquer momento. No entanto e ao contrário do objeto Math que é estático e sempre disponível, o
objeto Date requer um instanciamento separado se desejarmos utilizar suas ferramentas disponíveis.
Então teremos que criar um novo objeto Date dando-lhe um nome diferente, e depois podemos
chamar esse novo nome com todas as ferramentas disponíveis de Date.

Para criar uma nova réplica de Date utilizamos o método new:

var minhaData = new Date; // tente no seu console.


Agora que criamos um novo instance de Date podemos usá-lo como interface para agarrar qualquer
método que exista sobre Date na biblioteca de JavaScript.
Nota importante: Estes métodos que se seguem refletem o tempo exato de quando minhaData foi
criado. minhaData fica congelado no tempo como estampa e todos estes métodos são como linhas de
informação que podemos revisitar se necessário.

minhaData.getDate( );
// devolve o dia do mês. Exemplo: 22, se hoje é o vigésimo segundo dia do mês.

minhaData.getDay( );
// devolve o dia da semana. 0 para Domingo e 6 para Sábado.
Veja este ficheiro em raw para um exemplo em como redirecionar estes números para dias de
semana por extenso. (icontemp.com/p3/DateSemana.txt)

minhaData.getMonth( );
// devolve zero para Janeiro e até 11 para Dezembro.
Se desejar praticar um pouco, poderá criar um script para o dia do mês baseado no exemplo anterior.

minhaData.getFullYear( );
// devolve o ano de criação deste objeto (Exemplo 2014).

minhaData.getHours( );
// devolve a hora (0 – 23).

minhaData.getMinutes( );
// devolve o minuto exato do momento em que este instance de Date foi criado (0 – 59).

minhaData.getSeconds( );
// devolve o segundo exato de quando minhaData foi criado 0 – 59.
Em baixo encontrará um exemplo de script sobre como utilizar Date baseado nos métodos que
acabamos de cobrir:

Figure 77 ficheiro em raw. icontemp.com/p3/77.txt

Lines 1 - 11 representa uma função com nome aleatório de escrevaData que por sua vez chama o
objeto Date representado por minhaData na linha 5.
Depois a função vai concatenando os vários métodos de Date para completar um frase no final onde
mês, dia e ano se mostram em console.log.
Para aplicar este mecanismo chamamos a função escrevaData() na linha 13.
2.8.1 Convertendo objeto Date para string
Existem vários métodos para converter o formato Date de objeto para formato string. Vamos ver alguns destes métodos para ter um
ideia como eles funcionam.:

Vamos criar um novo instance do objeto Date . Para isso escolhi o mesmo nome que utilizamos nos exemplos anteriores:

var minhaData = new Date;


Dependendo da sua localização no Globo, os seus resultados poderão ser diferentes dos meus. Eis os
meus resultados:

minhaData; // devolve Wed Jan 22 2014 14:07:03 GMT-0500 (Eastern Standard Time).

E agora que temos um instance de Date em minhaDate podemos testar alguns dos métodos de
conversão a string:

minhaData.toDateString(); // Devolve (no meu caso) "Wed Jan 22 2014"


Se comparar com o exemplo anterior verificará que este método agarrou a parte esquerda do
minhaData, deixando o resto para trás.

minhaData.toLocaleDateString(); // Devolve "1/22/2014"


Devolveu a mesma data como no exemplo anterior, mas num formato mais apropriado para a minha
zona do globo.

minhaData.toLocaleTimeString(); // Devolve "2:07:03 PM"


toLocaleTimeString devolve a porção da hora num formato local.

minhaData.toLocaleString(); // Devolve "1/22/2014 2:07:03 PM"


toLocaleString é a combinação dos últimos dois m;etodos, toLocaleDateString e
toLocaleTimeString.

minhaData.toUTCString(); // Devolve "Wed, 22 Jan 2014 19:07:03 GMT"


toUTCSString devolve um string de acordo com o universal time.

minhaData.toJSON(); // Devolve "2014-01-22T19:07:03.856Z"


toJSON devolve um string no formato de JSON.
2.8.2 Bibliotecas úteis de Date em JavaScript
Bibliotecas de Date em JavaScript permite-nos adicionar funcionalidade às nossas aplicações
manipulando, formatando e analisando datas.
Later.js – Facilita a definição de agendas complexas, cálculo de ocorrências futuras ou
passadas. Funciona em Node e no browser. (bunkat.github.io/later)
Countdown.js – Um simples API para descrever intervalos entre duas datas.
(countdownjs.org)
Moment.js – Esta biblioteca ajuda a converter uma data para vários formatos,
adicionar/subtrair datas, horas e métodos para visualizar a informação em várias línguas.
(momentjs.com).
Cubism.js – Uma biblioteca de visualização em JavaScript para HTML e SVG, para
mostrar séries de tempo em real-time.( square.github.io/cubism).
XDate – É um wrapper que adiciona funcionalidade ao objeto Date de JavaScript para
analise e manipulação de datas. (arshaw.com/xdate).
Visite o Mozilla Developer Network para uma lista de métodos do objeto Date.
(developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date).
2.9 Listas Associativas como Objects
Nós já tivemos oportunidade de ver como um objeto type array é variável que aponta para uma
lista ordenada (2.2 Array como Objects em JavaScript . Em JavaScript quando vimos uma lista
encapsulada em colchetes ( parênteses retos) sabemos que é um array, como por exemplo
var x = [77, 34, 23, "berimbau"];
Sabemos também que a ordem em arrays começa a contar de zero para cima. No nosso exemplo a
primeira localidade, o zero, contem o item 77. A quarta posição, que é posição ordenada no. 3
contem o elemento "berimbau", etc.
E devemo-nos lembrar também de ter visto algo parecido com o seguinte script:
var y = {"Frutas": "maçã", "Vegetais": "espinafre", "Grãos": "feijão"};
O script do exemplo de cima representa uma lista não ordenada, isto é, não ordenada
numericamente. Em JavaScript, listas não ordenadas não fazem parte da família Array. Este
objeto aponta para uma lista que representa os seus elementos com um símbolo, um gênero de par
chave – valor, daí a razão de não terem que ser ordenadas porque existe sempre um símbolo a
apontar para um sítio de memória onde reside um certo valor. Isto dá-lhes mais flexibilidade do
que simples arrays. Ambos têm o seu papel na programação.
Então em sumário nós utilizamos parênteses retos [ ] para declarar lista ordenadas numericamente,
e chaves { } para declarar listas com pares de chave-valor.
Em arrays nós buscamos um elemento desta forma: x[2]; // devolve 23 (do nosso primeiro
exemplo).
No segundo exemplo ( listas não ordenadas) podemos utilizar a sintaxe de ponto para chamar um
elemento através de sua chave: y.Frutas; // devolve "maçã", esteja este elemento no princípio ou
no fim da lista.
Podemos também chamar este gênero de lista através da sintaxe de colchetes tal e qual o fazemos
com arrays, como por exemplo::
y["Frutas"]; // devolve "maçã".
Tenha a certeza de incluir a chave dentro de aspas quando (e só quando) utiliza sintaxe de
colchetes (parênteses retos).
A sintaxe de colchetes [ ] deve ser mantida em mente como uma opção de sintaxe alternativa
porque se alguma vez utilizar uma palavra chave que não seja um string, como por exemplo um
número, não poderá ser codificado em sintaxe de ponto, como por exemplo y.12="foo";. A
maneira correta de codificar esta atribuição de 12 como chave, é:
y[12] = "foo";
Chame y: y;
// Devolve Object {12: "foo", Frutas: "maçã", Vegetais: "espinafre", Grãos: "feijão"}
E se chamarmos y 12:
y[12]; // devolve 12: "foo". (chaves alfabéticas requerem aspas, chaves numéricas funcionam com
aspas ou sem elas).

Lab Work:
1- Vamos cria um novo objeto ou seja, uma lista não ordenada.
Desta vez vamos adicionar cada item em linha separada o que torna tudo mais agrável à vista. Isto
é uma técnica comum para criar objetos mais complexos porque simplifica a compreensão do
código. (copie o ficheiro em raw se lhe é mais conveniente):

Figure 78 ficheiro em raw. icontemp.com/p3/78.txt

Esta maneira de criar um objeto é prática mas mantenha em mente que, se tiver intenções de
duplicar (instanciar) este objeto aplicando-lhe outro nome, será melhor criar uma função
construtora que servirá de protótipo como já tivemos oportunidade de ver quando programamos o
formulário de aplicação de emprego aqui:

2.5.8 Funções como Construtores de Objetos, lembra-se? Revisitaremos este assunto outra vez.
Existem muitas maneiras de se criarem objetos. Mencionar todos estes caminhos para Roma é
uma fonte desnecessária de confusão e atrasa o entendimento e a adquirição de experiência
prática. Não sobrecarregue sua mente, aqui o menos representa mais!
2- Se ainda não o fez, passe o script acima mencionado para o seu console. Vamos testar alguns
conceitos importantes antes de iniciarmos a construção de algo mais complicado.
3- Chame o objeto:

y; // devolve Object {Frutas: "maçã", Vegetais: "espinafre", Grãos: "feijão"}


3- Chame Frutas:

y.Frutas; // devolve "maçã"


Eis uma história bem boba mas que serve para ilustrar alguns conceitos: "maçã" é o meu fruto
favorito e gosto de ver seu nome na minha lista de JavaScript. Porém alguém pode mexer no meu
computador e trocar "maçã" por "limão" quando eu estiver ausente.
4- (tente o seguinte):

y.Frutas = "limão";
Então um dia um amigo meu veio-me visitar e eu com orgulho lhe mostrei a minha lista de frutas
para indicar que "maçã" é realmente o meu fruto predileto,
5- e então chamei meu fruto da lista...

y.Frutas; // E saiu “limão”!!!


Como eu não quis ficar a trás com a partida dos meus colegas resolvi pregar-lhes uma partida em
troco fazendo com que o valor "maçã" não tivesse maneira de ser trocado acidentalmente ou de
propósito. E como faríamos isso?
Como privatizar os elementos de um objeto.
Bem, você lembra-se que escopo é baseado em funções? (ver 2.5.5 Escopo Léxico ). Nós podemos
criar o objeto através de uma função como fizemos com a aplicação de emprego e incluir as
nossas propriedades, isto é seus variáveis, com o prefixo var, o que os torna privados em vez de
globais, certo?
6- Transforme os elementos do objeto y para elementos privados. Para isso modifique o variável
y para função e com os mesmo elementos. Veja o ficheiro em raw para sua conveniência:

Figure 79 ficheiro em raw. icontemp.com/p3/79.txt

Agora se chamarmos o objeto y receberemos uma visualização da imagem vista acima. As nossas
frutas favoritas, os vegetais e grãos estão todos lá, mas existe um problema, nós também não
temos acesso a cada elemento da nossa lista. Privatizamos as propriedades do nosso objeto mas
não criamos nada para as poder utilizar. Nós queremos encapsular os nossos objetos, mas não é
necessário nos sentirmos claustrofóbicos.
Agora que o nosso objeto tem seus valores encapsulados (lembre-se deste termo) necessitamos
de criar um método que nos permita ler os valores a partir do exterior.
Como podemos nós expor para o mundo de fora o valor de um variável que seja dentro de
uma função e de forma privada?

Nós expomos uma propriedade que tenha um escopo de var, criando uma função interna que
devolva a informação. Se se lembra, já tínhamos feito isso antes, certo? Ainda se lembra de
closures, e o papagaio ou os balões com dois cordéis? Funções internas têm acesso a funções
externas que sejam suas mães. Podemos utilizar esta técnica para expôs data da função mãe ao
mundo de fora. As funções internas podem agir como assistentes de balcão num banco, são os
intermediários entre o dinheiro no cofre (função mãe) e a pessoa que requisita seu dinheiro.
2.9.1 Métodos acessores
Analise a função interna na linha 6 a 8 da figura de baixo. Depois leia os comentários:

Figure 80 (Ficheiro em raw só no próximo exemplo)

Nas linhas 6 a 8 implementamos um método aleatoriamente chamado getFrutas, que nos devolve o
valor do elemento Frutas. Porém existem alguns problemas com esta implementação:
a) Devido ao facto de que estamos a utilizar y como um construtor de objetos, não podemos
chamar os seus métodos nesta sua forma corrente porque um construtor é apenas um template
ou seja, um formulário para objetos. Faz-me lembrar o objeto Date. Necessitamos de
instanciar um novo objeto para poder utilizar o seu método getFruta().
b) Uma vez instanciado um new object, necessitamos de ter a certeza de que o método getFruta
é aplicado ao this correto (ao este do novo objeto) e não a outro objeto. Então necessitamos de
adicionar o prefixo this como guardador do objeto que irá tomar posse quando duplicamos y
com outro nome. Algo que será assim: this.getfruta = .
Nota: Existem outras notas secundárias sobre a figura de cima que podem ser lidas no fim deste
tópico ou aqui: [1], [2].

8- Adicione um this handler ao getFruta:


Figure 81 ficheiro em raw. icontemp.com/p3/81.txt

No script acima resolvemos o problema mencionado em (b). Para resolver o problema de (a) temos
que instanciar um novo objeto.
9- Copie o script de cima para o seu console se ainda não o fez. Agora vamos instanciar um
novo objeto a partir de y a que chamamos meuY (ou outro nome qualquer):

var meuY = new y();


10- E finalmente podemos chamar getFruta do meuY:

meuY.getFruta(); // devolve "maçã".


Sumário:
Quando criamos um objeto, as suas propriedades são públicas, o que torna sua leitura e reescrita
fácil mas menos segura. Nós podemos proteger as propriedades de um objeto incluindo o objeto
dentro de uma função porque funções têm escopo local desde que suas propriedades sejam iniciadas
com o prefixo var. Uma vez que protejamos as propriedades de um objeto, a única maneira de as
poder tocar é criando uma função interna também conhecida como um método assessor. É
convencional chamar este método getAlgo porque get significa busca ou apanha, e este gênero de
métodos é também conhecido como getters ou seja “apanhadores’. O contrário de get seria set onde
aplicaríamos algo ao objeto em vez de sacar algo do objeto.

[1]
Notas: Outro ponto a considerar é o que embora não seja mandatório, o nome y deveria começar em
letra maiúscula porque este é um construtor e não um objeto instanciado. É apenas uma convenção
mas merece ser mantida. No entanto, não quero que esse problema abafe os outros dois problemas
que estou cobrindo neste momento que são a) e b).

[2]
Notas: Poderá estar pensando qual será a razão porque não inserimos um return na função mãe (y)
para resolver o nosso problema de apanhar ‘maçãs’, isto é return getFrutas a partir da função y. Sim
poderíamos ter feito isso se a razão desta função y fosse apenas a de produzir o valor de frutas, mas
não é. Como resolveremos um return de outros elementos? Qual dos elementos queremos devolver
quando chamamos a função? Esta função é um objeto de onde podemos tirar informação mais
específica baseado na sintaxe de objetos ou seja listas não ordenadas.
2.9.2 Métodos de mutação
E se desejarmos modificar uma das propriedades privadas que esteja dentro do nosso objeto?
Antes de ter protegido as propriedades do nosso objeto, nós podíamos modificar essas propriedades
atribuindo-lhe outros valores (lembra-se maçã e limão?). A sintaxe seria assim: objeto.propriedade
= "outro valor";

Agora que as nossas propriedades têm o prefixo var e estão dentro de uma função, nós não temos
acesso direto às mesmas a não ser indiretamente, isto é, utilizando um método intermediário.
11- Crie um segundo método que faz o set (aplica, modifica) da propriedade Frutas para um
valor diferente se alguma vez a quisermos modificar, isto é, criamos um método que nos
oferece tal opção:

Figure 82 ficheiro en raw. icontemp.com/p3/82.txt

O método setFruta aceita um argumento no seu parâmetro novaFruta (ou outro nome dado) e atribui à
propriedade Frutas um novo valor que lhe passemos.
12- Agora que modificamos o objeto construtor e devido ao facto de que esta mudança foi feita
internamente (hardwired) e não em protótipo externo (mais sobre isso no próximo tópico),
temos que reinstanciar o nosso objeto meuY para que seja modelado a este y em vez do y
anterior:

meuY = new y();


13- Em seguida vamos testar o método modificando o valor de Frutas de "maçã" para "banana":
meuY.setFruta("banana");
14- Chame a propriedade Frutas do meuY:

meuY.getFruta(); // devolve "banana".


Só para ter a certeza de que compreendemos o conceito, quando chamamos o objeto meuY ao
console, os únicos elementos que visíveis são os métodos publicos setFruta e getFruta. Tudo o
resto está escondido:

meuY; // devolve y {getFruta: function, setFruta: function}


Acabando o objeto:
Tente adicionar getters e setters para as outras duas propriedades, Vegetais e Grãos. Não se
esqueça de reiniciar o objeto meuY.
Quando acabar pode ver o meu resultado neste ficheiro em raw. icontemp.com/p3/82b.txt.
2.9.3 Revisão e prática: Criando uma aplicação para empréstimo

Figure 83

Neste código teste, vamos desenhar uma aplicação fictícia para empréstimo onde revisitaremos
alguns dos conceitos importantes deste capitulo.
· Nome do objeto: emprestimoAp.
· Propriedades de input da aplicação: aplicanteNome, salario, emprestimo.
· Propriedade privadas: bankFilial, aprovStatus.
· Métodos públicos: submeter.
a) Uma pessoa preencherá a aplicação para empréstimo declarando seu nome, salário e quantia
de empréstimo desejada. Esta aplicação é bem simples. Salário apenas reflete um número
inteiro para facilitar o nosso cálculo. Não são necessários outros detalhes.

b) Haverá um método (submeter) que calculará a relação entre o (salário) da pessoa e a quantia
de empréstimo desejada (emprestimo). Se o salário da pessoa for pelo menos o dobro do
empréstimo desejado, o empréstimo será aprovado instantaneamente com a seguinte mensagem:
"Parabéns! Seu empréstimo de " + emprestimo + " foi aprovado." Por outro lado e ao
mesmo tempo, o valor do variável aprovStatus mudará de "invalido" para "Aprovado".
Else, se o salário da pessoa é menor do que a qualificação automática, a pessoa receberá a
seguinte mensagem: "Obrigado por ter submetido uma aplicação de empréstimo. Sua
aplicação está sendo processada. Entraremos em contato consigo brevemente." Ao mesmo
tempo o valor do variável aprovStatus mudará de "invalido" para "Em processo".
Para já é tudo. Mais tarde melhoraremos o script para tocar em outros tópicos importantes.
Você pode seguir as minhas direções abaixo indicadas ou codificar seu próprio script se assim o
desejar, comparando depois com as minhas notas. Eu comentarei cada etapa conforme vamos
avançando no processo. Será talvez melhor seguir os meus passos e mais tarde refazer o script outra
vez à sua maneira. Você é que sabe!

Irei começar pela secção (b) criando um script independente do projeto global. A razão é para que
possa testar cada etapa conforme vou codificando. Em seguida criarei o objeto, e então copiarei (e
adaptarei) o método submeter da secção (b) para que faça parte do objeto. (Um ficheiro em raw está por
debaixo da imagem).
Iniciar (parte b).

Figure 84 ficheiro em raw. icontemp.com/p3/84.txt

1- Primeiro declaramos o variável aprovStatus e damos-lhe o valor de "invalido":

var aprovStatus = "invalido"; // invalido é apenas um string, não é nenhuma palavra chave. O
termo inválido ajuda-me a saber que este variável não foi ativado.
2- Agora criamos uma função para podermos testar o script. Mais tarde modificaremos a função
para que a possa integrar no resto da programação. Esta função a que chamarei para já de
submeter aceita dois argumentos através dos parâmetros salario e emprestimo. Estes
parâmetros serão mais tarde transferidos para o construtor do objeto emprestimoAp mas
agora servem de rampa de lançamento para o nosso teste:

var submeter = function(salario,emprestimo){};


3- No corpo da função necessitamos de uma expressão condicional que qualifique o aplicante,
resultando numa das duas opções anteriormente estipuladas na seção b.
Se o salário é pelo menos o dobro do emprestimo requerido, o emprestimo é aprovado
imediatamente e o aplicante recebe a primeira mensagem (como vimos anteriormente na secção
b). Ao mesmo tempo o valor do variável aprovStatus muda para "Aprovado". Caso contrário
o aplicante receberá a segunda mensagem e o valor de aprovStatus será então de "Em
revisão".

if(salario/emprestimo >= 2){ // aqui o quociente da divisão será comparada com 2.


aprovStatus = "Aprovado";
console.log(“veja o script ou copie a mensagem na secção b a cima”);
} else {
aprovStatus = "Em revisão";
console.log(“veja a segunda mensagem no script ou secção b”);
}
4- Copie o script para o console e chame a função submeter com os seguintes dados de salario
e emprestimo:

submeter(5000, 1000);
// devolve " Parabéns! Seu empréstimo de 1000 foi aprovado. ".

aprovStatus; // devolve "Aprovado".


Até agora tudo bem! Vamos testar o else com um salário que não qualifica:

submeter(1500,1000);
// devolve " Obrigado por ter submetido uma aplicação de empréstimo. Sua aplicação está sendo processada. Entraremos
em contato consigo brevemente. "

aprovStatus; // devolve "Em processo".


Boa, o nosso método está funcionando!
Agora é altura de criarmos um construtor de objetos para replicar a nossa aplicação
emprestimoApp.
Aqui vai um sumário do que iremos fazer em seguida:
Vamos desenhar o construtor emprestimoAp com os seguintes parâmetros de input: aplicanteNome,
salario, e emprestimo. Estes parâmetros trarão argumentos de cada novo objeto que for instanciado.
No corpo desta função iremos tirar partido do mecanismo this para que o objeto seja portátil, isto é,
instanciável. Aqui, dois variáveis privados serão declarados: bankFilial e aprovStatus. Depois, a
função submeter será copiada para o construtor mas os parâmetros da função serão eliminados
porque eles já existem como parâmetros do construtor em si. (o ficheiro em raw está na etapa no. 5). Vamos
continuar:
1- Declare o construtor de objetos:
function emprestimoAp(aplicanteNome,salario,emprestimo){
2- Em linhas separadas inclua as propriedades listadas nos parâmetros da função. Não se
esqueça de aplicar o this a cada um:

this.aplicanteNome = aplicanteNome;
this.salario = salario;
this.emprestimo = emprestimo;
3- Declare a propriedade privada bankFilial e atribua-lhe uma localidade:

var bankFilial = "New York"; // Nós utilizaremos isto mais tarde


4- Declare uma propriedade privada com nome de aprovStatus e atribua-lhe um valor inicial
de "invalido":

var aprovStatus = "invalido";


5- Finalmente copie o método submeter mas tenha a certeza de incluir o prefixo this, para que
este método seja genérico e possa ser aplicado a todas as instâncias. Não inclua var na
inicialização deste método:

this.submeter = function(){
Copie o resto do script desta função como o tínhamos anteriormente. Veja imagem e ficheiro em raw.

Figure 85 ficheiro em raw. icontemp.com/p3/85.txt

6- Teste: Coloque o script no console e veja se existe algum erro. Corrija os erros existentes e
depois tente a próxima etapa.
7- Instancie um objeto que qualifique para um empréstimo. O meu objeto chama-se tony com um
salário de 5000 e um pedido de empréstimo de 1000:

var tony = new emprestimoAp("Tony",5000,1000); // passou!!


8- Chame o objeto só para ter a certeza:

tony; // devolve emprestimoAp {aplicanteNome: "Tony", salario: 5000, emprestimo: 1000, submeter:function}.
9- O cliente tony preencheu a aplicação mas o pedido de empréstimo ainda não foi submetido.
Submeta esta aplicação:

tony.submeter(); // devolve " Parabéns! Seu empréstimo de 1000 foi aprovado. "
10- Chame a propriedade aprovStatus de tony:

tony.aprovStatus; // devolve undefined ("Houston, temos um problema aqui!")


A máquina tem sempre razão. Não podemos ler o aprovStatus porque esta propriedade foi declarada
como privada ( por var ou por this). A única maneira de podermos ler o valor desta propriedade é se
criarmos um método de leitura que sirva de intermediário, um getter, lembra-se?
11- Vamos modificar o nosso construtor de objetos para incluir um método a que chamaremos
getAprovStatus. Tente fazê-lo por si e depois compare os resultados aqui: ficheiro em raw .
icontemp.com/p3/85b.txt

12- Copie o novo objeto para o console e reinicie o objeto tony:

var tony = new emprestimoAp("Tony",5000,1000);


13- Tente chamar o método getAprovStatus de tony:

tony.getAprovStatus(); // devolve “invalido” (porquê?)


O resultado é invalido porque nós ainda não submetemos a aplicação deste novo objeto e por isso
recebemos o valor inicial que é ‘invalido’.
14- Vamos submeter a aplicação de tony:

tony.submeter();
// devolve " Parabéns! Seu empréstimo de 1000 foi aprovado. "
15- Verify se o status de aprovamento de tony foi realmente alterado:

tony.getAprovStatus(); // devolve "Aprovado".


Mais uma coisa….

Nós ainda não testamos o “else” do método submeter. Temos que o testar para ter a certeza de que
tudo funciona como deve de ser.
16- Crie uma outra aplicação para Maria como objeto maria. O seu salário é também de 5000
mas ela quer aplicar para um empréstimo de 3000 o que não será aprovado instantaneamente:
var maria = new emprestimoAp("Maria",5000,3000);
17- Submeta a sua aplicação:

maria.submeter();
// devolve " Obrigado por ter submetido uma aplicação de empréstimo. Sua aplicação está sendo processada. Entraremos em
contato consigo brevemente. "

18- Algum tempo se passou e agora Maria quer verificar o status do seu pedido:

maria.getAprovStatus(); // devolve " Em processo ".


Parabéns por ter mantido a disciplina de fazer este projeto até ao fim!!!
Vamos descascar um pouco mais esta cebola a que chamamos objetos.

E se quiséssemos submeter a aplicação, e ter uma resposta imediata ao instanciarmos um aplicante?


2.9.4 Como executar um método automaticamente
Isto é uma função:

function ( ) { } ;
Isto é uma função que se chama a si própria:

function ( ) { }( );
Os últimos parênteses à direita fazem com que a função se chame a si própria.
A função de cima como está escrita funcionará perfeitamente assim. Ela se chamará a si própria
quando o programa começa a executar. Porém, é comum embrulhar toda a função em parênteses
externos, para dar sinal visual a quem inspeciona o script, de que esta função irá se chamar a si
própria.
Como por exemplo assim:

(function( ){ })();
// devolve function ( ) { }
Voltando ao nosso projeto anterior o objeto emprestimoAp, poderíamos implementar esta técnica
no método submeter. Isso faria com que o método submeter fosse executado imediatamente após um
instanciamento da aplicação emprestimoAp, o que por sua vez modificaría automaticamente o
variável aprovStatus. para “aprovado” ou “em processo”.
A seguinte imagem parcial mostra onde os parênteses de chamada da função devem ser colocados:

Figure 86 ficheiro em raw (completo) icontemp.com/p3/86.txt

1- Copie o novo construtor de objetos para o console e reinstancie a aplicação de tony:


var tony = new emprestimoAp("Tony",5000,1000);
Deverá ver a mesnagem de submissão imediatamente após o instanciamento de um novo objeto,
isto é um preenchimento de uma nova aplicação. O método submeter passou a ser automático.
2- Verifique se o aprovStatus também foi alterado automaticamente:

tony.getAprovStatus(); // devolve "Aprovado".


Parabéns! Se você se sente um pouco confuso é porque acabou de cobrir um território de
conhecimento muito vasto. Desde que você tenha compreendido o que aconteceu, pode seguir para
a próxima etapa. Se por outro lado se sente ainda incompleto nesta matéria, talvez seja bom rever
este capitulo outra vez agora que tem uma visão mais vasta sobre o assunto. Repetição é o segredo
de aprender JavaScript.
2.9.5 Prototipagem de novos métodos
E se quiséssemos adicionar um novo método à nossa aplicação de empréstimos emprestimoAp?

Poderíamos abrir o objeto e atar um novo método ao seu mecanismo. Porém, muitas vezes esta não é
a maneira mais conveniente de o fazer. Por outro lado, métodos dentro de construtores não os mais
eficientes porque, se se lembra do que leu anteriormente, cada vez que instanciámos um novo objeto,
estamos a duplicar a data do construtor. Métodos são sempre idênticos, não é necessário duplicá-los.
Poupa-se muita memória ao programar uma só vez e depois apontar para essa programação quando
necessitamos de utilizar tal método.
Uma maneira mais eficiente é apontar para métodos já existentes a fim de os poder utilizar quando
necessário.
É uma boa prática adicionar métodos separadamente, colocando-os em elos prototípicos. No entanto,
se você prefere encapsular métodos em seus construtores em vez de os manter externos, existem
maneiras de os implementar dessa forma sem o problema de aumento de memória desnecessária.
Veremos algumas dessas implementações um pouco mais tarde, mas primeiro vamos introduzir (ou
reintroduzir) a maneira mais recomendável.
Pergunta: Baseado no que foi escrito acima sobre eficiência de memória, porque é que no nosso
projeto anterior, incluímos os métodos submeter e getAprovStatus dentro do objeto construtor
emprestimoAp, em vez de os colocar fora? Não é isso uma má prática? Sim, parece que é. A razão
porque assim o fizemos é porque estes dois métodos agem como getters para acessar data privada.
Não podemos utilizar métodos externos para ir buscar data privada a um objeto. Devemos sempre
tentar ser eficientes na nossa codificação. Neste momento, essa foi uma das maneiras mais corretas
de fazer tal implementação.
No entanto, na maioria dos casos, novos métodos serão implementados separadamente.
Vamos adicionar um novo método ao nosso emprestimoAp como prática e ilustração de conceitos.
A nossa administradora vem ter conosco um dia e pergunta se existe uma maneira de ela conseguir
um sumário sobre cada aplicante do programa emprestimoAp. Respondemos que ainda não existe
um método para isso, mas que nada é impossível desde que ela aprove implementações no programa.
A administradora aprova a mudança e nós regressamos ao nosso cubículo, arregaçamos as mangas e
lançámo-nos ao trabalho.
1- Crie um método de protótipo com nome de sumario que imprima o nome do aplicante e o
empréstimo pedido: (Ver ficheiro em raw na etapa No. 5).

emprestimoAp.prototype.sumario = function(){
2- No corpo da função codifique o seguinte:

console.log(this.aplicanteNome + " aplicou para um emprestimo de " + this.emprestimo);


3- E não se esqueça de fechar a função:
}
Vamos testar a implementação antes de mostrar à nossa administradora:
4- Copie para o console o emprestimoAp: ver (ficheiro em raw). icontemp.com/p3/86.txt
5- A seguir copie o método sumario: (ficheiro em raw). icontemp.com/p3/86b.txt
6- Instancie uma nova aplicação:
var tony = new emprestimoAp("Tony", 5000, 1000);
7- Teste este novo método:

tony.sumario(); // devolve " Tony aplicou para um emprestimo de 1000 ".


Agora chame a administradora para lhe dar a boas novas!
Já tinhamos coberto este tipo de protótipos anteriormente, quando criamos aquela aplicação de
emprego. Para uma revisão siga este atalho: 2.5.8 Funções como Construtores de Objetos
2.9.6 Objetos que herdam de outros objetos
Às vezes gostaríamos de implementar funcionalidade de um objeto já existente em um novo objeto.
Isto é uma ba técnica porque evita repetição. Esta atitude é conhecida por DRY (don’t repeat
yourself, ou Não Se Repita). JavaScript permite a herança de funcionalidade de objeto para objeto
desde que ambos os objetos coexistam no programa.
Há várias maneiras de implementar esta hereditariedade, cada um desses métodos com seus truques e
esquisitices peculiares (quirks). Irei explicar um dos que acredito ser uma boa prática. Vamos
demonstra-lo através de experimentação:
Mais um episódio do nosso banco fictício...
O administrador da filial de Los Angeles chama o programador em New York e congratula-o pelo
bom trabalho feito no emprestimoAp. Agora eles querem fazer uma nova implementação para a filial
de Los Angeles mas sob o nome da sua filial em vez do nome geral de New York. Além disso
querem também ter a programação individualizada porque pensam em modificar extensivamente a
aplicação de empréstimos nos próximos meses para se adaptar melhor à localidade californiana. A
filial de Los Angeles quer também um novo método que imprima Los Angeles na aplicação porque o
programa atual não permite mostrar a sua origem que é ‘New York’.
Depois de uma troca de ideias, decidimos reutilizar o objeto emprestimoAp em vez de recriar um
novo para Los Angeles porque nos é mais prático reutilizar as ferramentas já contidas no programa
atual, além de que se desejarmos modificar certas regras globais, apenas temos que modificar a
implementação original. Tudo o que temos a fazer é criar um novo objeto com apenas os seguintes
ingredientes:
Novo nome da aplicação: emprestimoAp2. (qualquer nome serve).
bankFilial é agora Los Angeles.

O método adicional irá ser chamado getBankFilial


Tudo o resto será herdado do objeto emprestimoAp. Para isso iremos utilizar uma técnica de herança
chamada object masquerading onde a herança acontece indiretamente.
Figure 87 (ficheiro em raw na próxima imagem).

1- Nova declaração de objeto (ficheiro em raw estará na próxima figura):


function emprestimoAp2(aplicanteNome,salario,emprestimo){
2- Atribua a herança de emprestimoAp para emprestimoAp2 através de um variável
temporário chamado x ( Escolhi o nome de x para ficar bem claro que este nome não tem
importância, no entanto em implementação real deverá ter um nome mais ilustrativo para
auxiliar outros programadores que analisam o script):

this.x = emprestimoAp; // aqui x herda tudo de emprestimoAp (a funcionalidade original) e já


veremos porquê.
3- A seguir, escolha que propriedades de emprestimoAp quer que sejam herdadas, se todas ou se
apenas algumas. x servirá como intermediário e já verá como em seguida. Os inputs da nova
aplicação serão aplicados a esta funcionalidade como se fossem aplicados à aplicação
original:
this.x(aplicanteNome, salario, emprestimo);
Agora, a herança do emprestimoAp para dentro do emprestimoAp2 já foi estabelecida através de x.
JavaScript anotou o que x herdou de emprestimoAp. Nesta altura emprestimoAp2 já não necessita de
x porque o trabalho está feito. Então a próxima etapa é a de apagar x, e porquê? Porque queremos o
nosso construtor emprestimoAp2 independente de emprestimoAp. Agora que já temos sua
funcionalidade queremos seguir o nosso caminho. O nosso tanque está cheio e agora queremos
desligar da fonte de nossa funcionalidade. Aqui introduzimos um novo termo: delete. O operador
delete retira uma propriedade de um objeto. Não retira variáveis ou funções locais. Ao cortar com x
não iremos cortar com toda a funcionalidade já estabelecida na lista de JavaScript, tal e qual o
papagaio de dois cordéis pois existe uma outra referência. Cortamos a corda umbilical de
emprestimoAp através de x.
4- Delete x:

delete this.x;
Agora podemos adicionar nova funcionalidade ao objeto. A razão para não o ter feito antes de
atribuir emprestimoAp a x foi para prevenir que a funcionalidade herdada apagasse a funcionalide
existente. Daí só implementar nova funcionalidade a baixo do delete x.
5- Adicione o nome da nova filial:

var bankFilial = "Los Ageles";


6- Adicione o método para mostrar ‘Los Angeles’:

this.getBankFilial = function() {
return bankFilial;
};
7- Feixe o objeto emprestimoAp2:

}
Em baixo poderá ver a imagem do novo objeto. Com vê ela é mínima porque muita da funcionalidade
é herdada do objeto original emprestimoAp.
Figure 88 ficheiro em raw. icontemp.com/p3/88.txt

Vamos testar a nossa herança de objetos:

8- Copie o emprestimoAp original para o console: (ficheiro em raw) icontemp.com/p3/86.txt


9- Copie o método protótipo sumario (para usarmos mais tarde). (ficheiro em raw)
icontemp.com/p3/86b.txt

10- Copie o novo objeto emprestimoAp2 da figura 88.


11- Crie um novo cliente para o a aplicação de Los Angeles emprestimoAp2 (pode usar o velho
tony outra vez):
var tony = new emprestimoAp2("Tony", 5000, 1000);
12- Teste o novo método getBankFilial:

tony.getBankFilial(); // devolve Los Angeles.


13- Teste os métodos herdados do objeto de New York:

tony.getAprovStatus(); // devolve “Aprovado”.


Agora vamos utilizar um novo operador: instanceof. Este operador é muito útil para inspecionar a
origem de objetos:

tony instanceof emprestimoAp2; //? devolve true.


tony instanceof emprestimoAp; // devolve false. (tony é de Los Angeles)
emprestimoAp2 instanceof emprestimoAp; // devolve false. (emprestimoAp2 não é um instance ou
duplicação de emprestimoAp embora tenha herdado sua funcionalidade e adicionado outra funcionalidade própria. emprestimoAp2 é
um contrutor tal e qual emprestimoAp.)

14- Se copiou o método externo da etapa No9 terá também disponível o método sumario. Vamos
ver se é verdade:

tony.sumario();
// devolve " TypeError: Object #<emprestimoAp2> has no method 'sumario'"
Ooops! A razão porque não temos acesso à lista de protótipos de emprestimoAp é porque o objeto
construtor emprestimoAp2 tem a sua própria lista de protótipos. Cada Objeto tem a sua lista a não ser
que sejam instanciados de outros objetos, isto é, automaticamente herdam a lista do objeto mãe.
Quando um objeto herda funcionalidade de outro objeto via masquerading temos que adicionar uma
linha de código que redirecione também a lista prototipa, isto é, se assim o desejamos.
Temos que ligar a lista prototipa de emprestimoAp a emprestimoAp2. Depois, objetos instanciados
de emprestimoAp2 funcionarão perfeitamente:
15- Copie o seguinte script para o console. A cadeia protótipa de emprestimAp ficará disponível
de imediato para novos aplicantes. No entanto, aplicantes existentes não terão este privilégio e
por isso teremos que reaplicar tony para que ele tire proveito dos métodos na cadeia
prototípica:

emprestimoAp2.prototype = new emprestimoAp();


16- Agora podemos instanciar um aplicante:

var tony = new emprestimoAp2("Tony",5000,1000);


17- Teste se sumario já funciona:

tony.sumario();
// devolve " Tony aplicou para um emprestimo de 1000 ".
“Eureka!!!”.

Pergunta: O que acontecerá se agora declaramos null o nosso emprestimoAp (original)? Lembra-se
do papagaio que estava sendo segurado pelo menino e pela menina? Se declaramos o velho
construtor como null, o novo construtor ainda mantém sua garra na funcionalidade que herdou. Mas o
mundo não é perfeito. Se emprestimoAp deixar de existir, o variável x não poderá ser implementado
em novos instanciamentos, isto é, não será possível preencher uma nova aplicação de empréstimo
porque o intermediário x não tem acesso a emprestimoAp.
Mas a ideia não é de destruir o primeiro objeto construtor, a ideia é apenas a de não repetir
funcionalidade que já exista no sistema.
Sumário: Usar a técnica Masquerade (que se poderá traduzir por “esconder o objeto existente a trás
de uma máscara”) é uma boa maneira de delegar funcionalidade para evitar repetição. Mas temos que
ter a certeza de redirecionar a cadeia de protótipos para poder utilizar métodos externos do objeto
construtor original, porque mascarading só faz a herança de propriedade e métodos internos.
O administrador da filial de Los Angeles ficou muito contente com o resultado e nós também!
Neste tópico nós visitamos o processo de se criarem objetos ou seja, listas não ordenadas. Tivemos
oportunidade de verificar como encapsulamento torna o código mais eficiente, e ponderamos sobre
maneiras de poupar memória através de heranças, assim como a vantagem de utilizar a cadeia de
protótipos. Estes conceitos são importantes no paradigma de JavaScript e todos eles bastante úteis.
Antes de abandonar este tópico, existe um outro assunto de grande importância sobre encapsulamento
que poderá ter interesse, especialmente se vem de outra linguagem de programação:
Como podemos incluir métodos dentro de um construtor sem criar duplicação e ineficiência? Até
agora vimos como incluir métodos de protótipo em scripts externos ao construtor, o que é uma
prática recomendável. No entanto é possível incluir estes métodos dentro do construtor e ao
mesmo tempo evitar duplicação. No próximo tópico iremos ver uma maneira de se conseguir tal
proeza. Até depois.
2.9.7 Como incluir métodos protótipos dentro de um construtor
Às vezes queremos manter propriedades e métodos juntos dentro do construtor por qualquer razão,
seja ela por conveniência, questões de preferência estética, ou porque assim estamos habituados de
outras linguagens. Não porque existe algo errado no que temos feito até agora, o que até é
recomendável; mas vou incluir uma outra opção aqui em caso que esteja interessado em a utilizar.
Vamos criar um objeto simples para ilustrar como incluir métodos dentro de um construtor de
maneira que não sobrecarregue a memória (a outra alternativa é programa-los no exterior do objeto,
colocando-os na lista da cadeia prototipa como fizemos até aqui).
Este objeto será chamado Musico e contem duas propriedades: nome e instrumento. Depois criamos
um método que nos mostre um sumario sobre o músico. Simples, certo?

1- Create Player and paste it into the console:

Figure 89 ficheiro em raw. icontemp.com/p3/89.txt

2- Instancie um Musico:

var jc = new Musico("Coltrane", "saxofone");


3- Chame jc:

jc; // devolve Musico {nome: "Coltrane", instrumento: "saxofone", sumario: function}.


4- Todos os elementos parecem estar no seu sítio. Vamos testar o método sumario:

jc.sumario(); // devolve "Coltrane toca saxofone".


O objeto funciona bem, certo? Então porque quereremos nós modificá-lo?
Se o objeto fosse único eu deixá-lo-ia ficar como está. Porém isto não é só um objeto isto é um
construtor, o que significa que alguém irá instanciar outros objetos a partir deste objeto.
Como iremos instanciar outros objetos fico preocupado com a gestão de memória.
Para podermos duplicar (instanciar) este objeto sem duplicar desnecessariamente seus métodos,
temos que criar os métodos fora do construtor numa cadeia prototipa, ou podemos criar seus métodos
dentro do construtor mas embrulhados dentro de um script que verifique se os métodos já foram
instanciados uma outra vez, para não ter que os instanciar uma segunda vez. Isto é, aos instanciar o
primeiro objeto, os métodos ficam instanciados na memória. Ao instanciar um segundo objeto e
objetos consecutivos, os métodos não terão que ser instanciados, se criamos um mecanismo
condicional que verifique se já existem métodos instanciados em memória. Um instance é tudo o que
precisamos.
Preâmbulo.

O operador typeof permite verificar o type do elemento a que o aplicamos, mesmo que a data seja
undefined. É este último que nós queremos encontrar.
Convencionalmente, quando utilizamos um caractere _ (underscore) como prefixo do nome de um
variável, exemplo _abc, significa que este variável é um variável interno ou especial. Isto claro
serve apenas para ilustrar a quem inspecione o script que este variável é fora de comum, porque
JavaScript não presta atenção a essas coisas.
Nós vamos implementar um passe mágico no nosso objeto. Vamos pedir a JavaScript que siga em
frente com o instanciamento de métodos só se tais métodos não existem já em memória. Conseguimos
esta proeza ao implicitamente fazer tal pergunta, isto é, perguntar a JavaScript se “variável x” é
undefined, siga em frente. Mas claro que x está indefinido porque é a primeira vez que mencionamos
tal variável. JavaScript nunca tinha ouvido falar nele até nós fazermos essa pergunta. Depois
codificamos os nossos métodos e finalmente atribuímos ao variável x o valor de true, tornando-o
defined. Ao tornar x defined, na próxima vez que instanciámos um objeto dentro do mesmo ambiente
de execução, a pergunta a fazer a JavaScript será false e então estes métodos não serão duplicados.
Tantas palavras para tão pouca coisa! Vamos ver como isto funciona em prática:
5- Adicione o seguinte condicional if mesmo antes da definição dos métodos do objeto:

if (typeof Musico._xyz === "undefined"){


Agora incluímos os nossos métodos e depois atribuímos a _xyz o valor de true, fechando a
condição if em seguida.
Veja a próxima imagem e o ficheiro em raw:
Figure 90 ficheiro em raw. icontemp.com/p3/90.txt

Na linha 5 incluímos uma condição onde se pede a JavaScript para seguir em frente se um tal
variável _xyz ainda não foi definido (ler preâmbulo a cima da imagem). Depois na linha 9
atribuímos a _xyz o valor de true para que na próxima vez o tal condicional seja definido e assim
JavaScript saltará o script de implementação de métodos. Repare que aqui estamos a inserir o
método sumario na lista prototipa, caso contrario não será visto por objetos instanciados depois do
primeiro instanciamento. O ‘this’ é então aplicado ao output em si (veja conosle.log) porque não
existe ‘this’ ligado ao nome do método como tinhamos feito na figura anterior.
Claro que as propriedades serão sempre diferentes e por isso não nos temos que preocupar sobre
elas. A nossa preocupação é apenas sobre os métodos pois esses serão sempre iguais e queremos
evitar duplicação desnecessária.
6- Teste o nosso instance de objeto outra vez:

var jc = new Musico("Coltrane", "saxofone");


jc; // devolve Musico {nome: "Coltrane", instrumento: "saxofone", sumario: function}.
7- Chame o método sumario:
jc.sumario(); // devolve Coltrane toca saxofone
Nós não podemos ver nenhuma diferença entre esta implementação e a original, mas se você vai
encapsular seus métodos dentro do construtor, esta é uma forma melhor de o fazer porque faz a
prevenção de duplicação de data desnecessária na memória. Repare que os métodos continuam a ser
inseridos na lista prototipa embora esteja desenhados dentro do objeto construtor em si.
8- Só para ter a certza vamos instanciar mais um Musico, o compositor Villa Lobos:
var villalobos = new Musico("Villa-Lobos", "guitarra");
9- Chame o método sumario:
villalobos.sumario(); // devolve Villa-Lobos toca guitarra
Se desejar praticar um pouco sugiro regressar ao tema 2.9.3 Revisão e prática: Criando uma aplicação para
empréstimo e refazer os métodos internos de maneira a que sejam instanciados apenas uma só vez por
contexto de execução. A técnica será a mesma que acabamos de apresentar.
Em Conclusão
Poderíamos continuar infinitamente nesta nossa viagem pelo mundo de JavaScript. O tema é tão
grande como ao Oceano Atlântico e nós estamos apenas molhando os pés nas ondas de uma praia.
Mas eu acredito que tivemos uma viagem longa e cobrimos bom território embora seja apenas o
principio de uma grande e interessante jornada.
Este é provavelmente o momento certo para rever alguns dos conceitos cobertos neste eBook. Não se
distraia procurando na Internet porque você se perderá e ficará confuso. Muito do que está escrito na
Internet é uma cópia de cópia de outra cópia, e como se diz em computação, lixo dentro lixo fora.
Não quer dizer com isto que não haja boa informação na Internet, ela existe, e muito boa mesmo. Eu
já aprendi muito com leituras na web e estou muito agradecido aos autores. Mas existe grande perigo
e eu já perdi milhares de horas lendo tópicos que no fim não me ajudaram em nada porque copiar não
é ensinar. Por vezes quem publica uma cópia na net não compreende bem o que está a escrever, e
isso torna-se frustrante para quem perde seu tempo lendo. Às vezes temos que contar uma história
para transferir o conhecimento ao leitor sem este ter que memorizar algo só porque não compreende a
ideia que lhe estão transmitindo. Continuo um grande fã de metáforas. Elas ensinam
exponencialmente.
Você andou um grande caminho e eu gostei imenso de o acompanhar porque é benéfico para os dois.
Tudo o que foi aqui dito deu-me que pensar pois quando se transfere a palavra para o escrito, existe
uma grande responsabilidade, e estou muito satisfeito que ambos tenhamos chegado ao final deste
projeto.
Aqui vai uma revisão mental do que foi coberto:
Conceitos de memória. Stack versus Heap.
O valor e propósito dos tipos de referência.
Tudo em JavaScript vem de objetos.
Somos agora bons amigos do Console de JavaScript.
Você brincou com funções e agora são bons amigos.
O intocável Object. Apontadores, primitivos, embrulho de primitivos em objetos.
O contexto de execução, escopo, variáveis privados, this, o papel de funções em
privacidade de informação.
Objetos nativos, objetos proprietários da plataforma onde JavaScript é implementado,
objetos do usuário.
Funções anônimas, closures, funções call e apply.
Strings como objetos, Arrays, novos métodos nativos de iteração.
Objeto arguments, funções aninhadas, escopo léxico.
Funções como construtores de objetos.
Bibliotecas de Math e Date constructs.
Listas não ordenadas, herança, encapsulamento.
Poderíamos ter continuado, mas de que serve um livro de 400 páginas se esse livro não é lido na sua
totalidade?
É melhor então parar e pensar um pouco no que foi coberto até agora porque se você sabe tudo isto,
então você sabe bastante, e tudo o resto é apenas um caminho descendo a montanha que acaba de
subir.
Com este conhecimento você pode ingressar por livros mais especializados sem se perder pelo
caminho, porque você acabou de ter adquirido conceitos bastante poderosos.
Este livro pode também ser utilizado como referência quando necessita de clarificar sua mente sobre
um método que tem que aplicar em algum script que não está funcionando bem.
Tenho planos de melhorar este livro lendo-o e ajustando a informação. Esta tradução para Português
é um grande melhoramento do original em Inglês que foi publicado em Outubro de 2013.
Foi uma grande honra e uma experiência muito interessante ter escrito este eBook.
A tradução para Português foi uma viagem ao mundo da minha língua nativa e uma oportunidade de
conviver com a minha cultura paterna.
Muito obrigado!
Tony de Araujo
Fevereiro de 2014
Mais uma coisa…
Obrigado pela leitura e pelo investimento de seu tempo fazendo estes exercícios. Se tirou algum
proveito deste trabalho eu ficaria agradecido se deixa-se uma boa palavra no meu perfil do Amazon.
O seu suporte faz realmente muita diferença na decisão de um leitor em ordenar ou não ordenar o
livro no meio de tantos outros concorrentes.
Se desejar deixar uma nota por favor dirija-se ao link onde encontrou o livro que ordenou, ou então
visite o meu perfil oficial do Amazon aqui: Amazon profile .
Grato pelo seu suporte!
Tony de Araujo
New Jersey, Fevereiro de 2014
APPENDIX
Resources
· (pt)Wikipedia. Sobre javaScript (wikipedia)

· Escopo Léxico. (Wikipedia)

· JavaScript References (Mozilla Developer Network)


· Creator of the JavaScript language (Brendan Eich)
· JavaScript Repository of Facts (Mozilla)
· A re-introduction to JavaScript (Mozzilla)
· ECMAScript® Language Specification (ECMA-262)
· ECMAScript 5 Compatibility table (github)
· Google Hosted JavaScript Libraries (Google)
· Google's open source JavaScript engine (V8)
· Memory leak patterns in JavaScript (IBM)
· List of Really Useful JavaScript Libraries (W3Avenue).
· JavaScript-related security problem (cross-site scripting)
· Alternate syntax for JavaScript (CoffeeScript)
· Increase accessibility with JavaScript (Webaim.org)
· checking if JavaScript source code compliancy (Wikipedia about)
· List of JavaScript Libraries (Wikipedia)
· JSON (Wikipedia about)
· jQuery (Wikipedia about)
· AWS SDK for JavaScript in the Browser(Amazon)
· Platform built on Chrome's JavaScript runtime for easily building fast, scalable network
applications (node.js)
· Review: Why JavaScript will become the dominant language (ReadWrite)
· Review: Mozilla edges closer to replacing Flash with JavaScript(zdnet)
· Review: 4 supercool JavaScript tools for data visualization(infoWorld)
· Review: The triumph of JavaScript(InfoWorld)
· Review: Adobe's new Snap.svg (I Programmer)
Errata e Contato
Este trabalho é em formato eBook. Qualquer modificação maior estará disponível no Amazon.
Normalmente o upgrade será dependente das regras do Amazon na sua localidade. De qualquer
modo, todos os scripts dos exercícios estão no servidor do autor e qualquer modificação será feita
de imediato sem voc6e dar por isso.
Meu email é tony@icontemp.com
Aprender a codificar é um processo cumulativo. Essa a razão porque não o sobrecarreguei com
scripts, só o suficiente para compreender os conceitos. Esse foi o propósito deste trabalho. O
outro propósito foi o de servir como referência e essa referência será modificada de acordo com
novas implementações.
Existe um outro livro já publicado que cobre JavaScript mais básico. A tradução em Português já
começou e deve ser publicado antes do meio do ano.

Pode-me encontrar como moderador no Codecademy, um sítio que visito todos os dias sem
exceção.
Meu profile no Amazon é: www.amazon.com/Tony-de-Araujo/e/B00D7V08WY/

Obrigado,
Tony de Araujo
--- New Jersey, USA
Copyright
Amazon, Google, Mozilla, ECMASCRIPT and all other famous names used in this book are of
their respective owners and being named only to illustrate the concepts written by the author.
All rights reserved © Tony de Araujo
"Be sure you put your feet in the right place, then stand firm". - Abraham Lincoln
Gentle Rain
Gentle rain, soothing me
Drops of liquid life
Wind and thunder
Wooing man and mice

Trees and bushes


Moving to and fro
Quiver, tremble, and rock
As lightning makes them glow

I thought I had forgotten


But it all came back again,
All my memories appeared
As drops of gentle rain

They were there, alive and well


In all their glory, their amazing grace
And my mother and my father
In a glorious embrace

It was so long ago


So many years before
And I wish I knew what I know
I would have lived it more!

Tony de Araujo

Você também pode gostar