Sé que esto funcionará:
function Foo() {};
Foo.prototype.talk = function () {
alert('hello~\n');
};
var a = new Foo;
a.talk(); // 'hello~\n'
Pero si quiero llamar
Foo.talk() // this will not work
Foo.prototype.talk() // this works correctly
Encuentro algunos métodos para hacer el Foo.talk
trabajo,
Foo.__proto__ = Foo.prototype
Foo.talk = Foo.prototype.talk
¿Hay otras formas de hacer esto? No sé si es correcto hacerlo. ¿Utiliza métodos de clase o métodos estáticos en su código JavaScript?
javascript
oop
lostyzd
fuente
fuente
Foo.talk = function ...
Foo.walk = function() {}
no afectará sus instancias, ya que no está en la cadena de prototipos. ¿Existe un navegador cruzado para hacer que una función[[prototype]]
señaleprototype
?this
puntero.Respuestas:
En primer lugar, recuerde que JavaScript es principalmente un lenguaje prototípico , en lugar de un lenguaje basado en clases 1 .
Foo
no es una clase, es una función, que es un objeto. Puede crear una instancia de un objeto de esa función utilizando lanew
palabra clave que le permitirá crear algo similar a una clase en un lenguaje estándar de OOP.Sugeriría ignorar la
__proto__
mayor parte del tiempo porque tiene poca compatibilidad entre navegadores y, en su lugar, centrarse en aprender cómoprototype
funciona.Si tiene una instancia de un objeto creado a partir de una función 2 y accede a uno de sus miembros (métodos, atributos, propiedades, constantes, etc.) de alguna manera, el acceso fluirá por la jerarquía del prototipo hasta que (a) encuentre el miembro, o (b) no encuentra otro prototipo.
La jerarquía comienza en el objeto que se llamó y luego busca su objeto prototipo. Si el objeto prototipo tiene un prototipo, se repite, si no existe ningún prototipo,
undefined
se devuelve.Por ejemplo:
Me parece que ya has entendido al menos estas partes "básicas", pero necesito hacerlas explícitas solo para estar seguro.
En JavaScript, todo es un objeto 3 .
Todo es un objeto.
function Foo(){}
no solo define una nueva función, sino que define un nuevo objeto de función al que se puede acceder utilizandoFoo
.Es por eso que puede acceder
Foo
al prototipo conFoo.prototype
.Lo que también puede hacer es establecer más funciones en
Foo
:Se puede acceder a esta nueva función usando:
Espero que ahora esté notando una similitud entre las funciones de un objeto de función y un método estático.
Piense
f = new Foo();
como crear una instancia de clase,Foo.prototype.bar = function(){...}
como definir un método compartido para la clase yFoo.baz = function(){...}
como definir un método público estático para la clase.ECMAScript 2015 introdujo una variedad de azúcar sintáctica para este tipo de declaraciones para hacerlas más simples de implementar y al mismo tiempo más fáciles de leer. Por lo tanto, el ejemplo anterior se puede escribir como:
que permite
bar
ser llamado como:y
baz
ser llamado como:1:
class
era una "Palabra reservada para el futuro" en la especificación ECMAScript 5 , pero ES6 introduce la capacidad de definir clases usando laclass
palabra clave.2: esencialmente una instancia de clase creada por un constructor, pero hay muchas diferencias matizadas que no quiero engañarlo
3: valores primitivos -que incluyen
undefined
,null
, booleanos, números y cadenas de HAYA objetos técnicamente porque son implementaciones de lenguajes de bajo nivel. Los booleanos, los números y las cadenas aún interactúan con la cadena del prototipo como si fueran objetos, por lo que a los efectos de esta respuesta, es más fácil considerarlos "objetos" aunque no lo sean del todo.fuente
Foo.talk()
. Puede asignar eso en el constructor, si lo desea:this.talk = Foo.talk
- o, como observa, mediante la asignaciónFoo.prototype.talk = Foo.talk
. Pero no estoy seguro de que sea una buena idea: en principio, los métodos de instancia deben ser específicos de la instancia.Foo.talk()
solo está llamando a una función de espacio de nombres. Lo usaría en situaciones similares a cómo se llaman los métodos estáticos en lenguajes OOP como Java / C #. Un buen ejemplo de un caso de uso sería una función comoArray.isArray()
.Foo.talk = function ()...
no estará disponible para subclases en su propio nombre de clase. Esto puede solucionarse "ampliando" las subclases, pero también sigo buscando una forma más elegante.Puede lograrlo de la siguiente manera:
Ahora puede invocar la función "hablar" de la siguiente manera:
Puede hacer esto porque en JavaScript, las funciones también son objetos.
fuente
Llamar a un método estático desde una instancia:
Proyecto de clase Javascript simple: https://github.com/reduardo7/sjsClass
fuente
Clazz.staticMethod
sino que le está mostrando cómo vincular estos métodos estáticos desde un objeto instanciado. Esto es especialmente útil en entornos como Node.js donde, usando require, es posible que no tenga acceso directo al constructor original. Lo único que agregaría esthis.constructor.staticMethod.apply(this, arguments);
constructor: (a) -> @constructor.add @
(bueno casi, de todos modos)Aquí hay un buen ejemplo para demostrar cómo funciona Javascript con variables y métodos estáticos / de instancia.
fuente
this
.this
palabra claveAdemás, ahora es posible hacer con
class
ystatic
daré
fuente
a.talk()
no funciona. La respuesta aceptada dice que la cadena de prototipos debería encontrarlo, ¿verdad? Pero no es el casoYo uso espacios de nombres:
Y para usarlo:
O
fuente
ES6 admite ahora
class
ystatic
palabras clave como un encanto:fuente
Si tiene que escribir métodos estáticos en ES5, encontré un gran tutorial para eso:
ver @ https://abdulapopoola.com/2013/03/30/static-and-instance-methods-in-javascript/
fuente
Solo notas adicionales. Usando la clase ES6, cuando creamos métodos estáticos ... el motor Javacsript establece el atributo del descriptor un poco diferente del método "estático" de la vieja escuela
establece el atributo interno (propiedad del descriptor) para brand () en
comparado con
que establece el atributo interno para brand () en
vea que enumerable se establece en falso para el método estático en ES6.
significa que no puede usar el bucle for-in para verificar el objeto
El método estático en ES6 se trata como la propiedad privada de otra clase (nombre, longitud, constructor), excepto que el método estático todavía se puede escribir, por lo que el descriptor de escritura se establece en verdadero
{ writable: true }
. también significa que podemos anularlofuente
Cuando se intenta llamar
Foo.talk
, el JS intenta buscar una funcióntalk
a través__proto__
y, por supuesto, no puede ser encontrado.Foo.__proto__
esFunction.prototype
.fuente
Las llamadas a métodos estáticos se realizan directamente en la clase y no son invocables en instancias de la clase. Los métodos estáticos se utilizan a menudo para crear funciones de utilidad.
Descripción bastante clara
Tomado directamente de mozilla.org
Foo debe estar vinculado a su clase. Luego, cuando cree una nueva instancia, puede llamar a myNewInstance.foo () Si importa su clase, puede llamar a un método estático
fuente
Cuando me enfrenté a tal situación, hice algo como esto:
así que ahora puedo llamar al método de información como
Logger.info("my Msg", "Tag");
fuente
En su caso, si desea
Foo.talk()
:Pero es una forma ineficiente de implementar, usar
prototype
es mejor.Otra forma, My way se define como clase estática:
La clase estática anterior no necesita usar
prototype
porque solo se construirá una vez como uso estático.fuente
Javascript no tiene clases reales, sino que utiliza un sistema de herencia prototípica en el que los objetos 'heredan' de otros objetos a través de su cadena de prototipo. Esto se explica mejor a través del código en sí:
fuente