1. Função
JavasScript como o próprio nome diz é uma linguagem de programação em script, sua finalidade é implementar novos recursos e dar dinâmismo a outras linguagens, principalmente as páginas de internet escritas em HTML. Por ser uma liguagem de script é simples, a função assume papel muito importante, até porque não há outro meio. Com funções, nós podemos tornar o código não-linear, mais organizado e mais fácil de entender.
A execução do JavaScript, quando interpretado pelo navegador, é imediata. O JavaScript é executado assim que uma tag <script> é encontrada em nosso documento.
No entanto, muitas vezes desejamos definir um comportamento para ser executado em outro momento, inclusive para que possa ser reaproveitado depois, é nesse cenário que entra o papel da função, que pode ser executada imediatamente ou após a ocorrência de um evento.
Como se verá mais a frente a função cria novo escopo, visibilidade ou acesso, chamado escopo local, onde as variáveis internas da função declaradas com a expressão var são acessadas ou visíveis apenas no interior de seu escopo local.
As tecnicas que serão aqui abordadas são antigas e coletadas de blogs, sites e referências oficiais, pois o objetivo aqui é formar uma opnião global sobre o assunto, porém, é abordado os aspéctos cruciais para o entendimento da linguagem.
Alguns assuntos são repetitivos, porque faz parte da aprendizagem e facilitação do entendimento, fixa melho assim as idéias.

1.1. Definindo ou Declaração uma Função
Uma função é um conjunto de declarações que executam uma tarefa específica, em Javascript, uma função é definida ou declarada pela expressão function, por um nome (opcional) e um par de parênteses ( ), que delimitam zero ou mais parâmetros separados por vírgula. Todas as declarações dentro de uma função estão dentro de um par de chaves { }, cada declaração dentro da função termina com um ponto é vírgula.
O Javascript tem duas maneiras de separar instruções. A primeira é através do caractere ponto e vírgula (;) e a segunda é através de uma quebra de linha. Por esta razão, as sentenças Javascript não necessitam acabar em ponto e vírgula a não ser que coloquemos duas instruções na mesma linha.
Literais de função são compostos de quatro partes: function, nome, () e {} que criam um
valor de função.
Obs:
a) se não houver a necessidade de uma função ser chamada por seu nome, não há necessidade de dar um nome a ela.
b) quando uma função é nomeada, esse nome é válido ao longo do escopo dentro do qual a função é declarada, nesse caso a função é hoit (içada).
c) existem dois tipos de funções: funções desenvolvidas pelo usuário e funções pré-definidas da linguagem.
d) a função possui dois escopos, o escopo local que é delimitado pelo par de chaves e o escopo dos argumentos que estão relacionados com a chamada da função.

Declaração de Função Regular
Há quatro sintaxes que podem ser usadas para declarar funções:
Com a expressão de função function, é hoit, pode ser chamada antes da sua declaração.
function funcName() {
var nomeVar1 =  valorVar1; //escopo local
nomeVar2 =  valorVar2; //escopo global
declaração 1;
...
return n;
};
A declaração return  é opcional, é utilizada caso a função retorne um valor ou para cancelar imediatamente a execução da função.

Atribuindo uma Função de Expressão a uma Variável/Propriedade
Apenas o nome da variável é hoit, não pode ser chamada antes da sua declaração.
var nomeVar1 = function() {
var nomeVar2 =  valorVar2; //escopo local
nomeVar3 =  valorVar3; //escopo global 
...
 };
Observe o ponto e vírgula no final da instrução (;) pois a atribução a uma variável termina com ele. Chama-se a função com o nome da variável, assim: nomeVar1().

As outras duas formas são utilizando o objeto window
window.nomeVar1 = function() {
var nomeVar2 =  valorVar2; //escopo local
nomeVar3 =  valorVar3; //escopo global
...
 };

e

window['nomeVar1'] = function() {
var nomeVar2 =  valorVar2; //escopo local
nomeVar3 =  valorVar3; //escopo global 
...
 };

Como JavaScript não é tipado, o tipo da variável ocorre dinâmicamente, não é necessário declarar o nome da função como variável, porém, é bom usar as mesmas regras de outras linguagens e usar a palavra reservada var.
Essa é a sintaxe que você precisa usar se você deseja atribuir uma função como uma propriedade de um objeto.

Revisão:
1.1.1. Variável do tipo var
Variáveis são endereços de memória nos quais podemos armazenar dados ou informações.
No caso da palavra-chave var, além da variável ser içada (hoisting) ela é automaticamente inicializada com o valor undefined, caso não seja atribuído nenhum outro valor.
Existem duas formas de sintaxe para declarar ou dar nome a uma variável do tipo var em JavaScript:
Declaração:
var declara uma variável ou mais variáveis separadas por vírgula, opcionalmente, inicializando-a com um valor.
var nomeVar1, nomeVar2, nomeVar3;
ou na forma de atributo:
var nomeVar = valorVar;
Notas:
- O sinal de igual significa atribuição de valor
, isto serve para qualquer linguagem de programação.
- JavaScript é case-sensitive e usa o conjunto de caracteres Unicode, var Nome é diferente de var nome.
- No JavaScript, instruções são chamadas de declaração e são separadas por um ponto e vírgula.
- Utilizar a instrução var antes do nome da variável porque facilita na leitura do código.

1.1.2. Variável do tipo let
Declaração (nomeação):
let declara uma variável local de escopo do bloco que a contém, opcionalmente, inicializando-a com um valor.
let nomeLet;
Através da palavra-chave let podemos declarar variáveis com escopo de bloco,{}, só é visível dentro do bloco, tal mudança surgiu com o ECMAScript 6.
Exemplo:
<!DOCTYPE HTML>
<html>
<body>
<script>
function exibeMensagem() {
var x=10;
    if(x>2) {
      var escopoFuncao = "escopo da função";
      let escopoBloco = "escopo do bloco";
    }
      console.log(escopoFuncao);
// escopo da função
      console.log(escopoBloco);
// escopoBloco is not defined (linha:12)
}
    console.log(exibeMensagem());
</script>
</body>
</html>
Saída Console:
escopo da função
escopoBloco is not defined (linha:13)

Obs: Devido ao hoisting, variáveis declaradas com a palavra-chave var podem ser utilizadas mesmo antes de sua declaração, no exercício em questão possui o escopo da função.
As variáveis criadas com let só podem ser utilizadas após sua declaração e não é acessível fora do bloco.

1.1.3. Variável do tipo const
Guarda um valor que não muda. Constantes devem ser inicializadas obrigatoriamente no momento de sua declaração. const declara uma constante apenas de leitura.
Declaração:
const nomeConst = valorConst;
Exemplos:
<!DOCTYPE HTML>
<html>
<body>
<script>
const peso = 20; // constante válida
void function(){
  const mensagem = 'peso máximo';
  console.log(mensagem); // peso máximo
  mensagem = 'Nova mensagem'; //Assignment to constant variable. (linha:9)
}();
</script>
</body>
</html>
Saída console:
peso máximo
Uncaught TypeError: Assignment to constant variable. (linha:9)

O código acima gera um Uncaught TypeError: Assignment to constant variable, pois o comportamento fundamental de uma constante é que uma vez atribuído um valor a ela, este não pode ser alterado.
catch (kætʆ): v. 1. pegar, agarrar (uma bola, um objeto), 2. pegar (um bandido, um fugitivo, etc.), You can't catch me! Você não me pega!
3, pegar, flagrar, His mom caught him smoking in the yard. A mãe o pegou fumando no quintal.
caught (kɔt): pegou, pego.
assignment (əˈsaɪnmənt): s. 1. dever de casa, trabalho, 2. missão, 3. atribuição.

Obs:
A constante Infinity é um membro do objeto Global. A propriedade global Infinity é um valor numérico que representa infinito. Pela especificação ECMAScript 5, Infinity é somente leitura (implementado no JavaScript 1.8.5/Firefox 4).
Exemplo:
var arr = [345435, 1, 744, 78899, 3e500];
let menor = Infinity;
for (let nr of arr) {
  if (nr < menor) menor = nr;
}
console.log(menor);

1.1.4. Tipo
Os tipos de dados primários ou primitivos são: a) Cadeia de caracteres, b) Número e c) Booleano. Os tipos compostos são atribuídos as variáveis por uma expressão ou por referência, ou seja, por objetos ou matrizes.
1.1.4.1. Seis tipos de dados chamados primitivos:
- Boolean. true e false.
- null. Uma palavra-chave que indica valor nulo. Devido JavaScript ser case-sensitive, null não é o mesmo que Null, NULL, ou ainda outra variação.
- undefined. Uma propriedade superior cujo valor é indefinido.
- Number. 42 ou 3.14159.
- String. "Howdy"
- Symbol (novo em ECMAScript 6). Um tipo de dado cuja as instâncias são únicas e imutáveis.
1.1.4.2. Object
Você pode pensar em objetos como recipientes para os valores, e funções como métodos que suas aplicações podem executar.
1.1.5. Valores: o Javascript trabalha com os seguintes tipos de valores:
a) Números ( 7, 3.14, etc... ), b) Booleanos ( true ou false ), c) Texto ( "palavra" ), d) null e e) undefined. As variáveis declaradas sem valor têm o seu valor undefined, ou seja, indefinido.
1.1.6. Inicialização ou Atribuição
Significa atribuir valor a variável, utilizar-se para isso o sinal igual: var nomeVar = valorVar;
1.1.7. Expressão:  é um fragmento de código JavaScript que pode ser interpretado para produção de um valor. Pode-se dizer também que expressão é um conjunto de constantes, variáveis e operadores que, avaliados, resultam em um único valor (número, string ou booleano).
Expressões básicas: true, false, nomeVar, etc .
Expressão de atribuição: var nomeVar = 1, var arrayVazio = new Array, var meuObjeto = {}, etc.
Expressão de definição de função:
function nomeada() {
...
}
Expressões Matemáticas ou Aritméticas: +, -, /, *, %
Expressões Relacionais: ==, ===, !=, !==, <, >, <=, >=
Expressões Lógicas: &&, ||, !
Expressões de Atribuição: +=, -=, *=, /=, %=
1.1.8. Variáveis, ID & Classes
Todas as variáveis JavaScript devem ser escritas apenas com minúsculas ou camelCase. A única exceção para este caso é se estiver criando Constructor Functions, as quais começam com maiúsculas por tradição. Todo id e declarações class em CSS, devem ser escritas usando apenas minúsculas. Não use traços, nem sublinhados
O camelCase possui duas variações, o lowerCamelCase e o UpperCamelCase. Essas variações são aplicadas em contextos diferentes, veja abaixo.
O lowerCamelCase é o padrão no qual inicia-se com a primeira letra minúscula e as iniciais das palavras subsequentes são maiúsculas. É usado para dar nome à variáveis e métodos. Exemplo: inGet, outSet, etc.
Uma segunda variação do camelCase é a nomenclatura UpperCamelCase, onde a primeira letra de cada palavra é maiúscula, inclusive da primeira,  é usado com o para dar nomes à classes. Exemplo:
function Person() {
  this.nacionalidade = "brasileiro";
  this.setNome = function(valor){
    return this.nome = valor;
  }
}

1.2. Função com Parâmetro
A forma mais didática que considero é a distinção entre parâmetro e argumento.
Parâmetro é uma variável sem tipo definido que a função utiliza para fazer  uma ação, não confundir com argumento que é o valor passado para o parâmetro na chamada da função.
Sintaxe:
x é parâmetro.
function incremento(x) {
   return x +1;
}
20 é argumento de x na chamada da função.
incremento(20)

Passagem de argumento por valor quer dizer que o parâmetro receberá um argumento do tipo primitivo, isso quer dizer que o parâmetro recebe o argumento na chamada da função mesmo que o parâmetro tenha um valor diferente dentro do parentesis da função.
Exemplo:
Perceba que o agumento muda o valor do parâmetro padrão atribuído no construtor da função, mas não muda no corpo da função.
<html>
<head>
<title>Factorial</title>
<script language="JavaScript">
  function soma (x=20, y) {
    var sum;
    sum = x+y;
    return (sum);
  }
  var total = soma(5,4);
  document.write("Resultado da soma: ", total);
</script>
</head>
<body>
</body>
</html>

<html>
<head>
<title>Factorial</title>
<script language="JavaScript">
  function soma (x, y) {
    x=10;
    var sum;
    sum = x+y;
    return (sum);
  }
  var total= soma(5,4);
  document.write("Resultado da soma: ", total);
</script>
</head>
<body>
</body>
</html>
Resultado:
Resultado da soma: 9
Resultado:
Resultado da soma: 14

Explicação: 
A função está definida no topo do script, contudo, só é chamada no final, no corpo principal do código do programa. A chamada à função (total=soma(5,4)) é feita passando como argumentos os valores "5" e "4", que são colocados nas variáveis "x" e "y", internas à função soma(x,y), x e y não são conhecidas fora do corpo da função, como parâmetros fixos que são. Igualmente interna à função soma() é a variável "sum", cujo valor é por fim devolvido para o exterior da função, utilizando para tal a instrução return(sum).
O valor devolvido é colocado na variável "total", que foi utilizada na expressão de chamada da função.

1.3. Reutilização de Código
A reutilização de código pode ser demonstrada com o exemplo seguinte. Nele é utilizada uma função "fat()", que simplesmente calcula o fatorial de um número. Neste exemplo pretende-se calcular todos os fatoriais entre 1 e 10:
 
Cálculo do 10!

<html>
<head>
<title>Factorial</title>
 
<script language="JavaScript">
function fat(num) {                       // Função de Calculo do Fatorial
  var res=1;                               // Variável que vai conter o resultado final
  for (var k=num; k>=1; k--) {             // Cálculo do fatorial
     res *= k;                             // Expressão reduzida da multiplicação
  }
  return(res);                         // Retorna  o fatorial de num
}                                          // Fim da função
 
// Programa principal
function main() {  

  for (var k=1; k<=10; k++) {               // Cálculo dos fatoriais entre 1 e 10
      document.write(k, "! = " , fat(k), "<br/>");
  }    
}
</script>
</head>
<body>
<h3>Cálculo Fatorial</h3>
<script language="JavaScript">
  main();
</script>
</body>
</html>

Execução:
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
10! = 3628800

Neste caso, o código JavaScript foi colocado no cabeçalho (header) da página HTML, sob a forma de funções repare que a função principal main() também foi desenvolvida  no cabeçalho.
O corpo da página HTML contém, neste exemplo, apenas a invocação da função main(). A forma mais comum do uso de JavaScript é a chamada de função que executa um determinado evento.

Executando uma função ao clicar no elemento ul:
<!DOCTYPE html>
<html>
<body>
<ul id="myList">
  <li>Coffee</li>
  <li>Tea</li>
</ul>
<p>Click na lista</p>
<script>
document.getElementById('myList').onclick = function(){
  var newItem = document.createElement("LI");
  var textnode = document.createTextNode("Water");
  newItem.appendChild(textnode);
  var list = document.getElementById("myList");
  list.insertBefore(newItem, list.childNodes[0]);
}
</script>
</body>
</html>

Click na lista


1.4. Função Anônima Auto-executável (imediata)
É uma construção útil quando se tenta esconder variáveis ​​do namespace pai.  Todo o código dentro da função está contida no âmbito privado da função, o que significa que não podem ser acessados ​​de fora da função, tornando-se verdadeiramente privada.
(...())
(function () {} ()); // 1ª opção, mais recomenda
ou(...)()
(function () {}) (); // 2ª opção, também funciona
O primeiro par de parenteses na segunda opção engloba toda a função afim de não confundir a sua execução.
O segundo par de parênteses na segunda opção é usado para chamar a função que acabou de ser fechada, se a função tiver parâmetros, poderá ser chamada com os respectivos argumentos, o navegador vai saber que o segundo parêntese deve ser aplicado a toda a expressão anterior, isto é, function(){}.
Ela permite que uma função seja executada assim que seja definida. Isso é bom principalmente pelo fato de fornecer um escopo temporário para a ação que você vai fazer, sem a necessidade de poluir seu escopo global.
Esse recurso pode ser utilizado para execução de arquivo externo do tipo JavaScript (.js), isso se chama de módulo.

