Eu sei que isso vai funcionar:
function Foo() {};
Foo.prototype.talk = function () {
alert('hello~\n');
};
var a = new Foo;
a.talk(); // 'hello~\n'
Mas se eu quiser ligar
Foo.talk() // this will not work
Foo.prototype.talk() // this works correctly
Eu encontro alguns métodos para fazer o Foo.talk
trabalho,
Foo.__proto__ = Foo.prototype
Foo.talk = Foo.prototype.talk
Existem outras maneiras de fazer isso? Não sei se é certo fazê-lo. Você usa métodos de classe ou métodos estáticos no seu código JavaScript?
javascript
oop
lostyzd
fonte
fonte
Foo.talk = function ...
Foo.walk = function() {}
não afetará suas instâncias, pois não está na cadeia de protótipos. Existe cross-browser um método para fazer uma função[[prototype]]
ponto a seuprototype
?this
ponteiro.Respostas:
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 anew
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 comoprototype
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:
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 usandoFoo
.É por isso que você pode acessar
Foo
o protótipo comFoo.prototype
.O que você também pode fazer é definir mais funções em
Foo
:Esta nova função pode ser acessada usando:
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 eFoo.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:
que permite
bar
ser chamado como:e
baz
ser chamado como:1:
class
era uma "palavra reservada futura" na especificação do ECMAScript 5 , mas o ES6 introduz a capacidade de definir classes usando aclass
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.fonte
Foo.talk()
. Você pode atribuir isso no construtor, se desejar:this.talk = Foo.talk
- ou, como você observa, atribuindoFoo.prototype.talk = Foo.talk
. Mas não tenho certeza de que seja uma boa ideia - por princípio, os métodos de instância devem ser específicos para a instância.Foo.talk()
está apenas chamando uma função no espaço de nome. Você o usaria em situações semelhantes à forma como os métodos estáticos são chamados nas linguagens OOP, como Java / C #. Um bom exemplo de um caso de uso seria uma função comoArray.isArray()
.Foo.talk = function ()...
não estará disponível para subclasses no próprio nome da classe. Isso pode ser contornado através da extensão de subclasses, mas também estou procurando uma maneira mais elegante.Você pode alcançá-lo como abaixo:
Agora você pode chamar a função "talk" como abaixo:
Você pode fazer isso porque, em JavaScript, as funções também são objetos.
fonte
Chame um método estático de uma instância:
Projeto de classe Javascript simples: https://github.com/reduardo7/sjsClass
fonte
Clazz.staticMethod
mas ele está mostrando como vincular esses métodos estáticos a partir de um objeto instanciado. Isso é especialmente útil em ambientes como o Node.js, onde, usando o require, você pode não ter acesso direto ao construtor original. A única coisa que gostaria de acrescentar éthis.constructor.staticMethod.apply(this, arguments);
constructor: (a) -> @constructor.add @
(bem, quase, de qualquer maneira)Aqui está um bom exemplo para demonstrar como o Javascript funciona com variáveis e métodos estáticos / instâncias.
fonte
this
.this
palavra-chaveAlém disso, agora é possível fazer com
class
estatic
darei
fonte
a.talk()
que não funciona. A resposta aceita diz que a cadeia de protótipos deve encontrá-lo, certo? Mas não é o casoEu uso namespaces:
E para usá-lo:
Ou
fonte
O ES6 suporta agora
class
estatic
palavras - chave como um encanto:fonte
Se você precisar escrever métodos estáticos no ES5, encontrei um ótimo tutorial para isso:
consulte @ https://abdulapopoola.com/2013/03/30/static-and-instance-methods-in-javascript/
fonte
Apenas notas adicionais. Usando a classe ES6, Quando criamos métodos estáticos ... o mecanismo Javacsript define o atributo descritor um pouco diferente do método "estático" da velha escola
define atributo interno (propriedade do descritor) da marca () como
comparado com
que define o atributo interno da marca () como
veja que enumerable está definido como false para o método estático no ES6.
significa que você não pode usar o loop for-in para verificar o objeto
O método estático no ES6 é tratado como a propriedade privada da classe de outros (nome, comprimento, construtor), exceto que o método estático ainda é gravável, portanto o gravador do descritor é definido como verdadeiro
{ writable: true }
. isso também significa que podemos substituí-lofonte
Quando você tenta chamar
Foo.talk
, a JS tenta procurar uma funçãotalk
através de__proto__
e, é claro, não pode ser encontrada.Foo.__proto__
éFunction.prototype
.fonte
As chamadas de método estático são feitas diretamente na classe e não podem ser chamadas em instâncias da classe. Métodos estáticos são frequentemente usados para criar funções utilitárias
Descrição bastante clara
Tomado diretamente de mozilla.org
Foo precisa estar vinculado à sua classe Então, quando você cria uma nova instância, pode chamar myNewInstance.foo () Se você importar sua classe, pode chamar um método estático
fonte
Quando enfrentei tal situação, fiz algo parecido com isto:
então agora eu posso chamar o método info como
Logger.info("my Msg", "Tag");
fonte
No seu caso, se você quiser
Foo.talk()
:Mas é uma maneira ineficiente de implementar, usar
prototype
é melhor.Outra maneira, Meu caminho é definido como classe estática:
A classe estática acima não precisa ser usada,
prototype
pois será construída apenas uma vez como uso estático.fonte
Javascript não possui classes reais, ao contrário, usa um sistema de herança prototípica no qual os objetos 'herdam' de outros objetos por meio de sua cadeia de protótipos. Isso é melhor explicado através do próprio código:
fonte