我想稍微清理一下我的项目,现在我尝试将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);
答案 0 :(得分:13)
尝试使用代码固定app.get('/', routes.Root.bind(routes));
:
var _ = require('underscore');
// ..
var routes = new Routes();
_.bindAll(routes)
app.get('/', routes.Root);
您可以使用下划线bindAll功能退出样板。例如:
class Routes {
constructor(){
this.foo = 10
}
Root = (req, res, next) => {
res.json({foo: this.foo});
}
}
var routes = new Routes();
app.get('/', routes.Root);
我还发现es7允许您以更优雅的方式编写代码:
Date.now = function () {
return new Date().getTime();
}
var last_group = {
me: false,
time:Date.now()
}
var messages_count = 0;
function addMessage(msg, pseudo, date, me) {
messages_count++;
if(messages_count < 1){
console.log('first message');
createGroup(msg, pseudo, date, me);
last_group.me = me;
} else {
if(last_group.me == me){
if(last_group.time + 10000 > Date.now()) {
//console.log('adding to last group');
addToGroup(msg, pseudo, date, me);
} else {
//console.log('creating new group', last_group.me, me);
createGroup(msg, pseudo, date, me);
}
} else {
//console.log('creating new group', last_group.me, me);
createGroup(msg, pseudo, date, me);
}
}
}
function addToGroup(msg, pseudo, date, me){
$("#group-" + last_group.time).append('<div class="row message' + (me ? ' self' : '') + '">' + pseudo + '<p>' + msg + '</p></div>');
}
function createGroup(msg, pseudo, date, me){
last_group.time = Date.now();
var html = '<div class="group" id="group-' + last_group.time + '"><div class="row message' + (me ? ' self' : '') + '">' + pseudo + ' - ' + Date.now() + '<p>' + msg + '</p></div></div><br>';
//console.log(html);
$("#chatEntries").append(html);
last_group.me = me;
}
setInterval(function () {
addMessage('Hello', 'pseudo', new Date().getTime(), true);
}, 1000);
setInterval(function () {
addMessage('Hello 2', 'pseudo 2', new Date().getTime(), false);
}, 5000);
答案 1 :(得分:8)
这种情况正在发生,因为您已将方法作为独立函数传递来表达。 Express并不知道它来自哪个类,因此在调用方法时,它不知道将哪个值用作this
。
您可以使用this
强制bind
的值。
app.get('/', routes.Root.bind(routes));
或者您可以使用替代构造来管理路线。在没有类的情况下,您仍然可以利用面向对象编程的许多语法优势。
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课程看起来不那么好。
答案 2 :(得分:3)
或者如果你不喜欢绑定每个路由的上下文,你可以选择将它绑定到类的构造函数本身的方法。
E.g:
constructor() {
this.foo = 10;
this.Root = this.Root.bind(this);
}
答案 3 :(得分:2)
上述答案似乎有点过于复杂。查看我在这里所做的事情:
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
}
}
现在,在使用这个课程时,您可以采取以下措施:
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
类放入Router
文件中。
希望这有帮助!
答案 4 :(得分:2)
我们最近将所有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);
}
}
}
这确保父控制器方法和子对象类中的任何自定义方法都正确绑定(例如Foo extends Controller
)。
答案 5 :(得分:2)
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
,必须对其进行绑定。为了解决这个问题,您不必编写“常规”功能,而只需编写定义“胖箭头”功能即可自动绑定自身,那么您就很好了!