Je veux nettoyer un peu mon projet et maintenant j'essaie d'utiliser les classes es6 pour mes itinéraires. Mon problème est que this est toujours indéfini.
var express = require('express');
var app = express();
class Routes {
constructor(){
this.foo = 10
}
Root(req, res, next){
res.json({foo: this.foo}); // TypeError: Cannot read property 'foo' of undefined
}
}
var routes = new Routes();
app.get('/', routes.Root);
app.listen(8080);
import express from 'express';
const app = express();
class Routes {
constructor(){
this.foo = 10
}
const Root = (req, res, next) => {
res.json({foo: this.foo}); // TypeError: Cannot read property 'foo' of undefined
}
}
const routes = new Routes();
app.get('/', routes.Root);
app.listen(8080);
Voici une réécriture mineure du code, mais comme certaines des réponses ici l'ont souligné, la fonction elle-même lorsqu'elle est référencée comme cela dans la configuration de la route ignore this
et doit être liée. Pour contourner cela, au lieu d'écrire des fonctions "normales", il vous suffit d'écrire des fonctions de définition de "grosse flèche" qui se lient automatiquement et vous êtes prêt à partir!
essayez d'utiliser le code pour épingler this
:
app.get('/', routes.Root.bind(routes));
Vous pouvez sortir du passe-partout en utilisant la fonction de soulignement bindAll . Par exemple:
var _ = require('underscore');
// ..
var routes = new Routes();
_.bindAll(routes, 'Root')
app.get('/', routes.Root);
J'ai également constaté que es7 vous permet d'écrire le code d'une manière plus élégante:
class Routes {
constructor(){
this.foo = 10
}
Root = (req, res, next) => {
res.json({foo: this.foo});
}
}
var routes = new Routes();
app.get('/', routes.Root);
Cela se produit parce que vous avez passé une méthode en tant que fonction autonome à exprimer. Express ne sait rien de la classe dont il provient, donc il ne sait pas quelle valeur utiliser comme this
lorsque votre méthode est appelée.
Vous pouvez forcer la valeur de this
avec bind
.
app.get('/', routes.Root.bind(routes));
Ou vous pouvez utiliser une construction alternative pour gérer les itinéraires. Vous pouvez toujours utiliser de nombreux avantages syntaxiques pour la programmation orientée objet sans classes.
function Routes() {
const foo = 10;
return {
Root(req, res, next) {
res.json({ foo });
}
};
}
const routes = Routes();
app.get('/', routes.Root);
app.listen(8080);
this
new
ou nonbind
sur chaque routeIl y a une bonne liste de ressources ici , sur pourquoi les classes ES6 ne sont pas aussi bonnes qu'elles le paraissent.
Ou si vous n'aimez pas lier le contexte par routes, vous pouvez éventuellement le lier aux méthodes dans le constructeur de votre classe lui-même.
Par exemple:
constructor() {
this.foo = 10;
this.Root = this.Root.bind(this);
}
Nous avons récemment refactorisé tous nos contrôleurs Express pour qu'ils utilisent une classe de contrôleur de base, et nous avons également rencontré ce problème. Notre solution consistait à faire en sorte que chaque contrôleur lie ses méthodes à lui-même en appelant la méthode d'assistance suivante à partir du constructeur:
/**
* Bind methods
*/
bindMethods() {
//Get methods
const proto = Object.getPrototypeOf(this);
const methods = [
...Object.getOwnPropertyNames(Controller.prototype),
...Object.getOwnPropertyNames(proto),
];
//Bind methods
for (const method of methods) {
if (typeof this[method] === 'function') {
this[method] = this[method].bind(this);
}
}
}
Cela garantit que les deux méthodes de contrôleur parent et toutes les méthodes personnalisées de la classe de contrôleur enfant sont correctement liées (par exemple Foo extends Controller
).
Les réponses ci-dessus semblent un peu trop compliquées. Découvrez ce que j'ai fait ici:
class Routes {
constructor(req, res, next) {
this.req = req;
this.res = res;
this.next = next;
this.foo = "BAR"
// Add more data to this. here if you like
}
findAll (){
const {data, res,} = this; // Or just reference the objects directly with 'this'
// Call functions, do whaterver here...
// Once you have the right data you can use the res obejct to pass it back down
res.json ({foo: this.foo}); // Grabs the foo value from the constructor
}
}
Maintenant, quand il s'agit d'utiliser cette classe, vous pouvez faire quelque chose dans le sens de ceci:
var express = require('express');
var router = express.Router();
var {Routes} = require('./Routes');
router.get('/foo', (req, res, next) => {
new Routes(req, res, next).findAll();
});
Je séparerais les deux fichiers, de sorte que vous ayez juste besoin de la classe Routes
dans votre fichier Router
.
J'espère que cela vous a aidé!