Primeiro, lembre-se de que o JavaScript é principalmente uma linguagem prototípica , e não uma linguagem baseada em classe 1 . Foo
não é uma classe, é uma função, que é um objeto. Você pode instanciar um objeto de que a função usando a new
palavra-chave que lhe permitirá criar algo semelhante a uma classe em uma linguagem OOP padrão.
Eu sugiro que ignore a __proto__
maior parte do tempo, porque ele tem um suporte ruim entre navegadores e, em vez disso, concentre-se em aprender como prototype
funciona.
Se você tiver uma instância de um objeto criado a partir de uma função 2 e acessar um de seus membros (métodos, atributos, propriedades, constantes etc.) de qualquer forma, o acesso fluirá pela hierarquia do protótipo até que (a) encontre o membro, ou (b) não encontra outro protótipo.
A hierarquia inicia no objeto que foi chamado e, em seguida, pesquisa seu objeto de protótipo. Se o objeto protótipo tiver um protótipo, ele será repetido, se não houver protótipo, undefined
será retornado.
Por exemplo:
foo = {bar: 'baz'};
console.log(foo.bar); // logs "baz"
foo = {};
console.log(foo.bar); // logs undefined
function Foo(){}
Foo.prototype = {bar: 'baz'};
f = new Foo();
console.log(f.bar);
// logs "baz" because the object f doesn't have an attribute "bar"
// so it checks the prototype
f.bar = 'buzz';
console.log( f.bar ); // logs "buzz" because f has an attribute "bar" set
Parece-me que você pelo menos já entendeu um pouco essas partes "básicas", mas preciso explicitá-las apenas para ter certeza.
Em JavaScript, tudo é um objeto 3 .
tudo é um objeto.
function Foo(){}
não apenas define uma nova função, ele define um novo objeto de função que pode ser acessado usando Foo
.
É por isso que você pode acessar Foo
o protótipo com Foo.prototype
.
O que você também pode fazer é definir mais funções em Foo
:
Foo.talk = function () {
alert('hello world!');
};
Esta nova função pode ser acessada usando:
Foo.talk();
Espero que agora você esteja percebendo uma semelhança entre funções em um objeto de função e um método estático.
Pense f = new Foo();
em criar uma instância de classe, Foo.prototype.bar = function(){...}
como definir um método compartilhado para a classe e Foo.baz = function(){...}
como definir um método estático público para a classe.
O ECMAScript 2015 introduziu uma variedade de açúcar sintático para esse tipo de declaração, para torná-los mais simples de implementar e também para facilitar a leitura. O exemplo anterior pode, portanto, ser escrito como:
class Foo {
bar() {...}
static baz() {...}
}
que permite bar
ser chamado como:
const f = new Foo()
f.bar()
e baz
ser chamado como:
Foo.baz()
1: class
era uma "palavra reservada futura" na especificação do ECMAScript 5 , mas o ES6 introduz a capacidade de definir classes usando a class
palavra - chave.
2: essencialmente uma instância de classe criada por um construtor, mas há muitas diferenças sutis que eu não quero enganar você
3: valores primitivos - que incluem undefined
, null
booleanos, números e seqüências de caracteres - não são tecnicamente objetos porque são implementações de linguagem de baixo nível. Booleanos, números e seqüências de caracteres ainda interagem com a cadeia de protótipos como se fossem objetos. Portanto, para os fins desta resposta, é mais fácil considerá-los "objetos", mesmo que não sejam exatamente assim.
Foo.talk = function ...