Nodejs,将路由表示为 es6 类
Nodejs, express routes as es6 classes
我想稍微清理一下我的项目,现在我尝试使用 es6 类 作为我的路线。我的问题是 this 总是未定义。
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);
尝试使用代码固定 this
:
app.get('/', routes.Root.bind(routes));
您可以使用下划线 bindAll 函数脱离样板。例如:
var _ = require('underscore');
// ..
var routes = new Routes();
_.bindAll(routes, 'Root')
app.get('/', routes.Root);
我还发现 es7 可以让你用更优雅的方式编写代码:
class Routes {
constructor(){
this.foo = 10
}
Root = (req, res, next) => {
res.json({foo: this.foo});
}
}
var routes = new Routes();
app.get('/', routes.Root);
发生这种情况是因为您将方法作为独立函数传递给了表达。 Express 对它来自的 class 一无所知,因此它不知道在调用您的方法时将哪个值用作 this
。
您可以将 this
的值强制设置为 bind
。
app.get('/', routes.Root.bind(routes));
或者您可以使用另一种构造来管理路由。在没有 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
没有关系
- 您可以避免在每个路由上调用
bind
的复杂性
有一个很好的资源列表 here,说明为什么 ES6 classes 不像它们看起来那么好。
以上回答似乎有点复杂。看看我在这里做了什么:
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
}
}
现在,在使用这个 class 时,您可以按照以下方式做一些事情:
var express = require('express');
var router = express.Router();
var {Routes} = require('./Routes');
router.get('/foo', (req, res, next) => {
new Routes(req, res, next).findAll();
});
我会将这两个文件分开,这样您只需将 Routes
class 放入您的 Router
文件即可。
希望对您有所帮助!
或者,如果您不喜欢为每个路由绑定上下文,您可以选择将其绑定到 class' 构造函数本身中的方法。
例如:
constructor() {
this.foo = 10;
this.Root = this.Root.bind(this);
}
我们最近重构了所有 Express 控制器以使用基本控制器 class,并且 运行 也解决了这个问题。我们的解决方案是通过从构造函数调用以下辅助方法,让每个控制器将其方法绑定到自身:
/**
* 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);
}
}
}
这确保父控制器方法 和 子控制器 class 中的任何自定义方法都正确绑定(例如 Foo extends Controller
)。
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);
这里是对代码的轻微重写,但正如这里的一些答案所指出的那样,在路由配置中引用时,函数本身不知道 this
并且必须被绑定。要解决这个问题,您无需编写 "normal" 函数,只需编写定义 "fat arrow" 自动绑定自身的函数,您就可以开始了!
我想稍微清理一下我的项目,现在我尝试使用 es6 类 作为我的路线。我的问题是 this 总是未定义。
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);
尝试使用代码固定 this
:
app.get('/', routes.Root.bind(routes));
您可以使用下划线 bindAll 函数脱离样板。例如:
var _ = require('underscore');
// ..
var routes = new Routes();
_.bindAll(routes, 'Root')
app.get('/', routes.Root);
我还发现 es7 可以让你用更优雅的方式编写代码:
class Routes {
constructor(){
this.foo = 10
}
Root = (req, res, next) => {
res.json({foo: this.foo});
}
}
var routes = new Routes();
app.get('/', routes.Root);
发生这种情况是因为您将方法作为独立函数传递给了表达。 Express 对它来自的 class 一无所知,因此它不知道在调用您的方法时将哪个值用作 this
。
您可以将 this
的值强制设置为 bind
。
app.get('/', routes.Root.bind(routes));
或者您可以使用另一种构造来管理路由。在没有 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
没有关系 - 您可以避免在每个路由上调用
bind
的复杂性
有一个很好的资源列表 here,说明为什么 ES6 classes 不像它们看起来那么好。
以上回答似乎有点复杂。看看我在这里做了什么:
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
}
}
现在,在使用这个 class 时,您可以按照以下方式做一些事情:
var express = require('express');
var router = express.Router();
var {Routes} = require('./Routes');
router.get('/foo', (req, res, next) => {
new Routes(req, res, next).findAll();
});
我会将这两个文件分开,这样您只需将 Routes
class 放入您的 Router
文件即可。
希望对您有所帮助!
或者,如果您不喜欢为每个路由绑定上下文,您可以选择将其绑定到 class' 构造函数本身中的方法。
例如:
constructor() {
this.foo = 10;
this.Root = this.Root.bind(this);
}
我们最近重构了所有 Express 控制器以使用基本控制器 class,并且 运行 也解决了这个问题。我们的解决方案是通过从构造函数调用以下辅助方法,让每个控制器将其方法绑定到自身:
/**
* 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);
}
}
}
这确保父控制器方法 和 子控制器 class 中的任何自定义方法都正确绑定(例如 Foo extends Controller
)。
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);
这里是对代码的轻微重写,但正如这里的一些答案所指出的那样,在路由配置中引用时,函数本身不知道 this
并且必须被绑定。要解决这个问题,您无需编写 "normal" 函数,只需编写定义 "fat arrow" 自动绑定自身的函数,您就可以开始了!