Exemplo:

(function() {
  // some action
}());
Pode-se passar argumentos para as funções imediatas, algo assim:

(function(name, hobby) {
  console.log('Hi, my name is ' + name + ' and I like ' + hobby );
}('Fabeni', 'to travel'));

// "Hi, my name is Fabeni and I like to travel"

Uma grande vantagem de passar parâmetros para uma função imediata (IIFE), é que esse valor é passado como uma cópia, e não como uma referência. Isto significa que se alterarmos o valor desse parâmetro dentro da IIFE, esse valor não vai persistir fora dela.

Exemplo:
var myVar = true;
(function(myVar) {
  console.log(myVar); // true
  myVar = false;
  console.log(myVar); // false
}(myVar));
console.log(myVar); // true

O escopo da função anônima é local, ela altera o valor de uma variável global, porém só dentro de seu escopo essa alteração vale.
Isso é bom para criar cópias de variaveis globais, e garantir que se alguem sobreescrever essa variável, isso não vai influenciar o módulo que foi criado. Esse comportamento também é conhecido como Closure.

1.5. Parâmetro que Recebe Propriedade
Explicação 1:
Parâmetros primitivos (como um número) são passados para as funções por valor; o valor é passado para a função, mas se a função altera o valor do parâmetro, esta mudança não reflete globalmente ou na função chamada.
Se você passar um objeto (ou seja, um  valor não primitivo, tal como Array ou um objeto definido por você) como um parâmetro e a função alterar as propriedades do objeto, essa mudança é visível fora da função, conforme mostrado no exemplo a seguir:

Explicação 2:
Obs: passar parâmetro significa entrar com valor na função ou chamar a função com argumento.
Considerando que argumento é passado na chamada da função e parâmetro é declarado junto com a função. No código abaixo temos a função minhaFuncao(param), cuja parâmetro "param" recebeu a propriedade make igual a propriedade do objeto meucarro, ao chamar a função com o parâmetro meucarro, a propriedade make da função sobrescreveu a propriedade make do objeto anterior.
Exemplo:
<html>
<head>
<title></title>
<script language="JavaScript">
function minhaFuncao(obj) {
  obj.make = "Toyota";
}

var meucarro = {make: "Honda", model: "Accord", year: 1998};
var x, y;

x = meucarro.make;     // x recebe o valor "Honda"
document.write(x);
document.write('<br>');
minhaFuncao(meucarro); //aqui meucarro é um argumento, poderia ter qualquer nome.
y = meucarro.make;     // y recebe o valor "Toyota", ou seja, o retorno da função
                    // (a propriedade make foi alterada pela função)
 document.write(y);
</script>
</head>
<body>
</body>
</html>
Resultado:
Honda
Toyota

Perceba que a função acrescenta uma propriedade ao argumento passado, transformando o argumento em um novo objeto e sobrescrevendo o objeto já existente.
O resultado é justamente o que foi programado, ao lançar meucarro como argumento da função, a mesma acrescenta a propriedade make: Toiota, nesse caso meucarro é um simples argumento do parâmetro obj, poderia ser qualquer outro argumento que receberia a propriedade Toyota. O escopo de obj.make e meucarro.make são globais, ou seja, window.

1.6. Parâmetro this
Sempre que uma função é invocada, além dos parâmetros que representam os argumentos que são fornecidos na chamada da função, um parâmetro implícito chamado this também é transmitido a ela. O parâmetro this se refere a um objeto que está implicitamente associado à invocação da função e que recebe o nome de contexto da função. O parâmetro this aponta para algo que depende de como a função é invocada. A propriedade this especifica o objeto atual como sendo fonte dos valores passados a função.
parâmetro implementado com this significa que prevalece o escopo onde a função é  chamada (atual).
Exemplo:
O contexto atual é o objeto Maria.
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript">
function CriaClientes(nome,endereco,telefone,renda){
  this.Nome=nome; // o parâmetro nome é atribuído a variável Nome
  this.Endereco=endereco; // Nome tem escopo global porque não tem a expressão var, mesmo dentro da função.
  this.Telefone=telefone; // nome tem escopo local, interno a função porque está dentro dos parenteses.
  this.Renda=renda;
}
//A propriedade “this” especifica o objeto atual como sendo fonte dos valores passados a função. Agora, basta criar o nosso objeto:

Maria = new CriaClientes('Maria Aparecida','Rua Guilhotina dos Patos, S/N','332-1148',1300);

//Para acessar as propriedades do objeto Maria, basta usar a seguinte sintaxe:
console.log(Maria.Nome);// - retorna 'Maria Aparecida', escopo atual
console.log(Maria.Endereco);// - retorna 'Rua Guilhotina dos Patos, S/N', escopo atual.
console.log(Maria.Telefone);// - retorna '332-1148', escopo atual.
</script>
</head>
<body>
</body>
</html>
Saída Console:
Maria Aparecida
Rua Guilhotina dos Patos, S/N
332-1148
this.Nome = nome, significa atribuir o parâmetro nome a variável Nome . Para guardar valor precisa-se da variável Nome.
this, significa que a variável Nome tem o escopo onde o objeto está (externo ao objeto), com isso ela pode receber o argumento passado na construção do objeto.
O operador new  cria um  objeto para referênciar  através de um ponto (.) as variáveis dentro da função.
Não se usa var this.Nome porque senão Nome seria uma variável  local, só poderia ser acessada dentro da função.

O exemplo acima sem a criação do objeto com o operador new fica assim:
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript">
var Nome, Endereco, Telefone, Renda;
function CriaClientes(nome,endereco,telefone,renda){
  this.Nome=nome; //perceba que o parâmetro passará o valor recebido para a variável.
  this.Endereco=endereco;
  this.Telefone=telefone;
  this.Renda=renda;
}
CriaClientes('Maria Aparecida','Rua Guilhotina dos Patos, S/N','332-1148',1300);
console.log(Nome);
console.log(Endereco);
console.log(Telefone);
</script>
</head>
<body>
</body>
</html>
Saída Console:
Maria Aparecida
Rua Guilhotina dos Patos, S/N
332-1148

CONTEXTO DE EXECUÇÃO
Toda função JavaScript, ao ser executada, gera uma associação do objeto criado pelo interpretador através da palavra reservada this. A especificação da ECMAScript chama isso de ThisBinding, um evento que acontece toda vez que um código JavaScript é executado e um novo contexto de execução é estabelecido. O valor do this é constante e ele existe enquanto este contexto de execução existir.
Cuidado com this:
Exemplo:
<!DOCTYPE html>
<html>
<body>
<script>
var Number = function(value) {
  this.value = value;
  var self = this;
  var add = function(value) {
    this.value = value;
    return this.value + self.value;
  }
  return add;
}
//Resultado esperado é (3)
console.log(new Number(1)(2));
</script>
</body>
</html>

No browser, o this “padrão” referencia o objeto global window. Toda função declarada no escopo global também vai possuir o objeto window como valor do this (no strict mode vai ser undefined).

function myFunc () {
     console.log(this);  
}

var myFunc2 = function () {
     console.log(this);  
}

myFunc(); // Window (...)
myFunc2();  // Window (...)

OBJETOS
Quando uma função representa um método de um objeto, o valor do this passa a ser o objeto referenciado. Por exemplo:

var myObj = {
    init: function () {
        console.log(this);  
    }
};

myObj.init(); // Object {init: function}

O mesmo acontece quando um objeto é criado utilizando uma função construtora, só que nesse caso o this representa o objeto instânciado.

function MyObj () {
    console.log(this);  
}
var obj = new MyObj(); // MyObj {}

Escopo do this:
- JavaScript não suporta escopo em bloco; portanto, tudo que resta na linguagem é escopo de função.
- A única fonte de variáveis locais em JavaScript são parâmetros de funções e variáveis declaradas por meio da declaração var.
- Vejamos os exemplo abaixo sobre ecopos:
Sem this o escopo global e local são independentes
Com this.i=5 o escopo global é alterado pelo escopo local, a função tem escopo de chamada (argumento)
Com this.i=i o escopo global e o escopo local são alterados pelo escopo de chamada (argumento)
<!DOCTYPE html>
<html>
<head>
<SCRIPT type="text/javascript">
var i = 2; //escopo global
function test(i) {
i = 5; //escopo local
console.log(i);
}
test(10);//5 escopo local
console.log(i);//2 escopo global
</script>
</head>
<body>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<SCRIPT type="text/javascript">
var i = 2;//escopo global
function test(i) {
this.i = 5;//escopo local
console.log(i);//10
}
test(10);//10 escopo da chamada
console.log(i);//5 escopo global alterado
</script>
</head>
<body>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<SCRIPT type="text/javascript">
var i = 2;//escopo global
function test(i) {
this.i = i;//escopo local
console.log(i);
}
test(10);//10 escopo da chamada
console.log(i);//10escopo global alterado
</script>
</head>
<body>
</body>
</html>
Console:
5
2
Console:
10
5
Consosle:
10
10

- Todos escopos em JavaScript, incluindo o escopo global, tem o nome especial this, definidos em si, que se refere ao objeto atual.
- Escopos de função também tem o nome arguments, definido em si, e que contém os argumentos que foram passados para a função.

1.7. Invocações
Há 5 (cinco) maneiras diferentes de invocarmos uma função:
- Como uma função, na qual a função é invocada de modo direto;
- Como um método, o que associa a invocação a um objeto;
- Como um construtor, no qual um novo objeto é trazido à existência;
- Por meio do método bind();
- Por meio de seus métodos apply() e call() (aplicação/chamada).
Todas as invocações de funções também recebem dois parâmetros implícitos: “arguments” e “this”. Eles podem ser referenciados dentro da função da mesma forma que qualquer outro parâmetro nomeado explicitamente.
1.7.1. Invocação como Função
Ocorre quando uma função é invocada utilizando o operador () e a expressão para o qual o operador () é aplicado, não referencia a função como uma propriedade de um objeto.
Exemplos:
function calcular() {}; // função regular
calcular();

var xyz = function() {}; //função expressão
xyz();
OBS: observe que o contexto da função será seu contexto externo, e o parâmetro this apontará para esse contexto externo à função.

Exemplo:
var funcName = function( arg1, arg2, arg3 ) {
...
};
funcName();  // or
funcName(1,2,3); 
...

Você pode chamar uma função com qualquer número de argumentos e não obter um erro! É permitido que você crie funções com parâmetros “opcionais” e faça algo completamente diferente, dependendo do número de argumentos enviados.

Você não precisa definir os parâmetros na sua declaração de função. Em vez disso, todos os argumentos podem ser acessados via arguments dentro da função.
Exemplo:
var varName = function() {
console.log(arguments);
};  
varName();          // (nothing to output)
// or
varName(1, 2, 3);   // [1,2,3]
...

Exemplo:
O terceiro argumento "hello" não foi declarado na função.
<!DOCTYPE html>
<html>
<body>
  <script type="text/javascript">
   function ArgTest(arg1, arg2){
     var s = "";
     s += "The individual arguments are: "
     for (n = 0; n < arguments.length; n++){
       s += ArgTest.arguments[n];
       s += " ";
     }
   return(s);
   }
document.write(ArgTest(1, 2, "hello"));
// Output: The individual arguments are: 1 2 hello
  </script>
</body>
</html>

Resultado:
The individual arguments are: 1 2 hello

Obs: o ArgTest.arguments[n] é o próprio argumento, cuja índice n (0, 1 e 2), isto é, o primeiro argumento (1) tem índice 0, o segundo argumento (2) tem índice 1 e o terceiro agumento (hello) tem índice 2.

Exemplo:
O exemplo a seguir ilustra o uso da propriedade de arguments :
arguments é uma estrutura do tipo array. Na realidade, é um tipo especial de objeto que age como um array em muitos casos, mas possui sua própria funcionalidade e muitas vezes não terá a mesma funcionalidade que um array tem. Então, se você quer que ele seja um array, use slice para convertê-lo em um array.
var varName = function() {
var args = Array.prototype.slice.call(arguments);
};
...
<html>
<head>
<title></title>
<script language="JavaScript">
var varName = function() {
var args = Array.prototype.slice.call(arguments);
console.log(args);
}; 
varName();          // (nothing to output)
// or
varName(1, 2, 3);   // [1,2,3]
</script>
</head>
<body>
</body>
</html>
Saída Console:
(3) [1, 2, 3]
slice (slaɪs): s. fatia
1.7.2. Um função pode chamar a si mesma
Uma função pode referir-se e chamar a si própria. Há três maneiras de uma função referir-se a si mesma:
- o nome da função
- arguments.callee
- uma variável no escopo que se refere a função.
Uma função que chama a si mesma é chamada de função recursiva. Em alguns casos, a recursividade é análoga a um laço. Ambos executam o código várias vezes, e ambos necessitam de uma condição (para evitar um laço infinito, ou melhor, recursão infinita, neste caso).
Exemplo:
Uma função que calcula os fatoriais recursivamente:
function fatorial(n){
  if ((n == 0) || (n == 1))
    return 1;
  else///
    return (n * fatorial(n - 1));
}
Você poderia, então, calcular os fatoriais de um a cinco:
var a, b, c, d, e;
a = fatorial(1); // a recebe o valor 1
b = fatorial(2); // b recebe o valor 2
c = fatorial(3); // c recebe o valor 6
d = fatorial(4); // d recebe o valor 24
e = fatorial(5); // e recebe o valor 120

Por exemplo,  o seguinte laço:
var x = 0;
while (x < 10) { // "x < 10" a condição do laço
   // faça coisas
   x++;
}
Pode ser convertido em função recursiva e uma chamada para a função:

function loop(x) {
   if (x >= 10) // "x >= 10" a condição de parada (equivalente a "!(x < 10)")
      return;
   // faça coisas
   loop(x + 1); // chamada recursiva
}
loop(20);

1.7.3. Invocação como Método
Ocorre quando uma função é atribuída a uma propriedade de um objeto e a invocação ocorre referenciado-se a função que utiliza essa propriedade. A função será invocada como um método desse objeto.
Exemplo:
var xyz = {};
xyz.calcular = function() {};
xyz.calcular(); //invocada através de um objeto

Observe que o contexto ou visibilidade da função será o objeto xyz, e o parâmetro this aponta para este objeto. Esta, junto com construtores, são as principais formas pelas quais o JavaScript permite que códigos orientados a objetos sejam escritos;
Notar que o contexto de funções para cada invocação da função muda dependendo de como ela é invocada, e não de acordo como foi declarada.

Exemplo:
var nome = "João"
var idade = 30

var juca = {
  nome: "Juca",
  idade: 40,
  imprime: function () {
    console.log(this.nome + " " + this.idade)
  }
}

function imprime () {
  console.log(this.nome + " " + this.idade)
}

imprime() // João 30
juca.imprime() // Juca 40
Aqui criamos duas variáveis no contexto global, o que seria o mesmo que fazer window.nome ou this.idade, pois o this no contexto global referencia ao próprio objeto window. E criamos as mesmas variáveis dentro do objeto juca também. Dentro do objeto juca, o this passa a referenciar ao objeto juca, ou seja, this dentro da função se refere ao primeiro escopo externo.

1.7.4. Invocação como Construtor
Para invocar a função como um construtor, precedemos sua invocação com a palavra-chave new.

Exemplo:
function Especialistas() {    // define um construtor que cria uma propriedade "oculto" em qualquer objeto que seja o contexto da função.
    this.ocultar = function() { return oculto;};
}
var especialista1 = new Especialistas();
var especialista2 = new Especialistas();
var contexto1 = especialista1.ocultar();
var contexto2 = especialista2.ocultar();
OBS: a codificação como construtor traz a característica de se evitar a repetição de código. O código comum é escrito uma só vez, como o corpo do construtor.

