javascript Nodejs,将路由表示为 es6 类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33798933/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Nodejs, express routes as es6 classes
提问by Michael Malura
I want to clean up my project a bit and now i try to use es6 classes for my routes. My problem is that thisis always undefined.
我想稍微清理一下我的项目,现在我尝试将 es6 类用于我的路线。我的问题是这始终是未定义的。
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);
采纳答案by Balkana
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);
Here is minor rewrite of the code, but as some of the answers here pointed out, the function itself when referenced like that in the route config is unaware of this
and has to be binded. To get around this, instead of writing "normal" functions, you just have to write define "fat arrow" functions that automatically bind themselves and you are good to go!
这是对代码的小幅重写,但正如这里的一些答案所指出的那样,在路由配置中像这样引用时,函数本身是不知道的this
,必须绑定。为了解决这个问题,您不必编写“普通”函数,而只需编写定义自动绑定自己的“粗箭头”函数,就可以了!
回答by zag2art
try to use the code to pin this
:
尝试使用代码来固定this
:
app.get('/', routes.Root.bind(routes));
You can get out of the boilerplate using underscore bindAllfunction. For example:
您可以使用下划线bindAll函数摆脱样板。例如:
var _ = require('underscore');
// ..
var routes = new Routes();
_.bindAll(routes, 'Root')
app.get('/', routes.Root);
I also found that es7 allows you to write the code in a more elegant way:
我还发现 es7 允许您以更优雅的方式编写代码:
class Routes {
constructor(){
this.foo = 10
}
Root = (req, res, next) => {
res.json({foo: this.foo});
}
}
var routes = new Routes();
app.get('/', routes.Root);
回答by Dan Prince
This is happening because you've passed a method as a standalone function to express. Express doesn't know anything about the class that it comes from, therefore it doesn't know which value to use as this
when your method is called.
发生这种情况是因为您已将方法作为独立函数传递来表达。Express 对它来自的类一无所知,因此它不知道this
在调用方法时使用哪个值。
You can force the value of this
with bind
.
您可以强制使用this
with的值bind
。
app.get('/', routes.Root.bind(routes));
Or you can use an alternative construct for managing routes. You can still make use of a lot of the syntactic benefits for object oriented programming without classes.
或者您可以使用替代结构来管理路由。您仍然可以在没有类的情况下利用面向对象编程的许多语法优势。
function Routes() {
const foo = 10;
return {
Root(req, res, next) {
res.json({ foo });
}
};
}
const routes = Routes();
app.get('/', routes.Root);
app.listen(8080);
- You won't have to worry about the value of
this
- It doesn't matter whether the function is called with
new
or not - You can avoid the complexity of calling
bind
on each route
- 您将不必担心价值
this
- 不要紧的功能是否被调用
new
或不 - 您可以避免
bind
在每条路线上调用的复杂性
There's a good list of resources here, on why ES6 classes are not as good as they might seem.
有良好的资源列表在这里,为什么ES6类是不如他们看起来。
回答by John Edward Escuyos
Or if you don't like binding the context per routes, you can optionally bind it to methods in your class' constructor itself.
或者,如果您不喜欢为每个路由绑定上下文,您可以选择将其绑定到类的构造函数本身中的方法。
E.g:
例如:
constructor() {
this.foo = 10;
this.Root = this.Root.bind(this);
}
回答by Adam Reis
We recently refactored all our Express controllers to use a base controller class, and also ran into this issue. Our solution was to have each controller bind its methods to itself by calling the following helper method from the constructor:
我们最近重构了所有 Express 控制器以使用基本控制器类,并且也遇到了这个问题。我们的解决方案是通过从构造函数调用以下辅助方法,让每个控制器将其方法绑定到自身:
/**
* 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);
}
}
}
This ensures that both the parent Controller methods andany custom methods in the child controller class are bound correctly (e.g Foo extends Controller
).
这确保了父控制器方法和子控制器类中的任何自定义方法都被正确绑定(例如Foo extends Controller
)。
回答by James111
The above answers seem a bit over complicated. Checkout what I've done here:
上面的答案似乎有点过于复杂。看看我在这里做了什么:
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
}
}
Now when it comes to using this class you can do something along the lines of this:
现在,当谈到使用这个类时,你可以按照以下方式做一些事情:
var express = require('express');
var router = express.Router();
var {Routes} = require('./Routes');
router.get('/foo', (req, res, next) => {
new Routes(req, res, next).findAll();
});
I would seperate the two files, so that you just require the Routes
class into your Router
file.
我会将这两个文件分开,以便您只需Routes
要将该类放入您的Router
文件中。
Hope this helped!
希望这有帮助!