Je sais que cela fonctionnera:
function Foo() {};
Foo.prototype.talk = function () {
alert('hello~\n');
};
var a = new Foo;
a.talk(); // 'hello~\n'
Mais si je veux appeler
Foo.talk() // this will not work
Foo.prototype.talk() // this works correctly
Je trouve des méthodes pour faire du Foo.talk
travail,
Foo.__proto__ = Foo.prototype
Foo.talk = Foo.prototype.talk
Y a-t-il d'autres façons de procéder? Je ne sais pas s'il est juste de le faire. Utilisez-vous des méthodes de classe ou des méthodes statiques dans votre code JavaScript?
javascript
oop
lostyzd
la source
la source
Foo.talk = function ...
Foo.walk = function() {}
pas ses instances, car il ne se trouve pas sur la chaîne prototype. Y at - il cross-browser une méthode pour faire d'une fonction[[prototype]]
point à sonprototype
?this
pointeur.Réponses:
Tout d'abord, rappelez-vous que JavaScript est principalement un langage prototypique , plutôt qu'un langage basé sur une classe 1 .
Foo
n'est pas une classe, c'est une fonction, qui est un objet. Vous pouvez instancier un objet à partir de cette fonction en utilisant lenew
mot clé qui vous permettra de créer quelque chose de similaire à une classe dans un langage OOP standard.Je suggérerais d'ignorer la
__proto__
plupart du temps, car il ne prend pas en charge plusieurs navigateurs, et plutôt de se concentrer sur l'apprentissageprototype
fonctionnement.Si vous avez une instance d'un objet créé à partir d'une fonction 2 et que vous accédez à l'un de ses membres (méthodes, attributs, propriétés, constantes, etc.) de quelque manière que ce soit, l'accès descendra dans la hiérarchie du prototype jusqu'à ce qu'il (a) trouve le membre, ou (b) ne trouve pas un autre prototype.
La hiérarchie commence sur l'objet appelé, puis recherche son objet prototype. Si l'objet prototype a un prototype, il se répète, si aucun prototype n'existe,
undefined
est retourné.Par exemple:
Il me semble que vous avez déjà au moins quelque peu compris ces parties "de base", mais je dois les rendre explicites juste pour être sûr.
En JavaScript, tout est un objet 3 .
tout est un objet.
function Foo(){}
ne définit pas seulement une nouvelle fonction, il définit un nouvel objet fonction accessible à l'aide deFoo
.C'est pourquoi vous pouvez accéder
Foo
au prototype de avecFoo.prototype
.Vous pouvez également définir plus de fonctions sur
Foo
:Cette nouvelle fonction est accessible en utilisant:
J'espère que vous remarquez maintenant une similitude entre les fonctions d'un objet fonction et une méthode statique.
Pensez
f = new Foo();
à créer une instance de classe,Foo.prototype.bar = function(){...}
à définir une méthode partagée pour la classe etFoo.baz = function(){...}
à définir une méthode statique publique pour la classe.ECMAScript 2015 a introduit une variété de sucre syntaxique pour ces types de déclarations afin de les rendre plus simples à mettre en œuvre tout en étant plus faciles à lire. L'exemple précédent peut donc s'écrire:
qui permet
bar
d'être appelé comme:et
baz
être appelé comme:1:
class
était un "futur mot réservé" dans la spécification ECMAScript 5 , mais ES6 introduit la possibilité de définir des classes à l'aide duclass
mot - clé.2: essentiellement une instance de classe créée par un constructeur, mais il existe de nombreuses différences nuancées que je ne veux pas vous induire en erreur
3: les valeurs primitives - qui incluent
undefined
, lesnull
booléens, les nombres et les chaînes - ne sont pas techniquement des objets car ce sont des implémentations de langage de bas niveau. Les booléens, les nombres et les chaînes interagissent toujours avec la chaîne prototype comme s'ils étaient des objets, donc pour les besoins de cette réponse, il est plus facile de les considérer comme des "objets" même s'ils ne le sont pas tout à fait.la source
Foo.talk()
. Vous pouvez attribuer cela dans le constructeur, si vous le souhaitez:this.talk = Foo.talk
- ou, comme vous le notez, en l'attribuantFoo.prototype.talk = Foo.talk
. Mais je ne suis pas sûr que ce soit une bonne idée - en principe, les méthodes d'instance doivent être spécifiques à l'instance.Foo.talk()
appelle simplement une fonction à espace de noms. Vous l'utiliseriez dans des situations similaires à la façon dont les méthodes statiques sont appelées dans les langages OOP comme Java / C #. Un bon exemple de cas d'utilisation serait une fonction commeArray.isArray()
.Foo.talk = function ()...
ne sera pas disponible pour les sous-classes sur leur propre nom de classe. Cela peut être contourné en "étendant" les sous-classes, mais je recherche également une manière plus élégante.Vous pouvez le réaliser comme ci-dessous:
Vous pouvez maintenant invoquer la fonction "talk" comme ci-dessous:
Vous pouvez le faire car en JavaScript, les fonctions sont également des objets.
la source
Appelez une méthode statique à partir d'une instance:
Projet de classe Javascript simple: https://github.com/reduardo7/sjsClass
la source
Clazz.staticMethod
mais il vous montre comment établir un lien vers ces méthodes statiques à partir d'un objet instancié. Ceci est particulièrement utile dans des environnements tels que Node.js où, en utilisant require, vous ne pouvez pas avoir un accès direct au constructeur d'origine. La seule chose que j'ajouterais estthis.constructor.staticMethod.apply(this, arguments);
constructor: (a) -> @constructor.add @
(enfin presque, de toute façon)Voici un bon exemple pour montrer comment Javascript fonctionne avec les variables et méthodes statiques / d'instance.
la source
this
.this
motEn plus, il est maintenant possible de faire avec
class
etstatic
va donner
la source
a.talk()
cela ne fonctionne pas. La réponse acceptée dit que la chaîne de prototypes devrait le trouver, non? Mais ce n'est pas le casJ'utilise des espaces de noms:
Et pour l'utiliser:
Ou
la source
ES6 prend en charge maintenant
class
et lesstatic
mots clés comme un charme:la source
Si vous devez écrire des méthodes statiques dans ES5, j'ai trouvé un excellent tutoriel pour cela:
voir @ https://abdulapopoola.com/2013/03/30/static-and-instance-methods-in-javascript/
la source
Juste des notes supplémentaires. En utilisant la classe ES6, lorsque nous créons des méthodes statiques .. le moteur Javacsript définit l'attribut descripteur un peu différent de la méthode "statique" de la vieille école
il définit l'attribut interne (propriété du descripteur) pour brand () sur
par rapport à
qui définit l'attribut interne de brand () sur
voir que l' énumération est définie sur false pour la méthode statique dans ES6.
cela signifie que vous ne pouvez pas utiliser la boucle for-in pour vérifier l'objet
La méthode statique dans ES6 est traitée comme la propriété privée des autres classes (nom, longueur, constructeur), sauf que la méthode statique est toujours accessible en écriture, ainsi le descripteur accessible en écriture est défini sur true
{ writable: true }
. cela signifie également que nous pouvons le remplacerla source
Lorsque vous essayez d'appeler
Foo.talk
, le JS essaie de rechercher une fonction àtalk
travers__proto__
et, bien sûr, elle ne peut pas être trouvée.Foo.__proto__
estFunction.prototype
.la source
Les appels de méthode statique sont effectués directement sur la classe et ne peuvent pas être appelés sur les instances de la classe. Les méthodes statiques sont souvent utilisées pour créer une fonction d'utilité
Description assez claire
Tiré directement de mozilla.org
Foo doit être lié à votre classe Ensuite, lorsque vous créez une nouvelle instance, vous pouvez appeler myNewInstance.foo () Si vous importez votre classe, vous pouvez appeler une méthode statique
la source
Quand j'ai fait face à une telle situation, j'ai fait quelque chose comme ceci:
alors maintenant je peux appeler la méthode info comme
Logger.info("my Msg", "Tag");
la source
Dans votre cas, si vous souhaitez
Foo.talk()
:Mais c'est une manière inefficace de mettre en œuvre, utiliser
prototype
c'est mieux.Une autre façon, My way est définie comme une classe statique:
La classe statique ci-dessus n'a pas besoin d'être utilisée
prototype
car elle ne sera construite qu'une seule fois en tant qu'utilisation statique.la source
Javascript n'a pas de classes réelles, il utilise plutôt un système d'héritage prototypique dans lequel les objets «héritent» d'autres objets via leur chaîne de prototypes. Cela s'explique mieux par le code lui-même:
la source