1.7.5. bind()
Faz uma cópia de uma função, sendo que o primeiro argumento  é um objeto ao qual a palavra-chave this pode fazer referência dentro da nova função. Os demais argumentos faz um paralelo com os parâmetros da função original.
function func(param1, param2) { return ...}
var funcBind = func.bind(window, Arg1);
funcBind(Arg2);
ou
function func(param1, param2) { return ...}
var funcBind = func.bind(window, Arg1,Arg2);
funcBind();

Exemplo
O exemplo da direita não usa bind, mas o reultado é o memo.
<html>
<head>
<title></title>
<script language="JavaScript">
function foo(nome, idade) { return 'ola '+nome+', você tem '+idade}

var fooBind = foo.bind(window, 'joao');
console.log(fooBind('23')); // ola joao, você tem 23
</script>
</head>
<body>
</body>
</html>

<html>
<head>
<title></title>
<script language="JavaScript">
function foo(nome, idade) { return 'ola '+nome+', você tem '+idade}
var chamafoo = function (idade) {
    return console.log(foo('joao', idade));
}
chamafoo(23);
</script>
</head>
<body>
</body>
</html>
Saída Console:
ola joao, você tem 23
Saída Console:
ola joao, você tem 23

Exemplo:
Quando queremos manter o this do objeto que definiu aquele método, precisamos usar o bind(). O exemplo da esquerda usou o escopo da função func(), o da direita usou o escopo window. A chamada da função func.imprime(nome,idade) produz o mesmo efeito no exemplo da esquerda.

<html>
<head>
<title></title>
<script language="JavaScript">
var nome = "João";
var idade = 30;

var func = {
  nome: "Juca",
  idade: 40,
  imprime: function () {
    console.log(this.nome + " " + this.idade)
  }
}
var funcBind= func.imprime.bind(func,'Juca');
funcBind(40); // Juca 40,  escopo de func
</script>
</head>
<body>
</body>
</html>
<html>
<head>
<title></title>
<script language="JavaScript">
var nome = "João";
var idade = 30;

var func = {
  nome: "Juca",
  idade: 40,
  imprime: function () {
    console.log(this.nome + " " + this.idade)
  }
}
var funcBind= func.imprime.bind(window,'Juca');
funcBind(40); // Joao 30, escopo window
</script>
</head>
<body>
</body>
</html>
Saída Console:
Juca 40
Saída Console:
João 30

O que o bind está fazendo aqui é retornar o mesmo objeto, mas com o this do objeto passado como parâmetro.

1.7.6. Call e Apply
Vimos que o bind é o método que podemos utilizar para resolver todos os problemas com o this. Mas, e se quisermos simplesmente invocarmos uma função utilizando o this de outro objeto diretamente, sem ter que referenciá-la para outra função com o bind? Nesse caso podemos utilizar o apply() e o call().
Com esses dois métodos podemos invocar uma função passando o contexto de qualquer objeto que quisermos.
Exemplo:
var joaoObj = {
  nome: "João",
  idade: 20,
  cidade: "São Paulo"
}

var jucaObj = {
  nome: "Juca",
  idade: 40,
  cidade: "Rio de Janeiro"
}

function imprimeDados () {
  console.log(this.nome + ", " + this.idade + " anos, " + "nascido em " + this.cidade)
}

imprimeDados();   // undefined, undefined anos, nascido em undefined
imprimeDados.call(joaoObj);  // João, 20 anos, nascido em São Paulo
imprimeDados.apply(jucaObj); // Juca, 40 anos, nascido em Rio de Janeiro

Como pode ser visto no exemplo, a função foi chamada utilizando o this de cada objeto passado como parâmetro. Repare que os dois objetos e a função chamada estão no mesmo escopo.
Até aqui os métodos call e apply possuem a mesma função. O que os diferenciam é a forma como são utilizados quando precisamos invocar funções que recebem parâmetros. Vou alterar a função imprimeDados para que tenhamos que passar os valores de idade e cidade como parâmetro:
var joaoObj = {
  nome: "João"
}

var jucaObj = {
  nome: "Juca",
}

function imprimeDados (idade, cidade) {
  console.log(this.nome + ", " + idade + " anos, " + "nascido em " + cidade)
}

imprimeDados.call(joaoObj, 20, "São Paulo");
imprimeDados.apply(jucaObj, [40, "Rio de Janeiro"]);

// ou
var dados = [40, "Rio de Janeiro"];
imprimeDados.apply(jucaObj, dados);

Enquanto os parâmetros no método call vêm normalmente depois do objeto que será utilizado como contexto, no apply, precisamos passá-los como um array que pode ser a solução para alguns códigos.
Exemplo:
Se quiséssemos achar os valores máximos e mínimos de um array, teríamos que fazer um código assim:
var lista = [4,5,2,8,7,3,9,6,10,1]
max = -Infinity, min = +Infinity
for (var i = 0; i < lista.length; i++) {
  if (lista[i] > max) {
    max = lista[i]
  }
  if (lista[i] < min) {
    min = lista[i]
  }
}
Mas, como o apply nos deixa passar um array como substituto de uma cadeia de parâmetros, o algoritmo acima fica bem mais simples:
var lista = [4,5,2,8,7,3,9,6,10,1]
var max = Math.max.apply(undefined, lista)
var min = Math.min.apply(undefined, lista)
Vale notar que, apesar de utilizar o apply nessa condição faça com que o código fique mais enxuto, é importante não ultrapassar o limite máximo de parâmetros que uma função pode receber.

Em resumo, quando ficar em dúvida de qual objeto o this está referenciando em determinado momento, lembre-se: o objeto que invoca uma função é sempre o que está sendo referenciado pelo this naquele momento. E, se a função está sendo chamada de forma pura no código, então o this vai referenciar o objeto window.

1.8. arrow functions ()=>
Uma expressão função de seta tem uma sintaxe pequena em comparação com a expressão de função.
let soma = (a, b) => {
  return a + b
}
Nas linguagens com escopo léxico, o que conta é a estrutura "gramatical" do programa, ou seja, se no código-fonte uma estrutura está aninhada em outra, a de dentro pode acessar variáveis na de fora. Funções de seta capturam o valor this do contexto delimitado.
Funções de seta são sempre anônimas.
léxico: conjunto de palavras que uma linguagem de programação tem para fazer suas expressões.
Escopo léxico significa que um função interna tem acesso ou visibilidade ao escopo em que está inserida, ou seja, é capaz de acessar as variáveis externas e pertencentes ao escopo onde a função interna está inserida.

Para definirmos argumentos, existem 3 maneiras possíveis. Sem argumentos, um argumento e vários argumentos.
Sintaxe:
() => { ... } // sem argumentos
a => { ... } // um argumento
(a, b) => { ... } // vários argumentos

Na especificação do corpo da função, podemos definir como um bloco (a forma padrão) ou como uma expressão que é retornada implicitamente.
Usar new com arrow functions não é possível, pois elas não possuem o método interno [[Construct]] (o que permite que uma função normal seja usada com new) e muito menos a propriedade prototype. E já que seu this é léxico, e não dinâmico, não faria o mínimo sentido de qualquer forma.

Exemplo:
Função de seta altera a variável do escopo acima.
Exemplo:
Função anonima não altera a variável do escopo acima
<html>
<head>
<title></title>
</head>
<body>
<script language="JavaScript">
function Pessoa(){
  this.idade = 0;
  let var1= () => {
  return this.idade = 20;
  }
document.write(var1());
document.write('<br>');
}
var p = new Pessoa();
document.write(p.idade);
</script>
</body>
</html>
<html>
<head>
<title></title>
</head>
<body>
<script language="JavaScript">
function Pessoa(){
  this.idade = 0;
  let var1= function(){
  return this.idade = 20;
  }
document.write(var1());
document.write('<br>');
}
var p = new Pessoa();
document.write(p.idade);
</script>
</body>
</html>
Resultado:
20
20
Resultado:
20
0

Sem contexto de execução
Toda vez que uma função tradicional do JavaScript é chamada, seu contexto é criado antes de sua execução, nesse momento é determinado o valor das palavras reservadas this e arguments. Esse processo simplesmente não acontece com as novas arrow functions, elas são executadas sobre exatamente o mesmo contexto de onde forem criadas, utilizando o mesmo this e o arguments desse contexto, como se fossem qualquer outra variável externa a ela que estivesse acessando, tornando impossível alterá-los de qualquer forma.

Arrow functions não são construtures
Toda função tradicional do JavaScript é também um construtor e podem ser instanciadas, para isso guardam seu próprio protótipo no atributo .prototype, que é inexistente nas novas arrow functions, graças a isso elas não podem ser usadas dessa forma e qualquer tentativa de fazer isso retornará um erro de execução.

let foo = { 
  normal: function(){ console.log(this.x, arguments) },
  arrow: () => console.log(this.x, arguments)
}
console.log(foo.normal.prototype); // {} 
console.log(new foo.normal); // {}

console.log(foo.arrow.prototype); // undefined 
console.log(new foo.arrow);  // TypeError: () => is not a constructor

A falta de vários recursos, contexto próprio, protótipo e etc,  têm suas vantagens, afinal grande parte das vezes não precisamos de tudo isso, então elas não serão apenas mais fáceis de ler e escrever, como utilizarão menos memória e terão sua performance de execução otimizadas. Elas foram feitas para casos de uso simples, casam perfeitamente com as funções de map, reduce, filter e outros tantos métodos funcionais já existentes no antigo ECMAScript 5.

2. Funções Classes


Uma função em JavaScript pode ter propriedade e métodos dos quais os objetos que são criados com o operador new podem herdar.
Classe decorrente de uma função normal, é hoit:
function Pessoa(nome) {
this.Nome = nome;
}

Classe decorrente de uma função expressão, não é hoit:
var NomeVar = function() {
this.Nome = nome;
 };

Obs:
- a função expressão é anônima, não é hoit, a herança é feita com o nome da variável.
- this.Nome significa: a variável Nome recebe o valor do parâmetro nome, ou seja, recebe o argumento de entrada na função, quando ela é chamada. Fiz questão de colocar aqui com nomes diferentes, Nome e nome.
- a linguagem Javascript é case sensitive, ou seja, faz diferenciação entre maiúsculas e minúsculas: Nome é diferente de nome.
- this refere-se ao contexto do objeto corrente.

2.1. Function Expression x Function Declaration

As duas formas possuem o mesmo resultado, a diferença está em seu carregamento pelo navegador.

somaDoisNumeros(10, 20);
function somaDoisNumeros(num1, num2) {
 return num1 + num2;
}
O código acima funciona, mesmo chamando a função antes de sua declaração. Já o código a seguir dá um erro:

somaDoisNumeros(10, 20); // erro, função não foi declarada ainda
var somaDoisNumeros = function(num1, num2) {
 return num1 + num2;
};
Isso ocorre devido a um processo chamado hoisting (levantamento, içamento). Function declarations são 'içadas' até o topo do script pelo JavaScript. A mesma coisa são feitas com variáveis, mas a diferença é que apenas as declarações são 'içadas' até o topo do script, isto é, seu conteúdo continuam como 'undefined'. É como se o interpretador fizesse isso:

var somaDoisNumeros; // delcaração separada
somaDoisNumeros();
somaDoisNumeros = function(num1, num2) {
 return num1 + num2;
};
Por isso a função expressão não é adequada para ser classe.

3. Criando Objeto com Função

Pode-se dizer que um objeto em JavaScript é um tipo especial de variável que contém propriedades e métodos.
Para criar o objeto pessoa usando a classe Pessoa, simplesmente declare-o e use a palavra-chave new para inicializá-lo, assim podemos atribuir algum valor para a propriedade herdada da classe.
3.1. Objeto Instância de uma Classe
Classe decorrente de uma função normal, é hoit:
function Pessoa(nome) {
this.Nome = nome;
}

Cria-se o objeto com o operador new:
var pessoa = new Pessoa("Pedro");

Um construtor nada mais é do que uma função. Ela pode ser executada como uma função ou pode ser utilizada para instanciar um objeto utilizando a palavra reservada new.
Caso você execute a função como uma chamada normal, vale realçar que o this dentro da função, nesse contexto, será o objeto global window.
Exemplo:
function Categoria(nome) {
    this.nome = nome;
}
var categoria = new Categoria('Livros');

Ao executar a função Categoria com new estamos fazendo quatro coisas:
- criamos um novo objeto JavaScript ({});
- definimos o construtor do objeto categoria como Categoria – definindo também o tipo dele (retornado no instanceof);
- definimos o protótipo do objeto categoria como Categoria.prototype;
- executamos a função Categoria dentro do escopo do novo objeto, criando assim uma nova instância.
Obs:
- instanceof: operador que retorna um valor booleano que indica se um objeto é ou não uma instância de uma classe específica.
- prototype: a propriedade Object.prototype representa o Object protótipo do objeto.
3.1.1. Métodos e Propriedades Privadas
Uma outra particularidade das funções construtoras é a possibilidade de criar métodos e propriedades privadas.

function Categoria(nome) {
    var totalProdutos = 0,
        self = this,
        atualizaTotalProdutos = function() {
            self.totalProdutos += 1;
        };
    this.nome = nome;
    atualizaTotalProdutos();
}
A variável totalProdutos e o método atualizaTotalProdutos só existem no escopo do objeto Categoria criado e podem ser utilizados apenas por métodos do objeto.

Aqui utilizamos um forma de progrmar importante. Como cada função possui o seu próprio contexto e o this dentro do método atualizaTotalProdutos referencia a própria função e não o objeto Categoria precisamos armazenar o contexto do objeto dentro da variável self. (Outra forma seria utilizar os métodos call e aply para definir o this da função)

Utilizando a cadeia de protótipos, podemos atualizar propriedades ou inserir novos métodos em objetos criados a partir de funções construtoras.

Categoria.prototype.exibeProdutos = function () {
    var html = '',
        i;
    for (i = 0; i < this.produtos.length; i++) {
        html += this.produtos[i].nome;
    }
    return html;
};

O código acima adiciona o método exibeProdutos ao protótipo de Categoria e também a todos os objetos da cadeia, instanciados ou não.
As funções construtoras, portanto, são ideais para objetos que podem existir como múltiplas instâncias no mesmo contexto.
Uma observação: para melhor organizar seu código uma boa prática é utilizar a primeira letra maiúscula nos nomes de funções construtoras, diferenciando-as de funções comuns.

3.2. Objeto Literal
Também pode-se criar um objeto usando a sintaxe literal, porém esse recurso não utilizar a instância de uma classe:
var pessoa = {name: "Pedro"};

Adicionando Propriedades ao Objeto
pessoa.name="Pedro";
ou
pessoa["name"]="Pedro";
Propriedades de objetos em JavaScript podem também ser acessadas ou alteradas usando-se notação de colchetes. Objetos são às vezes chamados de arrays associativos, uma vez que cada propriedade é associada com um valor de string que pode ser usado para acessá-la.
3.2.1. Literais
Vejamos primeiro o que é literais.
Como estamos falando de funções e valores, este ítem é dedicado aos Literais, que são uma forma de entrada de dados através de um ou mais valores. O valor literal é um valor do tipo primitivo, ou seja, o valor é puro, simple ou direto.
- Literais Matrizes
Um literal matriz é uma lista de zero ou mais expressões, cada uma representando um elemento da matriz, delimitada por colchetes e separados por vírgulas.
Exemplo:
cidades = [ , "São Paulo", , , "Rio de Janeiro", , ]
Esta matriz tem 6 elementos, onde o primeiro, o terceiro, o quarto e o sexto não estão definidos. A última vírgula será ignorada.
Nota : Um array literal é um tipo de inicializador de objetos.
Se um array é criado usando um literal no topo do script, JavaScript interpreta o array cada vez que avalia a expressão que contêm o array literal. Além disso, um literal usado em uma função é criado cada vez que a função é chamada. 
- Literais Booleanos
O tipo booleano tem dois valores literais: true e false
Não confunda os valores primitivos Boolean true e false com os valores true e false do objeto Boolean.
- Literais Ponto flutuante
Um literal ponto flutuante é composto por um decimal isolado ou por um inteiro ou decimal seguido de uma parte exponencial de base 10.
A parte expoente é um "e" ou "E" seguindo por um inteiro o qual pode ser precedido por um sinal "+" ou "-". Um literal ponto flutuante deve ter pelo menos um dígito além de um ponto decimal ou "e" ou "E".
Exemplos:
3.1415
-.31-e2 // devolve -0.31*102 = 0.0031
1E4 // devolve 1*104 =10000
7e2.5 // devolve erro ou undefined, o expoente só pode ser inteiro
- Literais inteiros
Literais inteiros pode ser expressos na base 10 (decimal), base 16 (hexadecinal) e base 8 (octal). Um inteiro decimal é uma sequência de dígitos com o primeiro dígito diferente de zero. Os inteiros hexadecimais podem usar adicionalmente as letras a A a F. Devem começar com carácteres 0x ou 0X. O sistema octal deixou de fazer parte do padrão ECMA-262 edição 3.
Exemplos:
144, 0xF1, -237
- Literais Texto (Strings)
Um literal texto é zero ou mais carácteres delimitados por aspas dupla ("") ou apas simples, plicas (''). Um literal texto tem que ser delimitado pelo mesmo delimitador.
Exemplos:
"Texto 1"
'Texto 2'
3.2.2. Objetos Literais
Um objeto literal em javascript é uma variável que recebe as propriedades  entre chaves separadas por vírgula. Não há a instância de uma classe.
var pessoa = {name: "Pedro"};

