Já existem respostas muito boas, mas estou postando uma nova para enfatizar minha observação no caso III abaixo sobre o que acontece quando você tem uma declaração de retorno explícita em uma função que está new
desenvolvendo. Veja os casos abaixo:
Caso I :
var Foo = function(){
this.A = 1;
this.B = 2;
};
console.log(Foo()); //prints undefined
console.log(window.A); //prints 1
Acima está um caso simples de chamar a função anônima apontada por Foo
. Quando você chama essa função, ela retorna undefined
. Como não há uma declaração de retorno explícita, o intérprete de JavaScript insere forçosamente uma return undefined;
declaração no final da função. Aqui janela é o objeto invocação (contextual this
) que recebe novo A
e B
propriedades.
Caso II :
var Foo = function(){
this.A = 1;
this.B = 2;
};
var bar = new Foo();
console.log(bar()); //illegal isn't pointing to a function but an object
console.log(bar.A); //prints 1
Aqui, o intérprete JavaScript, vendo a new
palavra - chave, cria um novo objeto que atua como o objeto de invocação (contextual this
) da função anônima apontada por Foo
. Nesse caso, torne A
- B
se propriedades no objeto recém-criado (no lugar do objeto de janela). Como você não possui nenhuma declaração de retorno explícita, o intérprete JavaScript insere forçosamente uma declaração de retorno para retornar o novo objeto criado devido ao uso da new
palavra-chave.
Caso III :
var Foo = function(){
this.A = 1;
this.B = 2;
return {C:20,D:30};
};
var bar = new Foo();
console.log(bar.C);//prints 20
console.log(bar.A); //prints undefined. bar is not pointing to the object which got created due to new keyword.
Aqui, novamente, o intérprete JavaScript, vendo a new
palavra - chave, cria um novo objeto que atua como o objeto de invocação (contextual this
) da função anônima apontada por Foo
. Novamente A
e B
torne - se propriedades no objeto recém-criado. Mas desta vez você tem uma declaração de retorno explícita para que o intérprete JavaScript não faça nada por conta própria.
O ponto a ser observado no caso III é que o objeto que está sendo criado devido à new
palavra - chave se perdeu do seu radar. bar
está na verdade apontando para um objeto completamente diferente, que não é aquele criado pelo interpretador JavaScript devido à new
palavra - chave.
Citando David Flanagan de JavaScripit: The Definitive Guide (6th Edition), cap. 4, página 62:
Quando uma expressão de criação de objeto é avaliada, o JavaScript primeiro cria um novo objeto vazio, exatamente como o criado pelo inicializador de objetos {}. Em seguida, ele chama a função especificada com os argumentos especificados, passando o novo objeto como o valor da palavra-chave this. A função pode usar isso para inicializar as propriedades do objeto recém-criado. As funções escritas para uso como construtores não retornam um valor, e o valor da expressão de criação do objeto é o objeto recém-criado e inicializado. Se um construtor retornar um valor do objeto, esse valor se tornará o valor da expressão de criação do objeto e o objeto recém-criado será descartado.
--- Informações adicionais ---
As funções usadas no snippet de código dos casos acima têm nomes especiais no mundo JS, como abaixo:
Caso I e II - Função Construtora
Caso III - Função de fábrica. As funções de fábrica não devem ser usadas com a new
palavra - chave que fiz para explicar o conceito no encadeamento atual.
Você pode ler sobre a diferença entre eles neste tópico.