nodejs - Clase contra método estático en JavaScript
nodejs class (13)
Además, ahora es posible hacerlo con class
y static
''use strict''
class Foo {
static talk() {
console.log(''talk'')
};
speak() {
console.log(''speak'')
};
};
daré
var a = new Foo();
Foo.talk(); // ''talk''
a.talk(); // err ''is not a function''
a.speak(); // ''speak''
Foo.speak(); // err ''is not a function''
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 que Foo.talk
funcione,
-
Foo.__proto__ = Foo.prototype
-
Foo.talk = Foo.prototype.talk
¿Hay alguna otra manera de hacer esto? No sé si es correcto hacerlo. ¿Utiliza métodos de clase o métodos estáticos en su código JavaScript?
Cuando intentas llamar a Foo.talk
, el JS intenta buscar una función a través de __proto__
y, por supuesto, no se puede encontrar.
Foo.__proto__
es Function.prototype
.
Cuando me enfrenté a una situación así, he hecho algo como esto:
Logger = {
info: function (message, tag) {
var fullMessage = '''';
fullMessage = this._getFormatedMessage(message, tag);
if (loggerEnabled) {
console.log(fullMessage);
}
},
warning: function (message, tag) {
var fullMessage = '''';
fullMessage = this._getFormatedMessage(message, tag);
if (loggerEnabled) {
console.warn(fullMessage);`enter code here`
}
},
_getFormatedMessage: function () {}
};
así que ahora puedo llamar al método de información como Logger.info("my Msg", "Tag");
ES6 admite ahora palabras clave de class
y static
como un encanto:
class Foo {
constructor() {}
talk() {
console.log("i am not static");
}
static saying() {
console.log(this.speech);
}
static get speech() {
return "i am static method";
}
}
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 desde esa función usando la new
palabra clave que le permitirá crear algo similar a una clase en un lenguaje estándar de POO.
Yo sugeriría ignorar __proto__
mayor parte del tiempo porque no es compatible con el navegador cruzado, y en su lugar se enfoca en aprender cómo funciona el prototype
.
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 cualquier manera, el acceso fluirá hacia la jerarquía del prototipo hasta que (a) encuentre el miembro, o (b) no encuentra otro prototipo.
La jerarquía comienza en el objeto al que se llamó, y luego busca su objeto prototipo. Si el objeto prototipo tiene un prototipo, se repite, si no existe un prototipo, se devuelve undefined
.
Por ejemplo:
foo = {bar: ''baz''};
alert(foo.bar); //alerts "baz"
foo = {};
alert(foo.bar); //alerts undefined
function Foo(){}
Foo.prototype = {bar: ''baz''};
f = new Foo();
alert(f.bar);
//alerts "baz" because the object f doesn''t have an attribute "bar"
//so it checks the prototype
f.bar = ''buzz'';
alert( f.bar ); //alerts "buzz" because f has an attribute "bar" set
Me parece que al menos ya has comprendido 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 utilizando Foo
.
Esta es la razón por la que puede acceder al prototipo de Foo
con Foo.prototype
.
Lo que también puedes hacer es configurar más funciones en Foo
:
Foo.talk = function () {
alert(''hello world!'');
};
Se puede acceder a esta nueva función usando:
Foo.talk();
Espero que ya esté notando una similitud entre las funciones de un objeto de función y un método estático.
Piensa en f = new Foo();
como creando una instancia de clase, Foo.prototype.bar = function(){...}
como definiendo un método compartido para la clase, y Foo.baz = function(){...}
como definiendo un método estático público para clase.
ECMAScript 2015 introdujo una variedad de azúcar sintáctica para este tipo de declaraciones para hacerlas más fáciles de implementar y también para que sean más fáciles de leer. El ejemplo anterior se puede escribir como:
class Foo {
bar() {...}
static baz() {...}
}
lo que permite llamar a bar
como:
const f = new Foo()
f.bar()
y baz
ser llamado como:
Foo.baz()
1: la class
era una "Palabra reservada para el futuro" en la especificación ECMAScript 5 , pero ES6 introduce la capacidad de definir clases usando la palabra clave de class
.
2: esencialmente una instancia de clase creada por un constructor, pero hay muchas diferencias matizadas que no quiero engañarles
3: los valores primitivos —que incluyen valores undefined
, null
, booleanos, números y cadenas— no son objetos técnicamente porque son implementaciones de lenguaje 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 tanto.
En tu caso, si quieres Foo.talk()
:
function Foo() {};
// But use Foo.talk would be inefficient
Foo.talk = function () {
alert(''hello~/n'');
};
Foo.talk(); // ''hello~/n''
Pero es una forma ineficiente de implementar, usar prototype
es mejor.
Otra forma, Mi camino se define como clase estática:
var Foo = new function() {
this.talk = function () {
alert(''hello~/n'');
};
};
Foo.talk(); // ''hello~/n''
La clase estática no necesita usar prototype
porque solo se construirá una vez como uso estático.
https://github.com/yidas/js-design-patterns/tree/master/class
Este es un buen ejemplo para demostrar cómo funciona Javascript con variables y métodos estáticos / de instancia.
function Animal(name) {
Animal.count = Animal.count+1||1;// static variables, use function name "Animal"
this.name = name; //instance variable, using "this"
}
Animal.showCount = function () {//static method
alert(Animal.count)
}
Animal.prototype.showName=function(){//instance method
alert(this.name);
}
var mouse = new Animal("Mickey");
var elephant = new Animal("Haddoop");
Animal.showCount(); // static method, count=2
mouse.showName();//instance method, alert "Mickey"
mouse.showCount();//Error!! mouse.showCount is not a function, which is different from Java
Las llamadas a métodos estáticos se realizan directamente en la clase y no se pueden llamar en instancias de la clase. Los métodos estáticos se utilizan a menudo para crear la función 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.
Llama a un método estático desde una instancia:
function Clazz() {};
Clazz.staticMethod = function() {
alert(''STATIC!!!'');
};
Clazz.prototype.func = function() {
this.constructor.staticMethod();
}
var obj = new Clazz();
obj.func(); // <- Alert''s "STATIC!!!"
Proyecto de clase de Javascript simple: https://github.com/reduardo7/sjsClass
Lo puedes lograr de la siguiente manera:
function Foo() {};
Foo.talk = function() { alert(''I am talking.''); };
Ahora puedes invocar la función "hablar" como se muestra a continuación:
Foo.talk();
Puedes hacer esto porque en JavaScript, las funciones también son objetos. "zzzzBov" también lo ha respondido pero es una lectura larga.
Si tienes que escribir métodos estáticos en ES5, encontré un excelente tutorial para eso:
//Constructor
var Person = function (name, age){
//private properties
var priv = {};
//Public properties
this.name = name;
this.age = age;
//Public methods
this.sayHi = function(){
alert(''hello'');
}
}
// A static method; this method only
// exists on the class and doesn''t exist
// on child objects
Person.sayName = function() {
alert("I am a Person object ;)");
};
vea @ https://abdulapopoola.com/2013/03/30/static-and-instance-methods-in-javascript/
Solo notas adicionales. Usando la clase ES6, cuando creamos métodos estáticos ... el motor Javacsript configuró el atributo descriptor en un poco diferente del método "estático" de la vieja escuela
function Car() {
}
Car.brand = function() {
console.log(''Honda'');
}
console.log(
Object.getOwnPropertyDescriptors(Car)
);
establece el atributo interno (propiedad del descriptor) para la marca () en
..
brand: [object Object] {
configurable: true,
enumerable: true,
value: ..
writable: true
}
..
comparado con
class Car2 {
static brand() {
console.log(''Honda'');
}
}
console.log(
Object.getOwnPropertyDescriptors(Car2)
);
que establece el atributo interno para la marca () a
..
brand: [object Object] {
configurable: true,
enumerable: false,
value:..
writable: true
}
..
ver 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
for (let prop in Car) {
console.log(prop); // brand
}
for (let prop in Car2) {
console.log(prop); // nothing here
}
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 aún se puede escribir, por lo que el descriptor se puede establecer en true { writable: true }
. también significa que podemos anularlo
Car2.brand = function() {
console.log(''Toyota'');
};
console.log(
Car2.brand() // is now changed to toyota
);
Yo uso espacios de nombres:
var Foo = {
element: document.getElementById("id-here"),
Talk: function(message) {
alert("talking..." + message);
},
ChangeElement: function() {
this.element.style.color = "red";
}
};
Y para usarlo:
Foo.Talk("Testing");
O
Foo.ChangeElement();