Exemplo:

var tweet = {
    'user': 'tiu_uiLL',
    'message': 'Afinal, como é Orientação a Objetos em JavaScript ? – Exemplos',
    'date': '2013-05-17'
};
console.log( tweet.user );//tiu_uiLL
console.log( tweet.message );//Afinal, como é Orientação a Objetos em JavaScript ? – Exemplos

A variavel tweet é um objeto javascript. Possui 3 atributos: user, message e date.
Para acessa-los, uso o operador ponto.

Exemplo:
capital = { Portugal: "Lisboa", Angola: "Luanda" }
document.write( capital.Angola ); // escreve Luanda

Exemplo:
O primeiro elemento do objeto carro define uma propriedade, meuCarro, e atribui para ele uma nova string, "Punto"; o segundo elemento, a propriedade getCarro, é imediatamente atribuído o resultado de chamar uma função (tipoCarro("Fiat")); o terceiro elemento, a propriedade especial, usa uma variável existente (vendas).

var vendas = "Toyota";
function tipoCarro(nome) {
  if (nome == "Fiat") {
    return nome;
  } else {
    return "Desculpa, não vendemos carros " + nome + ".";
  }
}
var carro = { meuCarro: "Punto", getCarro: tipoCarro("Fiat"), especial: vendas };

console.log(carro.meuCarro);   // Punto
console.log(carro.getCarro);  // Fiat
console.log(carro.especial); // Toyota

Além disso, você pode usar um literal numérico ou string para o nome de uma propriedade ou aninhar um objeto dentro do outro. O exemplo a seguir usar essas opções.

var carro = { carros: {a: "Saab", "b": "Jeep"}, 7: "Mazda" };
console.log(carro.carros.b); // Jeep
console.log(carro[7]); // Mazda

Importante:
Nomes de propriedades de objeto podem ser qualquer string, incluindo uma string vazia. Caso o nome da propriedade não seja um identificador JavaScript ou número, ele deve ser colocado entre aspas. Nomes de propriedades que não possuem identificadores válido, também não podem ser acessadas pela propriedade através de ponto (.), mas podem ser acessadas e definidas com a notação do tipo array ("[]").
Exemplo:
var unusualPropertyNames = {
  "": "Uma string vazia",
  "!": "Bang!"
}
console.log(unusualPropertyNames."");   // SyntaxError: string inesperada
console.log(unusualPropertyNames[""]);  // Um string vazia
console.log(unusualPropertyNames.!);    // SyntaxError: símbolo ! inesperado
console.log(unusualPropertyNames["!"]); // Bang!

Obs:
var foo = {a: "alpha", 2: "two"};
console.log(foo.a);    // alpha
console.log(foo[2]);   // two
//console.log(foo.2);  // Error: missing ) after argument list
//console.log(foo[a]); // Error: a não está definido
console.log(foo["a"]); // alpha
console.log(foo["2"]); // two
 
3.2.3. Função Anônima como Valor da Propriedade de um Objeto Literal

É possível atribuir uma função literal como valor da propriedades de um objeto. O objeto é criado utilizando um par de chaves, {} e suas propriedades e métodos são todos públicos. Este tipo de objeto também é chamado de objeto estático.
Encapsule o objeto entre chaves {}, delimite as propriedades e métodos com vírgulas dentro do objeto. Ao atribuir o objeto a uma variável, não se esqueça do ponto e vírgula após a chave de fechamento, porque uma instrução termina com ponto e vírgula.
Exemplo:
var obj = {
    a: "",
    b: "",
    c: "",
    funcao1: fucntion (){},
    funcao2: fucntion (){},
    funcao3: fucntion (){}
};

Seu uso é recomendado em situações onde não podem existir mais de uma instância do objeto, como por exemplo, objetos de configurações do projeto ou coleções de objetos. Além disso, este tipo de notação é muito utilizado para definir o namespace do seu código JavaScript.

3.3. Imprimindo as Propriedade de um Objeto

Formas de acesso a propriedade de um objeto:
1) nomeObjeto["nomePropriedade"]
2) nomeObjeto.nomePropriedade
3) for (var nomesProp in nomeObjeto) {
      document.body.innerHTML += "nomeObjeto." + nomesProp + " = " + nomeObjeto[nomesProp]+'<br>';
    }
Obs: o loop for (var nomesProp in nomeObjeto) percorrerá todo o objeto e guardará o nome da propriedade na variável nomesProp para cada ciclo.

Exemplos:
<html>
<head>
<title></title>
</head>
<body>
<script language="JavaScript">
var cliente = {
  nome: "Wesley",
  idade: 20,
  cargo: "Front End",
};

document.body.innerHTML += cliente["nome"]+'<br>';
document.body.innerHTML += cliente["idade"]+'<br>';
document.body.innerHTML += cliente["cargo"]+'<br>';
</script>
</body>
</html>
Resultado:
Wesley
20
Front End

3.4. Alterando as Propriedade de um Objeto
<html>
<head>
<title></title>
</head>
<body>
<script language="JavaScript">
var cliente = {
  nome: "Wesley",
  idade: 20,
  cargo: "Front End",
  setAtualiza: function(n, i, c){
    this.nome = n;
    this.idade = i;
    this.cargo = c
  }
};
cliente.setAtualiza("NovoNome", 25, "Pleno");

document.body.innerHTML += cliente["nome"]+'<br>';
document.body.innerHTML += cliente["idade"]+'<br>';
document.body.innerHTML += cliente["cargo"]+'<br>';
</script>
</body>
</html>
Resultado:
NovoNome
25
Pleno

3.5. Imprimindo Todas as Propriedade de um Objeto (loop)
O nome das propriedades de um objeto pode ser capturado com a função for(var nomesProp in nomeObj){}, onde nomesProp é o nome das propriedades e nomeObj é o nome do objeto, esse loop percorre todas as propiedades do objeto.

<html>
<head>
<title></title>
</head>
<body>
<script language="JavaScript">
var cliente = {
  nome: "Wesley",
  idade: 20,
  cargo: "Front End",
  setAtualiza: function(n, i, c){
    this.nome = n; //observe que this é o mesmo escopo da função que é o do objeto, não confunda com o escopo criado pela função.
    this.idade = i;//pode dizer também que o this dentro da função faz referência ao escopo externo, ou seja, do objeto.
    this.cargo = c
  }
};
cliente.setAtualiza("NovoNome", 25, "Pleno");

for (var nomesProp in cliente) {
   document.body.innerHTML += "cliente." + nomesProp + " = " + cliente[nomesProp]+'<br>';
}
</script>
</body>
</html>
Resultado:
cliente.nome = NovoNome
cliente.idade = 25
cliente.cargo = Pleno
cliente.setAtualiza = function (n, i, c){ this.nome = n; this.idade = i; this.cargo = c }

3.6. Imprimindo Algumas Propriedade de um Objeto (loop)
A quarta propriedade do objeto é uma função, não é interessante imprimí-la, para isso será modificado o código acima, vamos criar uma array, keys = [] com os nomes das propriedades e depois usar o índice desse array com a função for (var i=0; i < 3; i++) para imprir as propriedades.
<html>
<head>
<title></title>
</head>
<body>
<script language="JavaScript">
var cliente = {
  nome: "Wesley",
  idade: 20,
  cargo: "Front End",
  setAtualiza: function(n, i, c){
    this.nome = n;
    this.idade = i;
    this.cargo = c
  }
};
cliente.setAtualiza("NovoNome", 25, "Pleno");
var keys = [];
for (var namesProp in cliente){
    keys.push(namesProp)
}

for (var i=0; i < 3; i++) {
document.body.innerHTML += cliente[keys[i]]+'<br>';
}
</script>
</body>
</html>
Resultado:
cliente.nome = NovoNome
cliente.idade = 25
cliente.cargo = Pleno
w
3.7. Criação de Objetos
Será abordado cinco formas de criar objeto.
3.7.1. Singleton Objects
É simplesmente um objeto literal com métodos e atributos, agrupados por algum tipo de relação que têm uns com os outros, utilizando a notação literal mais conhecida como JSON (JavaScript Object Notation):
Exemplo:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script>
var carro = {
  cor: "Azul",
  ano: 2018,
  cliente: "Marcos",
  comprar: function () {
    return this.cliente + " comprou o carro";
  },
  vendeu: function () {
    return "O carro " + this.cor + " foi vendido";
  }
}
console.log(carro.comprar());
console.log(carro.cor);
</script>
</body>
</html>
Saída no Console:
Marcos comprou o carro
Azul

3.7.2. Factory Functions
Outra forma, é utilizando funções construtoras que fornece uma instância aos objetos criados com o operador new.
factory (ˈfæktəri): s. fábrica.

<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script>
function Carro (cor, ano, cliente) {
  this.cor = cor;
  this.ano = ano;
  this.cliente = cliente;
  this.comprar = function () {
    return this.cliente + " comprou o carro";
  }
  this.escolhe = function () {
    return console.log(this.cliente + " escolheu o carro "+this.cor);
  }
}
var gol = new Carro("Azul", 2016, "Paula");
var palio = new Carro("Verde", 2010, "Marcos");
console.log(palio.cor); // Verde
var r = palio.comprar();
console.log(r);

console.log(gol.cor); // Azul
gol.escolhe();

</script>
</body>
</html>

Saída no Console:
Verde
 Marcos comprou o carro
Azul
Paula escolheu o carro Azul

3.7.3.1. new Object()
Object, Function, Boolean, Symbol , Error, EvalError, InternalError, RangeError, ReferenceError, StopIteration, SyntaxError, TypeError e URIError
Estes são objetos globas, básicos e fundamentais nos quais todos os outros objetos são baseados. Isso inclui objetos que representam objetos genéricos, funções e erros.
Object é um objeto global com propriedades e métodos pré-definidos.
Todos os objetos em javascript são herdeiros de Object (ou seja, sua instâncias).
Todos os objetos herdam métodos e propriedades de Object.prototype, porém eles podem ser sobrescritos. Por example,  outros construtores prototypes podem sobrescrever a propriedade constructor e fornecer seu próprio método toString.
Mudanças no Object, objeto prototype, são propagadas para todos os objetos até que as propriedade e métodos modificados sejam sobrescritos na corrente prototype mais a frente.

Sintáxe
new Object( [ valor ] )
Exemplo:
var contaBancaria = new Object () ;
contaBancaria . numero = 1234;
contaBancaria . saldo = 1000;

contaBancaria.deposita = function ( valor ) {
   if( valor > 0) {
   this . saldo += valor ;
   }
   else {
   alert (’Valor inválido !’) ;
  }
};

3.7.3.2. Protótipo
O protótipo é atribuído somente no momento da criação do objeto, e isso pode ser feito de duas maneiras.
3.7.3.3. prototype
Toda função possui uma propriedade chamada prototype (funções são objetos em JavaScript, portanto podem possuir propriedades). Quando uma função é invocada como construtor, é criado um novo objeto cujo protótipo é o valor da propriedade prototype da função. Por exemplo:

function Veiculo() {}
Veiculo.prototype.buzinar = function() {
    alert('Fom');
}
var carro = new Veiculo(); // invocação como construtor
carro.buzinar();  // dispara o alert

No Javascript, todas as funções possuem um objeto chamado prototype, onde podemos adicionar métodos ou objetos que serão compartilhados entre todas as instâncias criadas com o new.
Veja um exemplo:
<!DOCTYPE html>
<html>
<head>
<script>
function Carro (cor, ano, dono) {
  this.cor = cor;
  this.ano = ano;
  this.dono = dono;
}

Carro.prototype.ligar = function () {
  return this.dono + " ligou o carro";
}

Carro.prototype.andar = function () {
  return "O carro " + this.cor + " está andando";
}

var camaro = new Carro("Amarelo", 2016, "joao");
var fusca = new Carro("Preto", 1977, "joao");

console.log(camaro.andar()); // O carro amarelo está andando
console.log(fusca.andar());  // O carro preto está andando
</script>
</head>
<body>
</body>
</html>
Agora, os objetos camaro e fusca não possuem mais, cada um, uma cópia dos métodos definidos na função construtora. Os dois estão utilizando os mesmos métodos definidos no protótipo de Carro e mesmo assim ainda retornam valores diferentes. Isso acontece pois o this utilizado sempre é o do objeto que invocou a função, ou seja, o this faz uma referência entre o objeto criado com a propriedade da função construtora. É só lembrar da relação this/new.
O protótipo de uma função serve justamente para compartilharmos métodos e objetos entre instâncias. Todos os objetos possuem um protótipo associado a ele. Se não modificamos esse protótipo, ele será o próprio Object do Javascript.

3.7.3.4. Site Oficial
Consulte sempre a referência para tirar as dúvidas.
https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf

3.7.4. Atribuição direta - Object.create
A partir do ECMAScript 5, a linguagem oferece outra maneira de se criar um objeto com determinado protótipo, a função Object.create. Repare que ela é um método do construtor Object, portanto pode ser considerada um método estático. O que essa função faz é criar um novo objeto cujo protótipo é o que tiver sido passado como primeiro argumento:

var veiculo = {
    buzinar: function() {
        alert('Fom');
    }
};
var carro = Object.create(veiculo); // veiculo será o protótipo de carro
carro.buzinar(); // dispara o alert

4. Escopo

Em JavaScript há apenas dois tipos de escopo, visibilidade ou acesso, (1) o global que é fora da função e (2) o local que é dentro da função. Função é o único construtor em JavaScript que criam um novo escopo. Então se nós desejamos que nossos módulos tenham um escopo próprio, teremos que colocá-los em funções de alguma forma.
Caso você queira isolar uma variável, deve declará-la dentro de uma função com var.
<html>
<head>
<title></title>
</head>
<body>
<script language="JavaScript">
        var counter = 1; //escopo global
        var teste = (function(){
                var counter = 0; //escopo local

                return function(){
                    return counter++;
                };
            }()
        );
     
        document.write(counter+'<br>'); //counter = 1, global
        document.write(teste()+'<br>'); // counter = 0 depois counter++ = 1
        document.write(teste()+'<br>'); // counter = 1 depois counter++ = 2
        document.write(teste()+'<br>'); // counter = 2 depois counter++ = 3
        document.write(teste()+'<br>'); // counter = 3 depois counter++ = 4
        document.write(counter); //counter = 1, global
</script>
</body>
</html>

Resultado:

1
0
1
2
3
1
Observe que a mesma variável é criada duas vezes e com o mesmo nome.
Revisão: incremento (++)
x=2
1) x = ++x = x + 1 = 3
2) x = x++ = x + 1 = 3
3) Comparação: y = ++x
Primeiro faz o incremento: ++x = 3
Segundo faz a igualdade: y = 3
4) Comparação: y = x++
Primeiro faz a igualdade: y = x = 2
Segundo faz o incremento: y = x++ = 3

Funções não podem ser declaradas em blocos que não sejam de código:
Vejamos este código:
if (true) {
  function foo() {
    return 'primeiro';
  }
} else {
  function foo() {
    return 'segundo';
  }
}
foo();
Alguns browsers vão retornar "primeiro", outros "segundo"!
De acordo com a especificação, declarações de função até podem aparecer dentro de blocos de função, mas não dentro de blocos de if, while, for e outros blocos estruturais.

4.1. Closures
Quando uma função é declarada dentro de outra função, essa função interna possui acesso a todas as variáveis e funções declaradas dentro do escopo da função externa. Essa técnica, que se chama closure, é utilizada para criar namespaces e facilitar o uso do escopo.
function vezes(x){
return function(y){
    return x*y;
  };
}
var return1 = vezes(3);
var return2 = return1(5);
alert(return2); // Retorna 15

Quando você chama vezes(3), ela retorna a função anônima declarada dentro dela inferindo o valor passado à variável x. A função retornada e referenciada pela variável return1 é assim:
function(y) {
 return 3 * y;
};
Depois, esta variável é passada recebendo o valor de y e executa a multiplicação, retornando o resultado. Entretando, isso só foi possível por conta do closure criado, onde a função interna tinha acesso à variável x da função externa.
Uma closure é criada quando a função interna é de alguma forma disponibilizada para qualquer escopo fora da função externa.
closure (ˈkloʊʒər): s. fechamento (de uma empresa, um hospital, etc.).

Clousures
Uma clousure define um escopo de execução.
Veja por exemplo:
<html>
<head>
<title></title>
</head>
<body>
<script language="JavaScript">
function init(){
    document.write("window scope"+'<br>');
}
(function(){
    function init(){
        document.write("local scope"+'<br>');
    }
    init();//local scope
    window.init();//a função interna acessa o window scope
}());
</script>
</body>
</html>
Reultado:
local scope
window scop

Foi declarada duas funções com o mesmo nome: init. A função normal pertence ao escopo geral e não pode acessar o escopo local e a função anônima e imediata cria um escopo local e pode acessar o escopo geral. Por existirem em escopos diferentes uma função não interfere na outra e pode coexistir em um código.
Tudo o que for declarado no escopo window é acessível de qualquer escopo, pois window é o root, o que for declarado no escopo local só é acessível no escopo local.

<html>
<head>
<title></title>
</head>
<body>
<script language="JavaScript">
function init(){
    document.write("window scope"+'<br>');
}

(function(){
    function init(){
        document.write("local scope"+'<br>');
    }
}());
    init();//window scope
    window.init();//window scope
</script>
</body>
</html>
Resultado:
window scope
window scope

Conclusão: o escopo local acessa o escopo geral, o escopo geral não acessa o escopo local.

O trecho de código abaixo mostra que uma função anônima pode retornar uma função que por sua vez retorna uma variável sem herança.
Uma variável pura não é herdável diretamente, necessita de um metodo: function(){...}

Exemplo:
Para acessar a variável email necessita-se dos métodos getEmail() e setEmail().
var usuario = function () {
  var email = “iurimadeira@gmail.com”;// Escopo privado ou local
  return {
        getEmail : function () {
        return email;
       },
       setEmail : function (newEmail) {
       email = newEmail;
       }
   }
}();
alert(usuario.email); // Undefined, email, variável pura não é herdável diretamente, necessita de um metodo: function(){...}
alert(usuario.getEmail()); // “iurimadeira@gmail.com”
usuario.setEmail(“outro@exemplo.com”);
alert(usuario.getEmail()); // “outro@exemplo.com”
- A função anônima retorna (return) os métodos getEmail() e setEmail().
- Após declarar a função anônima, usamos o () para auto-invocar a função.
- A variável email é privada porque foi declarada com a expressão var dentro da função anônima.
- Os métodos getEmail() e setEmail() e a variável email estão no mesmo escopo interno.

4.2. Hoisting
Em JavaScript, funções e variáveis são hoisted. Hoisting é um comportamento do JavaScript, o interpretador move as declarações para o topo de um escopo global ou escopo da função em que se encontra. Não importa o local onde foi declarada uma função ou variável nem em qual ordem, será movida para o lugar mais alto do seu escopo. O escopo de uma variável ou função no JavaScript são as linhas de código em que estas são acessíveis.
hoist (hɔɪst):  v. içar (um objeto, uma carga, etc)
host (hoʊst): s. 1. anfitrião (triã), 2. apresentador (a), 3. host city sede; v. 1. sediar, 2. apresentar (show).

4.2.1. Escopo de Variáveis
Como as declarações de variáveis em geral são processadas antes de qualquer código ser executado, declarar uma variável em qualquer lugar no código é equivalente a declarar no inicio. Isso também significa que uma variável pode aparecer para ser usada antes dela ser declarada. Esse comportamento é chamado de hoisting, a variável é movida para o inicio da função ou do código global.

Uma diferença importante entre declarações de funções das declarações de classes, é que  declarações de  funções são hoisted e declarações de classes não são. Primeiramente deve declarar sua classe para só então acessá-la, pois do contrário o código irá lançar uma exceção: ReferenceError:

O JavaScript não suporta escopo de bloco (no qual um conjunto de chaves {. . .} define um novo escopo), exceto em caso especial de variáveis com escopo em bloco.
Encapsulamento é um dos fundamentos da programação orientada a objetos tradicional é uma forma de restringir acesso à informação.

4.2.2. Declaração e Nomes no Escopo
Existem 4 maneiras de um nome entrar em um escopo em JavaScript:
- Definido pela linguagem: todo escopo possui o this, e caso seja uma função, também o arguments.
- Parâmetros de uma função: caso uma função seja chamada na forma foo(a, b), a e b entram no escopo da função.
- Declaração de uma função: funções declaradas na forma function foo() {}.
- Declaração de uma variável: variáveis declaradas como var pertence ao escopo onde foram declaradas.
Porém, para cada diferente método de entrada no escopo há diferença na ordem de resolução de nomes. Alguns podem ser resolvidos primeiro mesmo aparecendo ao fim do escopo, enquanto outros podem ter apenas seus nomes resolvidos, sem ter seus valores inicializados. E é esse comportamento não explicito de resolução de nomes e inicialização de valores do JavaScript que foi batizado como hoisting por Ben Cherry.

4.2.2.1. Variable hoisting
Toda vez que uma variável é definida, sua declaração é hoisted, mas não sua inicialização. O que quer dizer que a declaração da variável vai para cima do escopo antes mesmo do código ser executado, mas esta variável não recebe nenhum valor e permanece como undefined.
Exemplo:
// Irá imprimir o erro dentro do `catch`
<script>
try {
  console.log(a);
} catch (e) {
  console.error("A variável 'a' não foi definida.");
}
</script>

Exemplo:
<script>
try {
  var a;
  console.log(a); //undefined
  a = 2;
} catch (e) {
  console.error("'a' não existe no contexto atual");
}
</script>
Reparem no código acima que no penútimo exemplo, quando tentamos imprimir o valor de a, recebemos um erro pois esta variável não existe. Já no último exemplo, undefined será impresso, mesmo tendo a declaração de a depois do comando console.log. Ali ocorreu um hoisting da declaração da variável a, mas não da sua inicialização, ou seja, a = undefined, não gera o erro.
APENAS A DECLARAÇÃO DE UMA VARIÁVEL É HOISTED, NÃO SUA INICIALIZAÇÃO.

4.2.2.2. Function hoisting
O hosting com funções acontece de maneira diferente. Aqui, não só o nome da função é hoisted como também seu corpo.
Exemplo:
foo();
function foo() {
  console.log('bar')
}
O código acima irá imprimir bar, sem nenhum erro. Mesmo executando uma função antes mesmo de ser definida. Isso porque tanto o nome da função como seu corpo são hoisted.

Vamos analisar o próximo exemplo e verificar  por que seu output é 8:
Exemplo:
function foo(){
      function bar() {
      return 3
     }
return bar()
     function bar() {
     return 8
    }
}
console.log(foo());

Dentro do escopo da função foo, primeiro temos a definição da função bar que já está no topo. Depois do return temos uma outra definição de função com o nome de bar. Apesar de aparecer ao fim do escopo, ela é hoisted — vai para o topo antes da execução. Como ela é a segunda função com o mesmo nome, ela acaba por sobreescrever a primeira, e o nome bar acaba por fazer referência à segunda função.

4.2.2.3. Expressão de Função
Uma expressão de função define uma função como parte de uma expressão sintática maior, geralmente uma atribuição de variável. Funções definidas com expressões de função podem ter nome ou serem anônimas.
- Não podem iniciar por function, por isso os parênteses são usados na "auto invocação"
- A expressão termina com ponto e vírgula como sempre é feito.
- A função pode ser chamada pelo nome da variável mais o para de parenteses.
Expressão anônima de função:
var a = function() {
   return 3;
};
ou
var somaDoisNumeros = function(numero1, numero2) {
   return numero1 + numero2;
};
somaDoisNumeros(10,20); //chamada da função pelo nome da variável

Uma função pode ser declarada como expressão e obedece a regra de hoisting da variável. Apenas o nome da variável será hoisted.
Repare que a variável recebe como parâmetro um bloco de função sem nome, isto é, uma função anômima. Outra peculiaridade é que a declaração termina com ponto e vírgula. Como a função é anônima, a única maneira de invocá-la é através da variável que a guarda.

Expressão nominada de função:
var a = function bar() {
   return 3;
}

Expressão "autoinvocada" de função:
(function digaOi() {
    alert("Oi!");
})();

Exemplo:
foo() // TypeError
var foo = function() {}
No exemplo acima será disparado um erro do tipo TypeError, nos avisando que undefined não pode ser usado como uma função.

Function Expression Vs Function Declaration
As duas formas possuem o mesmo resultado, a diferença está em seu carregamento pelo navegador.

somaDoisNumeros(10, 20);
function somaDoisNumeros(num1, num2) {
  return num1 + num2;
}
O código acima funciona, mesmo chamando a função antes de sua declaração. Já o código a seguir gera um erro:

somaDoisNumeros(10, 20); // erro, função não foi declarada ainda
var somaDoisNumeros = function(num1, num2) {
  return num1 + num2;
};
Isso ocorre devido a um processo chamado hoisting (levantamento, içamento). Function declarations são 'içadas' até o topo do script pelo JavaScript. A mesma coisa são feitas com variáveis, mas a diferença é que apenas as declarações são 'içadas' até o topo do script, isto é, seu conteúdo continuam como 'undefined'. É como se o interpretador fizesse isso:

var somaDoisNumeros;
somaDoisNumeros();
somaDoisNumeros = function(num1, num2) {
  return num1 + num2;
};

Exemplo de loop de função:
Calcula o fatorial de 3.
<html>
<head>
<title></title>
</head>
<body>
<script language="JavaScript">
var fatorial = function fac(n) {return n<2 ? 1 : n*fac(n-1)};
console.log(fatorial(4));
</script>
</body>
</html>
Resultado:
24
Obs: return n*(n-1)*(n-2)*(n-3)...

Exemplo:
As expressões de função são convenientes ao passar uma função como um argumento para outra função. O exemplo a seguir mostra uma função de nome map sendo definida e, em seguida, chamada com uma função anônima como seu primeiro parâmetro:
<html>
<head>
<title></title>
</head>
<body>
<script language="JavaScript">
function map(f,a) {
  var result = []; // Cria um novo Array
  var i;
  for (i = 0; i != a.length; i++)
    result[i] = f(a[i]); //result=[f(a[0]), f(a[1]), f(a[2]),...]
  return result;
}
y=map(function(x) {return x * x * x}, [0, 1, 2, 5, 10]);//argumento para a função map
console.log(y);
document.write(y);
</script>
</body>
</html>
Resultado:
0,1,8,125,1000

Exemplo:
Em JavaScript, uma função pode ser definida com base numa condição. Por exemplo, a seguinte definição de função define minhaFuncao somente se num  é igual a 0:
var minhaFuncao;
if (num == 0){
  minhaFuncao = function(objeto) {
    objeto.make = "Toyota"
  }
}
4.3. Encapsulamento
Encapsulamento também conhecido como o ato de "esconder informação" é um conceito fundamental em todas as linguagens orientadas a objeto. Javascript tem mecanismos de encapsulamento embora não possua um private accessors.

Digamos que você tem um dinheiro no cofre sua casa e você não quer que ninguém saiba quanto existe nele, mas, ao mesmo tempo, quer que as pessoas possam depositar e sacar dinheiro.

function createVault(yourSecretMoney){ 
  var myVault = {}; //seu cofre, variável com escopo local
  var mySecretMoney = yourSecretMoney; //seu dinheiro secreto, variável com escopo local

  function sacar(x){
    if(!mySecretMoney){
      console.log("O cofre não tem mais dinheiro");
      return 0;
    }
    if(mySecretMoney - x < 0){
      console.log("Não temos a quantia solicitada.");
      return 0;
    }

    mySecretMoney = mySecretMoney - x;
    console.log("Você sacou R$" + x);
    return x;
  }

  function depositar(x){
    mySecretMoney = mySecretMoney + x;
    console.log("Obrigado!");
  }

  myVault.sacar = sacar;
  myVault.depositar = depositar;

return myVault;
}

var pig = createVault(10); 
pig.sacar(2); //Você sacou R$2 
pig.sacar(9);  //Não temos a quantia solicitada 
pig.depositar(3); // Obrigado! 
pig.sacar(9);  // Você sacou R$9 

5. Parameters

O ECMAScript 6 criou dois tipos novos de parâmetros de função: parâmetros padrão e parâmetros rest.
5.1. Parâmetros Padrão
Em JavaScript, parâmetros padrões de funções são undefined. No entanto, em algumas situações pode ser útil definir um valor padrão diferente.
Em versões anteriores a estratégia geral para definir padrões era testar os valores de parâmetro no corpo da função e atribuir um valor se eles fossem undefined. Se, no exemplo a seguir, nenhum valor é fornecido para b na chamada, seu valor seria undefined ao avaliar a*b e a chamada para multiplicar retornaria NaN. Isso é feito com a segunda linha neste exemplo:
Exemplo 1:
function multiplicar(a, b) {
  b = typeof b !== 'undefined' ?  b : 1;
  return a*b;
}
multiplicar(5); // 5

Exemplo 2:
Algo muito comum ao desenvolvermos é verificar a presença de uma váriavel e caso ela não exista, inicializamos com um valor, assim como no código abaixo:

<script>
function hello(nome,cidade){
  Nome = nome || "Caio";
  Cidade = cidade || "São Paulo";
  console.log("Sou "+Nome+ " e moro em "+Cidade);
}
hello(); // Sou Caio e moro em São Paulo
</script>

Default Parameters
Com parâmetros padrão, a verificação no corpo da função não é mais necessária. Pode simplesmente colocar 1 como valor padrão para b no campo de declaração de parâmetros:

function multiplicar(a, b = 1) {
  return a*b;
}
multiplicar(5); // 5

5.2. Rest Parameters
Em JavaScript sempre pudemos passar quantos parâmetros quiséssemos para uma função por meio de argumentos:
<html>
<head>
<title></title>
</head>
<body>
<script language="JavaScript">
function somaContaDoCliente(cliente, moeda, valores){
  var i = 2;
  var tamanho = arguments.length;
  var resultado = 0;

  while (i < tamanho) {
   resultado += arguments[i];
   i++;
  }
console.log("A conta do cliente "+cliente+ " totalizou "+moeda+ resultado);
document.write("A conta do cliente "+cliente+ " totalizou "+moeda+ resultado);
}
somaContaDoCliente("Caio","R$",1,2,3,4,5); // A conta do cliente Caio totalizou R$15
</script>
</body>
</html>
Resultado:
A conta do cliente Caio totalizou R$15

Repare que no código acima precisamos lembrar da posição que começa nosso valores, mas e se adicionarmos mais um parâmetro no futuro? Precisaríamos lembrar de alterar o índice que usamos, mas será que só pelo nome da variável, lembraríamos que ali pode estar uma quantidade indefinida de valores?

Pensando isto, foi criado o Rest Parameters, onde nós podemos realizar isso de um modo mais interessante, pois não precisamos mais acessar o array arguments e verificar as posições dele, o parâmetro que pode receber vários valores é precedido por três pontos(…) e precisa ser sempre o último parâmetro da função:
<html>
<head>
<title></title>
</head>
<body>
<script language="JavaScript">
function somaContaDoCliente(cliente, moeda, ...valores){
  var resultado = 0;
  var i = 0;
  while (i < valores.length) {
    resultado += valores[i];
    i++;
  }
console.log("A conta do cliente "+cliente+ " totalizou "+moeda+ resultado);
document.write("A conta do cliente "+cliente+ " totalizou "+moeda+ resultado+'<br>');
}
somaContaDoCliente("Caio","R$",1,20,3,4,5);
somaContaDoCliente("Maria","R$",1,2,3,4,1,1,1,1);

</script>
</body>
</html>
Resultado:
A conta do cliente Caio totalizou R$33
A conta do cliente Maria totalizou R$14

Repare que ficou mais simples, não nos preocupamos com o índice e ainda está bem claro que o valores é um parâmetro especial que recebe um ou mais números.

6. Parser

O parser é um analisador sintático. Sua função é ler uma entrada de dados que possuem certas regras específicas - em geral é um texto reconhecível por humanos - e montar uma estrutura de como é sua composição. Obviamente uma de suas funções é "enxergar" erros cometidos e recusar as entradas que não estejam dentro das regras.
parse: significa análisar.
Ele é o centro do compilador de todas as linguagens de programação e marcação, como é o caso do HTML, CSS e JS. Neste contexto, ele é o segundo passo para ter um texto traduzido para algo que o computador entenda. Ele usa uma gramática com as regras que devem ser usadas. Podemos dizer que ele procura entender e separar o que é o substantivo, verbo, adjetivo, pronome, conjunção, pontuação, etc. Em geral uma árvore é montada com todos os elementos encontrados. Isso se ele não encontrar uma estrutura incompatível com as regras. Em alguns casos é possível ignorar parte da árvore e usar o que deu certo.

Função 1:
function teste(valor){
    return (valor > 1) ? true : false;
}

Função 2:
var teste = function(valor){ // função anônima atribuida a uma variável.
    return (valor > 1) ? true : false;
}
A função 1 é defenida quando o script é analizado (parse time) e a função 2 quando é executado (run-time).

7. Funções Aninhadas

Você pode aninhar uma função dentro de outra. A função aninhada (interna) é acessível apenas para a função que a contém (exterior). Isso constitui também uma closure. Uma closure é uma expressão (tipicamente uma função) que pode ter variáveis livres em conjunto com um ambiente que conecta estas variáveis (que "fecha" a expressão).

Uma vez que uma função aninhada é uma closure, isto significa que uma função aninhada pode "herdar" os argumentos e variáveis de sua função de contenção. Em outras palavras, a função interior contém o escopo da função exterior.

Em resumo:
A função interna só pode ser acessada de dentro da função externa.
A função interna forma uma closure: a função  interna pode usar os argumentos e variáveis da função externa, enquanto a função externa não pode usar os argumentos e variáveis da função interna.
O exemplo a seguir mostra as funções aninhadas:
function addSquares(a,b) {
   function square(x) {
      return x * x;
   }
   return square(a) + square(b);
}
a = addSquares(2,3); // retorna 13
b = addSquares(3,4); // retorna 25
c = addSquares(4,5); // retorna 41

Uma vez que a função interna forma uma closure, você pode chamar a função externa e especificar argumentos para a função externa e interna:
function fora(x) {
   function dentro(y) {
      return x + y;
   }
   return dentro;
}
Observe como x é preservado quando a função dentro é retornada. Uma closure deve preservar os argumentos e variáveis em todos os escopos que ela referencia. Uma vez que cada chamada fornece potencialmente argumentos diferentes, uma nova closure é criada para cada chamada de fora. A memória só poderá ser liberada quando a função dentro retornada já não é mais acessível.

Isso não é diferente de armazenar referências em outros objetos, mas muitas vezes é menos óbvio, porque um não define diretamente as referências e não pode inspecioná-las.

7.1. Múltiplas funções aninhadas
Funções podem ter múltiplo aninhamento, por exemplo, a função (A) contém a função (B) que contém a função (C). Tanto as funções B e C formam uma closure, então B pode acessar A, e C pode acessar B. Além disso, uma vez que C pode acessar B que pode acessar A, C também pode acessar A. Assim, a closure pode conter vários escopos; eles recursivamente contém o escopo das funções que os contém. Isso é chamado encadeamento de escopo.

Considere o seguinte exemplo:
function A(x) {
   function B(y) {
      function C(z) {
         alert(x + y + z);
      }
      C(3);
   }
   B(2);
}
A(1); // Exibe um alerta com o valor 6 (1 + 2 + 3)

Neste exemplo, C acessa y do B e x do A.
Isso pode ser feito porque:
B forma uma closure incluindo A, isto é, B pode acessar argumentos e variáveis de A.
C forma uma closure incluindo B.
Devido a closure B inclui A, a closure C inclui A, C pode acessar tanto argumentos e variáveis de B como de A. Em outras palavras, C encadeia o escopo de B e A, nesta ordem.
O inverso, no entanto, não é verdadeiro. A não pode acessar C, porque A não pode acessar qualquer argumento ou variável de B.
7.2. Conflitos de Nome
Quando dois argumentos ou variáveis nos escopos da closure tem o mesmo nome, há um conflito de nome. Mas escopos internos tem prioridade, por isso o escopo mais interno tem a maior prioridade, enquanto que o escopo mais externo tem a menor. Esta é a cadeia de escopo. O primeiro da cadeia é o escopo mais interno, e o último é o escopo mais externo.

Considere o seguinte:
function fora() {
   var x = 10;
   function dentro(x) {
      return x;
   }
   return dentro;
}
result = fora()(20); // retorna 20 em vez de 10
O  conflito de nome acontece na declaração return x e está entre o parâmetro x de dentro e a variável x de fora. A cadeia de escopo aqui é {dentro, fora, objeto global}. Por isso o x de dentro tem precedência sobre o x de fora, e 20 (x de dentro) é retornado em vez de 10 (x de fora).

Exemplo:
<!DOCTYPE html>
<html>
<head>
<body>
<script type="text/javascript">
function hypotenuse(a,b){
     function square(x){ return x*x; }
return Math.sqrt(square(a) + square(b));
}
           
     function secondFunction(){
     var result;
     result = hypotenuse(1,2);
     console.log(result);
 }
secondFunction(); // 2.23606797749979
</script>
</body>
</html>

8. Usando Objeto de Argumentos

Os argumentos de uma função são mantidos em um objeto do tipo array. Dentro de uma função, você pode endereçar os argumentos passados para a função conforme:
arguments[i]
onde i é um número ordinal do argumento, começando com zero. Então, o primeiro argumento passado para a função seria argumentos[0]. O número total de argumentos é indicado por arguments.length.

Usando o objeto arguments, você pode chamar a função com mais argumentos do que na sua declaração. Isso muitas vezes é útil se você não sabe de antemão quantos argumentos serão passados para a função. Você pode usar arguments.length para determinar a quantidade de argumentos passados para a função, e então acessar cada argumento usando o objeto arguments.

Por exemplo, considere uma função que concatena várias strings. O argumento formal para a função é uma string que especifica os caracteres que separam os itens para concatenar.  A função fica definida assim:

function myConcat(separador) {
   var result = "", i; // declara a variável result como vazia e declara a variável i.
   for (i = 1; i < arguments.length; i++) { // itera por meio de argumentos
      result += arguments[i] + separador; //result = arguments[0] + separador 
   }                                                           //result = arguments[0] + separador  + arguments[1] + separador
   return result;  // Você pode passar qualquer quantidade de argumentos para esta função, e ela concatena cada argumento na string "list":
}                                                            
myConcat(", ", "red", "orange", "blue"); // retorna "red, orange, blue, "
myConcat("; ", "elephant", "giraffe", "lion", "cheetah"); // retorna "elephant; giraffe; lion; cheetah; "
myConcat(". ", "sage", "basil", "oregano", "pepper", "parsley"); // retorna "sage. basil. oregano. pepper. parsley. "

Nota: A variável arguments é "como um array", mas não é um array. Ela parece um array pois possui um índice numerado e a propriedade length. No entanto, não possui todos os métodos de manipulação de array.

9. Diferença entre Objeto literal e Objeto Construtor

Diferenças entre os dois métodos de criação de objetos. Vamos comparar estruturas semelhantes utilizando Object Literal e Constructors (new):

<script type="text/javascript">
var object_literal = {
    Automovel: {quantidadeRodas: 4
                }
};

var constructor = {
    Automovel: function() {
        this.quantidadeRodas = 4;
    }
};

var carro = object_literal.Automovel;
console.log('quantidade de rodas:', carro.quantidadeRodas); // 4

var carro = new constructor.Automovel();
console.log('quantidade de rodas:', carro.quantidadeRodas); // 4
</script>
Acima já reparamos numa das maiores vantagens do Object Literal: criar namespaces. Isolamos as duas declarações para que possamos usar os mesmos nomes:

Acessar quantidadeRodas de object_literal.Automovel é muito mais fácil do que constructor.Automovel. Não é errado dizer que quantidadeRodas de constructor.Automovel é um “atributo de instância”, logo, é necessário criar uma instância da classe para acessá-lo.

Os métodos entram em ação:
Vamos atribuir aos nossos automóveis a capacidade de ligarMotor
<script type="text/javascript">
var object_literal = {
    Automovel: {
        quantidadeRodas: 4,
        motorLigado: false,

        ligarMotor: function() {
            //object_literal.Automovel.motorLigado = true;
            this.motorLigado = true;
        }
    }
};

var constructor = {
    Automovel: function() {//não é método é closure
        this.quantidadeRodas = 4;
        this.motorLigado = false;
    }
};
//aqui a função é método
constructor.Automovel.prototype.ligarMotor = function() {
    this.motorLigado = true;
}; //repare no ponto e vírgula, pois é uma atribuição
var carro = object_literal.Automovel;
carro.ligarMotor();
console.log('motor ligado:', carro.motorLigado); // true

var carro = new constructor.Automovel();
carro.ligarMotor();
console.log('motor ligado:', carro.motorLigado); // true
</script>

Aqui que as diferenças começam a ficar mais visível.
Por não conseguirmos criar uma instância de um Object Literal (afinal de contas, ele já é um objeto), não conseguimos fazer uma referência this como em classes, não temos a definição de atributos e métodos via Prototype. Se o fizéssemos, estaríamos explorando atributos da função anônima associada à propriedade ligarMotor, da propriedade Automovel, da variável object_literal. Mas, conseguimos sim explorar atributos e métodos do objeto através do this. O mesmo ocorre em ligarMotor de constructor, o this é capaz de acessar os valores e métodos nas instâncias de Automovel:

Sabemos que um automóvel pode ter 2, 4, 6 ou até 8 rodas, então vamos adaptá-los:

var constructor = {
    Automovel: function(qtndRodas) {
        this.quantidadeRodas = qtndRodas;
        this.motorLigado = false;
    }
};

O objeto literal não tem instância, temos de alterar diretamente o seu valor.
// object literal
var moto = object_literal.Automovel;
moto.quantidadeRodas = 2;
console.log('quantidade de rodas (moto):', moto.quantidadeRodas); // 2

// constructor function
var moto = new constructor.Automovel(2);
console.log('quantidade de rodas (moto):', moto.quantidadeRodas); // 2

// object literal
console.log('quantidade de rodas (carro):', carro.quantidadeRodas); // 2

// constructor function
console.log('quantidade de rodas (carro):', carro.quantidadeRodas); // 4

A implementação ficará assim:

<script type="text/javascript">
var object_literal = {
    Automovel: {
        quantidadeRodas: 4,
        motorLigado: false,

        ligarMotor: function() {
        this.motorLigado = true;
        }
    }
};

var constructor = {
    Automovel: function(qtRodas) {
        this.quantidadeRodas = qtRodas;
        this.motorLigado = false;
    }
};

constructor.Automovel.prototype.ligarMotor = function() {
    this.motorLigado = true;
};

var carro = object_literal.Automovel;
carro.ligarMotor();
console.log('motor ligado:', carro.motorLigado); // true
console.log('quantidade de rodas (carro):', carro.quantidadeRodas);

var carro = new constructor.Automovel(6);
carro.ligarMotor();
console.log('motor ligado:', carro.motorLigado); // true
console.log('quantidade de rodas (carro):', carro.quantidadeRodas); // 6

var moto = object_literal.Automovel;
moto.quantidadeRodas = 2;
console.log('quantidade de rodas (moto):', moto.quantidadeRodas); // 2

var moto = new constructor.Automovel(2);
console.log('quantidade de rodas (moto):', moto.quantidadeRodas); // 2
</script>

Instâncias x Referências
Com uso de Constructor Functions, criamos uma “estrutura” (classe), que a cada new é “copiada” para um novo espaço na memória (instância). Assim, a propriedade quantidadeRodas de moto é diferente da propriedade de mesmo nome, da instância carro.

Constructor function
console.log('carro == moto:', carro == moto) // false
Já com Object Literal, não temos a capacidade de criar uma classe. Criamos diretamente uma instância, e vinculamos o espaço na memória onde esta foi criada à uma variável. No nosso caso, a variável em questão é object_literal.Automovel.

Quando atribuímos object_literal.Automovel à variável carro e depois à variável moto, na verdade estávamos criando referências a instânca contida em object_literal.Automovel (ou seja, as três variáveis correspondem ao mesmo endereço e valor na memória):
Object literal
console.log('carro == moto:', carro == moto) // true
Considerações finais:
Então, quando você tiver um tipo que possuirá várias instâncias, utilize Constructor Functions. Quando quiser criar objetos “estáticos”, que não sofrerão alterações no decorrer de uma execução (como o exemplo do namespace), utilize Object Literal.

10. Revisão: Operador ||

O operador lógico or é escrito como duas barras verticais, assim no JavaScript: ||. Ele resulta em true quando um, ou as duas expressões são true, senão retorna false:
Expressão
Retorno
true || true true
true || false true
false || true true
false || false false

Exemplo:
var tired=true;
var bored=false;

var nap = function(){
if(tired || bored){
return true;
}else{
return false;
}
};

Chama se coalescência essa relação, é sinônimo de: fusão, junção, aglutinação.
var resultado = valorA || valorB;
É exatamente o mesmo que:
var resultado = valorA ? valorA : valorB;
se resultado = valorA é true então resultado = valorA senão resultado = valorB;

Acontece que no javascript, praticamente todos os valores podem ser tratados de forma lógica, ou seja, convertidos para verdadeiro ou falso. Quanto à operação anterior, quando o valor valorA é tratado como verdadeiro, o resultado da expressão é o seu próprio valorA. Quando é tratado como falso, o resultado da expressão é valorB.
Devemos então entender o que é tratado como verdadeiro e como falso.
O que é falso:
é false
Explicação
""
string vazia
0
número zero
false

null

undefined

NaN


O JavaScript, internamente, trata os valores true e false como 1 e 0, respectivamente.
O que é verdadeiro:
é true
Explicação
!false
tudo que não for false
"x"
string não vazia
...-2,-1,1,2...
todos nºs diferentes de zero
true


Alguns exemplos:
false || "texto qualquer";     // false || true    retorna "texto qualquer" (true)
"" || "texto qualquer";        // false || true     retorna "texto qualquer" (true)
0 || "texto qualquer";         // false || true     retorna "texto qualquer" (true)
null || "texto qualquer";      // false || true    retorna "texto qualquer" (true)
undefined || "texto qualquer"; // false || true      retorna "texto qualquer" (true)

"algum texto" || "texto qualquer"; // true || true    retorna  "algum texto"
1 || "texto qualquer";   // // true || true    retorna  1

11. Espaço de Nomes (name space) e Módulos

Variáveis, objetos e funções podem ser referênciados por um mesmo nome que divide o acesso aos mesmo por categoria afim de melhorar a organização, a funcionalidade, a reutilização de código, a compreensibilidade e sobretudo a segurança ou acessibilidade do código. Essa estrutura de código quando separada em um arquivo independente se chama MÓDULO.
A forma mais simples de garantir a segurança do NameSpace é através de um objeto literal ou através de uma função anônima, pois ambos não fornece instâncias e possuem escopo local.

O atributo SRC permite chamar um arquivo de scripts externo (arquivos com extensão ".js" ).  A fim de facilitar a manutenção, recomenda-se armazenar as funções Javascript de uma página em um arquivo separado, que pode ser incluído no documento HTML com a construção abaixo:
<SCRIPT LANGUAGE="javascript" SRC="arquivo.js"></SCRIPT>
 
11.1. Usando Objeto Literal e Função Anônima
Características:
Uma das possibilidades para criar espaço de nome é utilizando objeto literal porque não pode ser criado uma instância desse objeto. Um nome tem de ser único, isso quer dizer ques as propriedades desse objeto são acessíveis somente pelo seu nome.
A função anônima cria um escopo local capaz de garantir a segurança dos componentes do objeto.
Definimos um módulo através de:
- A criação de um objeto, que conterá o “nome” do módulo;
- A criação de uma função anônima auto-invocada, para poder conter o escopo do módulo e suas variáveis “privadas”;
Por exemplo, iremos criar o módulo js2.js no bloco de notas do Windows, que conterá as funções que comumente utilizamos em todas as aplicações. Iremos usar o objeto glc:

//Declaração do “nome” do módulo
var glc = {} || glc;
(function() {
    //Corpo do módulo
})();
A sintaxe de declaração com o operador de OR funciona da seguinte forma. Se já existir uma variável glc declarada, o JavaScript irá utiliza-la. Caso não exista, ele irá declarar um objeto em branco. Isso permite que um módulo seja dividido em vários arquivos, caso necessário.

Podemos incluir funções e variáveis na área do corpo do módulo. Elas serão consideradas privadas, a menos que sejam inseridas como atributos do objeto glc. O exemplo abaixo mostra 2 funções, uma privada e uma publica:

//Declaração do “nome” do módulo
var glc = {} || glc;
(function() {
    var privada = function() {
        alert("privada!");
    }
    glc.publica = function() {
        alert("publica!");
    }  
})();
Note que graças ao escopo lexico, o objeto glc, externo, será visível. Da mesma forma, todas as variáveis internas à função anônima serão preservadas devido ao escopo local.
Arquivo HTML, pode ter qualquer nome válido
Arquivo de nome js2.js
<!DOCTYPE html>
<html>
<head>
<SCRIPT LANGUAGE="javascript" SRC="js2.js"></SCRIPT>
</head>
<body>
<SCRIPT type="text/javascript">
function test() {
publica1();
glc.publica2();
}
test();
</script>
</body>
</html>
var glc = {}||glc;
(function() {
    var privada = function() {
        alert("privada!");
    }
 
    publica1 = function() {
        alert("publica1!");
    } 
    glc.publica2 = function() {
        alert("publica2!");
    }
})();

// espaco de nomes global//
var MEUAPP = MEUAPP || {};
No código acima, primeiro verificamos se MEUAPP já está definido (no mesmo arquivo ou em outro). Se estiver, usamos o objeto MEUAPP global existente. Caso contrário, criamos um objeto vazio chamado MEUAPP, que encapsula métodos, variáveis e objetos.

Podemos também criar sub-espaços de nomes.
// sub espaço de nomes
MEUAPP.eventos = {};

11.2. Uma Função Anônima
No item 1.4 dessa apostila foi ressaltado que:
Uma grande vantagem de passar parâmetros para uma função imediata (IIFE), é que esse valor é passado como uma cópia, e não como uma referência. Isto significa que se alterarmos o valor desse parâmetro dentro da IIFE, esse valor não vai persistir fora dela.

O escopo da função anônima é local, ela altera o valor de uma variável global, porém só dentro de seu escopo essa alteração vale.
Isso é bom para criar cópias de variaveis globais, e garantir que se alguem sobreescrever essa variável, isso não vai influenciar o módulo que foi criado. Esse comportamento também é conhecido como Closure.
Uma função anônima não é apropriada para fazer um NameSpace, simplesmente porque não tem nome.

Arquivo HTML, pode ter qualquer nome válido
Arquivo de nome js2.js
<!DOCTYPE html>
<html>
<head>
<SCRIPT LANGUAGE="javascript" SRC="js2.js"></SCRIPT>
</head>
<body>
<SCRIPT type="text/javascript">
function test() {
publica1();
glc.publica2();
}
test();
</script>
</body>
</html>
variavel=(function() {
    var privada = function() {
        alert("privada!");
    }
 
    publica1 = function() {
        alert("publica1!");
    } 
    glc.publica2 = function() {
        alert("publica2!");
    }
})();

Exemplo de módulo, repare que não possui nome e referência:
Somente com funções anônimas é possível fazer módulo, espaço de nome  não é possível porque funções não são acessíveis por referência. Pode-se chamar a função com o nome da variável.
Arquivo HTML, pode ter qualquer nome válido
Arquivo de nome js2.js
<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
    <button id="btnSomar"> Somar </button>
    <button id="btnSubtrair"> Subtrair </button>
    <br />
    <span id="valor"></span>
</body>
<script src="module.js"></script>
<script type="text/javascript">
    function loadPage () {
        var btnSomar, btnSubtrair;
        btnSomar = document.getElementById('btnSomar').addEventListener("click", escrever);
        btnSubtrair = document.getElementById('btnSubtrair').addEventListener("click", escrever);
        function escrever(e){
            if (e.target.id == "btnSomar") {
                contador.soma();
            } else {
                contador.subtrai();
            };
            document.getElementById("valor").innerHTML = "O Valor de X é = " + contador.getX();
        }//End Function escrever
    }//End Function loadPage
    window.onload = loadPage();
</script>
</html>
var contador = (function() {
    var x = 0;
    function soma(){
        x += 1;
    }//End soma
    function subtrai(){
        x -= 1;
    }//End subtrai
    function getX (){
        return x
    }//End getX
    return {
        getX: getX,
        soma: soma,
        subtrai: subtrai
    }//End Return
})();//End Módulo
Foi adicionado dois botões na página html e um span para exibir o valor, foi adicionado também mais uma tag script onde a função loadPage é chamada.
Quando a função escrever é chamada é feito uma comparação para descobrir qual botão chamou “e.target.id” e chamar a função desejada do módulo.

11.3. Espaço de Nome com Atribuição Direta (Direct Assignment): nesse caso tem-se o nome e o módulo.
Essa é a abordagem mais básica, é segura e inequívoca.
Arquivo HTML, pode ter qualquer nome válido
Arquivo de nome js2.js
<!DOCTYPE html>
<html>
<head>
<SCRIPT LANGUAGE="javascript" SRC="js2.js"></SCRIPT>
</head>
<body>
<SCRIPT type="text/javascript">
function test() {
 window.console && console.log(
    myApp.next(),
    myApp.next(),
    myApp.reset(),
    myApp.next()
);
}
test();
</script>
</body>
</html>
var myApp = {};
myApp.id = 0;
 myApp.next = function() {
    return myApp.id++; 
}
 myApp.reset = function() {
    myApp.id = 0;  
}

Console:
 0, 1, undefined, 0


Explicação:
var myApp = {} objeto global e literal, embora vazio.
myApp.id = 0;
 myApp.next = function() { função expressão, não é hoist, possui return.
    return myApp.id++; 
}
 myApp.reset = function() { função expressão, não é hoist, não possui return.
    myApp.id = 0;  
}
 window.console && console.log(
    myApp.next(), primeira chamada, retorna 0.
    myApp.next(), segunda chamada, retorna 1.
    myApp.reset(), função expressão sem return undefined.
    myApp.next() terceira chamada, porém, variável modificada pela função myApp.reset().
); // 0, 1, undefined, 0

Você poderia tornar a manutenção futura um pouco mais fácil usando this para fazer referência a propriedades irmãs, mas isso é um pouco arriscado, já que não há nada que impeça suas funções no namespace de serem reatribuídas:

var myApp = {}
 myApp.id = 0;
 myApp.next = function() {
    return this.id++;  
}
 myApp.reset = function() {
    this.id = 0;   
}
 
myApp.next(); // 0
myApp.next(); // 1
var getNextId = myApp.next; //não pode atribuir uma referência a uma variável
getNextId(); // NaN

Explicação:
A propriedade global NaN é um valor especial que significa Not-A-Number (não é um número).
Existem duas formas de passar valores:
- Por valor: atribuir um valor à uma variável;
- Por referência: a) atribuir um valor à uma propriedade ou método de um objeto, ou b) passar argumentos para uma função (ou método de um objeto).
Por exemplo:
var string = 'uma string qualquer'
var obj = {}
No exemplo acima, foi atribuído o valor 'uma string qualquer' à variável string, e também atribuí um novo objeto à variável obj.
Existem alguns conceitos por detrás dessas atribuições:
O valor 'uma string qualquer' foi passado para a variável string por valor.
Já o objeto passado para a variável obj, foi passado por referência, obj está vazio, não possui propriedade.

Exemplo :
Usando função anônima.
Um problema comum associado a se ter apenas um namespace global é a probabilidade de nomes de variáveis se coincidirem. Em JavaScript esse problema pode ser facilmente evitado com a ajuda dos wrappers anônimos

(function() {
    // um "namespace" reservado

    window.foo = function() {
        // uma closure exposta
    };

})(); // executa a função imediatamente

Função sem nome são consideradas expressões; assim, a fim de serem acessíveis, elas precisam primeiro serem avaliadas.

( // avalia a função dentro dos parênteses
function() {}
) // e retorna o objeto da função
() // chama o resultado da avaliação
Há outras maneiras de avaliar e chamar expressões de função, que embora difiram na sintaxe, se comportam da mesma maneira.

// Alguns outros estilos para invocar diretamente
!function(){}()
+function(){}()
(function(){}());
// e assim por diante...

Revisão:
- JavaScript não suporta escopo em bloco; portanto, tudo que resta na linguagem é escopo de função.
- A única fonte de variáveis locais em JavaScript são parâmetros de funções e variáveis declaradas por meio da declaração var.
- Vejamos os exemplo abaixo sobre ecopos:
Sem this o escopo global e local são independentes
Com this.i=5 o escopo global é alterado pelo escopo local, a função tem escopo de chamada (argumento)
Com this.i=i o escopo global e o escopo local são alterados pelo escopo de chamada (argumento)
<!DOCTYPE html>
<html>
<head>
<SCRIPT type="text/javascript">
var i = 2; //escopo global
function test(i) {
i = 5; //escopo local
console.log(i);
}
test(10);//5 escopo local
console.log(i);//2 escopo global
</script>
</head>
<body>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<SCRIPT type="text/javascript">
var i = 2;//escopo global
function test(i) {
this.i = 5;//escopo local
console.log(i);//10
}
test(10);//10 escopo da chamada
console.log(i);//5 escopo global alterado
</script>
</head>
<body>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<SCRIPT type="text/javascript">
var i = 2;//escopo global
function test(i) {
this.i = i;//escopo local
console.log(i);
}
test(10);//10 escopo da chamada
console.log(i);//10escopo global alterado
</script>
</head>
<body>
</body>
</html>
Console:
5
2
Console:
10
5
Consosle:
10
10

- Todos escopos em JavaScript, incluindo o escopo global, tem o nome especial this, definidos em si, que se refere ao objeto atual.
- Escopos de função também tem o nome arguments, definido em si, e que contém os argumentos que foram passados para a função.

11.4. Padronização em Módulo
Significa divisão do código em partes e escopos afim de organizar e permitir uma FUNCIONALIDADE lógica sem a possibilidade de interferência não programada.
Cria-se objetos únicos com dados privados utilizando uma expressão de função imediatamente invocaca (IIFE: Immediatley Invoked Function Expression), cuja variáveis locais não são acessíveis fora da função.
Uma expressão de função imediatamente invocacada pode retornar um método com propriedades públicas.

Expressão de Função Imediatamente Invocaca = Nome + Função Anônima Auto-executável (imediata)

Padrão de Módulo Básico
var meuObj = (function(){
   //variáveis locais armazena dados privados
   return{
     //métodos e propriedades públicas
   };
}());
Isso significa que a função só existe por um momento, é executada, em seguida, é destruída.

O trecho de código abaixo utiliza uma expressão de função imediata que retorna outra função cuja parâmetros são iguais, possibilitando assim retornar um elemento de uma array.

var dayName = function() {
var names = ["Sunday", "Monday", "Tuesday", "Wednesday",Thursday", "Friday", "Saturday"];
return function(num) {
            return names[num];
            };
}();
console.log(dayName(3)); // → Wednesday
A função anônima retornar uma função que por sua vez retorna um elemento do array.
A variável names é local dentro da uma função anônima. Esta função é criada e chamada imediatamente, e seu retorno é outra função que possui um parâmetro tal que o retorno dessa outra função é a variável names com índice igual ao valor do parâmetro.

Um padrão similar é usado para isolar inteiramente código do mundo exterior. O módulo abaixo tem algum efeito, mas não fornece qualquer valor para outros módulos usarem.

(function() {
  function square(x) { return x * x; }
  var hundred = 100;
  console.log(square(hundred));
})(); // → 10000
Este código simplesmente imprime o quadrado de cem (no mundo real, este poderia ser um módulo que adiciona um método a algum prototype, ou configura algum widget em uma página da web). Ele encapsula seu código em uma função para, novamente, prevenir que as variáveis que ele usa internamente estejam no escopo global.

Objetos como namespaces
Agora imagine que o módulo dia-da-semana (day-of-the-week) precise fornecer não uma, mas duas funções, porque nós adicionamos uma função dayNumber que vai de um nome para um número. Nós podemos mais simplesmente retornar a função, mas devemos encapsular as duas funções em um objeto.

var weekDay = function() {
var names = ["Sunday", "Monday", "Tuesday", "Wednesday","Thursday", "Friday", "Saturday"];
return {
  name: function(number) { return names[number]; },
  number: function(name) { return names.indexOf(name); }
  };
}();
console.log(weekDay.name(weekDay.number("Sunday"))); // → Sunday
Para módulos maiores, juntar todos os módulos exportados em um objeto no fim da função se torna algo incômodo, e geralmente requer que façamos algo repetido. Isso pode ser melhorado declarando um objeto, usualmente nomeado exports, e adicionando propriedades a este objeto sempre que nós definirmos algo que precise ser exportado. Este objeto pode então ser retornado, ou aceito como um parâmetro armazenado em algum lugar pelo código exterior ao módulo.

(function(exports) {
var names = ["Sunday", "Monday", "Tuesday", "Wednesday","Thursday", "Friday", "Saturday"];
  exports.name = function(number) {
    return names[number];
  };
  exports.number = function(name) {
    return names.indexOf(name);
  };
})(window.weekDay = {});

console.log(weekDay.name(weekDay.number("Saturday"))); // → Saturday

Avaliando dados como código
Existem várias formas de se pegar dados (uma string de código) e rodá-los no contexto do programa atual.
A mais óbvia maneira é o operador padrão especial eval, que vai executar a string de código no escopo atual. Isso usualmente é uma ideia muito ruim, porque quebra algumas propriedades que escopos normalmente tem (ser isolado do mundo externo é a mais notável).

function evalAndReturnX(code) {
  eval(code);
  return x;
}
console.log(evalAndReturnX("var x = 2")); // → 2

A melhor forma de converter dados dentro do programa é usar uma função construtora. Ela recebe como argumentos uma lista de nomes de argumentos separados por vírgula, e então uma string contendo o corpo da função.

var plusOne = new Function("n", "return n + 1;");
console.log(plusOne(4)); // → 5
Isso é precisamente o que precisamos - podemos encapsular o código para um módulo em uma função, com este escopo de função se tornando nosso escopo de módulo.

Require
Se a nova função construtora, usada pelo nosso módulo de carregamento, encapsula o código em uma função de qualquer forma, nós podemos omitir a função namespace encapsuladora atual dos arquivos. Nós também vamos fazer exports um argumento à função módulo, então o módulo não precisará de declarar isso. Isso remove um monte de barulho supérfluo do nosso módulo de exemplo:

var names = ["Sunday", "Monday", "Tuesday", "Wednesday","Thursday", "Friday", "Saturday"];
exports.name = function(number) {
  return names[number];
};
exports.number = function(name) {
  return names.indexOf(name);
};

Essa é uma implementação mínima de require:
function require(name) {
  var code = new Function("exports", readFile(name));
  var exports = {};
  code(exports);
  return exports;
}
console.log(require("weekDay").name(1));
// → Monday
Quando usando este sistema, um módulo tipicamente começa com pequenas declarações de variáveis que carregam os módulos que ele precisa.

var weekDay = require("weekDay");
var today = require("today");
console.log(weekDay.name(today.dayNumber()));
A implementação de require acima tem diversos problemas. Primeiro, ela vai carregar e rodar um módulo todas as vezes que este for "require-d" (requisitado), então se diversos módulos têm a mesma dependência, ou uma chamada require é colocada dentro de uma função que vai ser chamada múltiplas vezes, tempo e energia serão desperdiçados.

Isso pode ser resolvido armazenando os módulos que já tenham sido carregados em um objeto, e simplesmente retornando o valor existente se eles forem carregados novamente.

O segundo problema é que não é possível para um módulo expor diretamente um valor simples. Por exemplo, um módulo pode querer exportar apenas o construtor do tipo do objeto que ele define. Por agora, isso não pode ser feito, porque require sempre vai usar o objeto exports que ele cria como o valor exportado.

A solução tradicional para isso é fornecer outra variável, module, que é um objeto que tem a propriedade exports. Essa propriedade inicialmente aponta para o objeto vazio criado por require, mas pode ser sobrescrita com outro valor para exportar algo a mais.

function require(name) {
  if (name in require.cache)
    return require.cache[name];

  var code = new Function("exports, module", readFile(name));
  var exports = {}, mod = {exports: exports};
  code(exports, mod);

  require.cache[name] = module.exports;
  return module.exports;
}
require.cache = Object.create(null);
Agora temos um sistema de módulo que usa uma simples variável global (require) para permitir que módulos encontrem e usem um ao outro sem ter que ir para o escopo global.

Este estilo de sistema de módulos é chamado "Módulos CommonJS", após o pseudo-padrão que o implementou pela primeira vez. Ele também é feito dentro do Node.js. Implementações reais fazem bem mais do que o exemplo que eu mostrei. Mais importante, eles tem uma forma muito mais inteligente de ir de um nome de módulo para uma parte de código real, permitindo ambos caminhos relativos e nomes de módulos registrados "globalmente".

Carregando módulos lentamente
Embora seja possível usar a técnica acima para carregar JavaScript no navegador, isso é um pouco complicado. A razão para isso é que ler um arquivo (módulo) na web é muito mais lento que ler este mesmo arquivo do seu disco rígido. JavaScript no navegador é obrigado a se comportar de tal forma que, enquanto um script esteja rodando, nada mais pode acontecer no site que ele está rodando. Isso significa que se todas as chamadas require carregarem algo em algum servidor web distante, a página vai ficar congelada por um doloroso longo período durante sua inicialização.

Existem maneiras de se trabalhar isso, por exemplo, rodando outro programa (como o Browserify) em seu programa antes, que irá concatenar todas as dependências olhando todas as chamadas require, e colocando-as em juntas em um grande arquivo.

Outra solução é encapsular seu módulo em uma função, carregar os módulos que ela depende em segundo plano, e apenas rodar essa função quando todas suas dependências forem carregadas. Isso é o que o sistema de módulos AMD ("Asynchronous Module Definition") faz.

Nosso programa trivial com dependências, em AMD, se parece com isso:

define(["weekDay", "today"], function(weekDay, today) {
  console.log(weekDay.name(today.dayNumber()));
});
A função define é o conceito central nessa abordagem. Ela primeiro recebe um array com nomes de módulos, e então uma função que recebe um argumento para cada dependência. Ela vai carregar as dependências (se elas ainda não tiverem sido carregadas) em segundo plano, permitindo que a página continue a trabalhar em quanto está esperando. Uma vez que todas as dependências estejam carregadas, ela vai carregar a função que foi passada, com as interfaces das dependências como argumentos.

Os módulos que são carregados dessa forma devem conter uma chamada a define. O valor usado para sua interface é qualquer valor retornado pela função que é o segundo argumento passado nessa chamada. Aqui está o módulo weekDay de novo.

define([], function() {
  var names = ["Sunday", "Monday", "Tuesday", "Wednesday","Thursday", "Friday", "Saturday"];
  return {
    name: function(number) { return names[number]; },
    number: function(name) { return names.indexOf(name); }
  };
});
Para mostrar uma simples implementação de define, vamos supor que também temos uma função backgroundReadFile, que pega o nome do arquivo e uma função, e vai chamar a função com o conteúdo do arquivo assim que este for carregado.

function define(depNames, moduleFunction) {
  var deps = [], myMod = define.currentModule;

  depNames.forEach(function(name) {
    if (name in define.cache) {
      var depMod = define.cache[name];
    } else {
      var depMod = {exports: null,
                    loaded: false,
                    onLoad: []};
      define.cache[name] = depMod;
      backgroundReadFile(name, function(code) {
        define.currentModule = depMod;
        new Function("", code)();
      });
    }
    deps.push(depMod);
    if (!depMod.loaded)
      depMod.onLoad.push(runIfDepsLoaded);
  });

  function runIfDepsLoaded() {
    if (!deps.every(function(m) { return m.loaded; }))
      return;

    var args = deps.map(function(m) { return m.exports; });
    var exports = moduleFunction.apply(null, args);
    if (myMod) {
      myMod.exports = exports;
      myMod.loaded = true;
      myMod.onLoad.every(function(f) { f(); });
    }
  }
  runIfDepsLoaded();
}
define.cache = Object.create(null);
Isso é muito mais difícil de seguir que a função require. Sua execução não segue um caminho simples e previsível. Ao invés disso, múltiplas operações são definidas para acontecerem em algum tempo não especificado no futuro (quando o módulo for carregado), que obscurece a forma que o código é executado.

O maior problema que este código lida é coletar os valores das interfaces das dependências do módulo. Para rastrear os módulos, e seus estados, um objeto é criado para cada módulo que é carregado por define. Este objeto armazena o valor exportado pelo módulo, um booleano indicando se o módulo já foi completamente carregado e um array de funções para ser chamado quando o módulo tiver sido carregado.

Um cache é usado para prevenir o carregamento de módulos múltiplas vezes, assim como fizemos para o require. Quando define é chamada, nós primeiro construímos um array de módulos de objetos que representam as dependências deste módulo. Se o nome da dependência corresponde com o nome de um módulo cacheado, nós usamos o objeto existente. Caso contrário, nós criamos um novo objeto (com o valor de loaded igual a false) e armazenamos isso em cache. Nós também começamos a carregar o módulo, usando a função backgroundReadFile. Uma vez que o arquivo tenha sido carregado, seu conteúdo é rodado usando o construtor Function.

É assumido que este arquivo também contenha uma (única) chamada a define. A propriedade define.currentModule é usada para informar a esta chamada sobre o módulo objeto que está sendo carregado atualmente, dessa forma podemos atualizá-lo umas vez e terminar o carregamento.

Isso é manipulado na função runIfDepsLoaded, que é chamada uma vez imediatamente (no caso de não ser necessário carregar nenhuma dependência) e uma vez para cada dependência que termina seu carregamento. Quando todas as dependências estão lá, nós chamamos moduleFunction, passando para ela os valores exportados apropriados. Se existe um módulo objeto, o valor retornado da função é armazenado, o objeto é marcado como carregado (loaded), e as funções em seu array onLoad são chamadas. Isso vai notificar qualquer módulo que esteja esperando que suas dependências sejam carregadas completamente.

Uma implementação real do AMD é, novamente, bem mais inteligente em relação a resolução dos nomes e suas URLs, e genericamente mais robusta. O projeto RequireJS (http://requirejs.org) fornece uma implementação popular deste estilo que carregamento de módulos.

12. Callback Function

Referência:
https://developer.mozilla.org/en-US/docs/Glossary/Callback_function

CallBack ou chamada de retorno, em português, é um processos assíncrono, caracterizada por uma função que possui um parâmetro do tipo function, capaz de receber um uma função como argumento, esse argumento que se chama função callback.
assíncrono: nesse caso significa que pode-se programar a execução da função callback no momento em que se deseja.
Exemplo:
<!DOCTYPE html>
<html>
<body>
<script>
function quad(n) { //função callback , argumento
  alert(n 'ao quadrado é igual a: 'n*n);
}

function calcular(callback) {
  var n = prompt('Entre com um número.');
  callback(n); // função parâmetro
}
calcular(quad);
</script>
</body>
</html>

Exemplo:
<!DOCTYPE html>
<html>
<body>
<script>
function calcular(x, y, callback) {
    return callback(x, y);
}
function calcProduto(x, y) { //função callback , argumento
    return x*y;
}
function calcSoma(x, y) { //função callback , argumento
    return x + y;
}
alert("Produto: "+calcular(8, 13, calcProduto));
alert("Soma: "+calcular(8, 13, calcSoma));
</script>
</body>
</html>

12.1. Callbacks e this
Um dos erros mais comuns acontece quando utilizamos a palavra reservada this dentro de um callback e confundimos seu valor. O this dentro do callback vai guardar o valor do objeto pai da função callback e não da função que recebe o callback.

var myObj = {
    init: function (callback) {
        callback();
    }
};

myObj.init(function () {
    console.log(this); // Window (...) 
});

Para esses casos especiais, podemos definir o valor do this utilizando os métodos call e apply (falo mais sobre eles logo, logo).

Outro ponto que merece atenção é o uso do this na hora de anexar eventos a um elemento. Nesse caso, o valor da palavra reservada representa o elemento e não a função.

var myObj = {
    init: function () {
        this.link = document.querySelector('a');
        this.link.onclick = function (e) {
            console.log(this);  
        };
    }
};

myObj.init();
// clique no link: <a href="#">link</a>
Aqui a solução é armazenar o estado do objeto em uma variável, normalmente chamada de that ou self e utilizá-la na função do evento.

var myObj = {
    init: function () {
        var that = this;
        this.link = document.querySelector('a');
        this.link.onclick = function (e) {
            console.log(that);  
        };
    }
};

myObj.init();
// clique no link: Object {init: function, link: a}

13. Função Recursiva

Uma função que chama a si mesma é chamada de função recursiva. Em alguns casos, a recursividade é análoga a um laço. Ambos executam o código várias vezes, e ambos necessitam de uma condição para evitar um laço infinito, ou melhor, recursão infinita, neste caso.
Por exemplo,  o seguinte laço:
var x = 0;
while (x < 10) { // "x < 10" a condição do laço
   // faça coisas
   x++;
}
Pode ser convertido em função recursiva e uma chamada para a função:
function loop(x) {
   if (x >= 10) // "x >= 10" a condição de parada (equivalente a "!(x < 10)")
      return x + loop(x - 1); // chamada recursiva
}    // return 15 + 14 + 13 + loop(13-1)...
loop(15);

A figura abaixo esquematiza o o retorno para cada chamada da função:


Uma função pode referir-se e chamar a si própria. Há três maneiras de uma função referir-se a si mesma:
- Pelo nome da função.
- Por uma variável no escopo que se refere a função.
- Pelo arguments.callee.

Exemplo de chamada pelo próprio nome:
<!DOCTYPE html>
<html>
<body>
<script>
function fatorial(num) 
    if (num < 0) { 
        return -1; 
    } 
    else if (num == 0) { 
        return 1; 
    } 
    else { 
        return (num * fatorial(num - 1));  // chamada recursiva, guarda o valor e faz um loop
    }         // return num*num-1*num-2*num-3*fatorial(num-4)...

var result = fatorial(8); 
document.write(result); 
</script>
</body>
</html>
Obs:
A função fatorial recursiva é últil para alterar o parâmetro é fazer o loop, o return matém o valor anterior.


Exemplo usando variável:
- a variável fatorial cria uma capsula para a função myself que é visível apenas dentro de seu própro bloco;
- o escopo da variável fatorial pertence onde ela foi criada, ou seja, pode ser chamada onde foi declarada;
- a função atribuída a variável pode se chamada pela própria variável.

Exemplo de função chamada no retorno da função:

1<!DOCTYPE html>
2<html>
3<body>
4<script>
5var fatorial = function myself (n) {
6console.log(typeof myself);            //linha: 6, typeof myself === 'function'
7   if (n <= 1) {           //n=5, return 5*myself(5-1)
 8       return 1;            //n=4, return 5*4*myself(4-1)
 9   }                            //n=3, return 5*4*3*myself(3-1)...
 10  return n * myself(n-1); //Retorna o valor passado e chama a função (loop), recursividade
11}
12console.log(typeof myself); // linha: 12, typeof myself === 'undefined'
13console.log(fatorial(5)); //linha: 13
</script>
</body>
</html>
Saída Console:
linha:12 undefined
linha:6 function
linha:6 function
linha:6 function
linha:6 function
linha:6 function
linha:13 120
Obs:
A função myself só é visível dentro do escopo criado pelo nome fatorial, ela é últil para alterar o parâmetro.


Exemplo de chamada pelo nome da variável que a função é atribuída:
<!DOCTYPE html>
<html>
<body>
<script>
var fatorial = function(n) {
   if (n <= 1) { 
        return 1;
    }                
   return n*fatorial(n-1);  // função recursiva
}
console.log(fatorial(5));
</script>
</body>
</html>

Exemplo de função chamada pelo arguments.callee:
<!DOCTYPE html>
<html>
<body>
<script>
var factorial = function (n) {
    if (n <= 1) {
        return 1;
    }
    return n * arguments.callee(n-1); // recursividade
}
console.log(factorial(5));
</script>
</body>
</html>
Saída Console:
12
Obs:
A propriedade callee é membro do objeto arguments que fica disponível apenas quando a função associada está sendo executada.
O valor inicial da propriedade callee é o objeto Function que está sendo executado. Isso permite que funções anônimos sejam recursivas.

Exemplo:
<!DOCTYPE html>
<html>
<body>
<script>
var varS = function soma(x, y) {
   return console.log(x+" + " +y+" = "+x+y);
   arguments.callee(); // chamada recuriva usando arguments.calle
}
varS(2,5);
</script>
</body>
</html>

Comentários:
Alguns algoritmos não podem ser simples laços iterativos. Por exemplo, conseguir todos os nós da estrutura de uma árvore no DOM é mais fácil se feito recursivamente:

function walkTree(node) {
   if (node == null) //
      return;
   // faça algo com o nó
   for (var i = 0; i < node.childNodes.length; i++) {
      walkTree(node.childNodes[i]);
   }
}
Em comparação ao laço da função, cada chamada recursiva realiza outras chamadas recursivas.

É possível converter qualquer algoritmo recursivo para um não recursivo, mas muitas vezes a lógica é muito mais complexa e exige o uso de pilhas. Na verdade a própria recursão usa pilha: a pilha de função.
O comportamento da pilha pode ser vista a seguir no exemplo:

function foo(i) {
   if (i < 0) return;
   document.writeln('begin:' + i);
   foo(i - 1);
   document.writeln('end:' + i);
}
foo(3);
que produz:
begin:3 begin:2 begin:1 begin:0 end:0 end:1 end:2 end:3