Inf*_*Dev 10 javascript node.js express ecmascript-6 es6-class
我正在使用Node.js,Express.js和MongoDB制作应用程序.我正在使用MVC模式,并且还有单独的路由文件.我正在尝试创建一个Controller类,其中一个方法调用在其中声明的另一个方法.但我似乎无法做到这一点.我得到"无法读取未定义的属性".
index.js文件
let express = require('express');
let app = express();
let productController = require('../controllers/ProductController');
app.post('/product', productController.create);
http.createServer(app).listen('3000');
Run Code Online (Sandbox Code Playgroud)
ProductController.js文件
class ProductController {
constructor(){}
create(){
console.log('Checking if the following logs:');
this.callme();
}
callme(){
console.log('yes');
}
}
module.exports = new ProductController();
Run Code Online (Sandbox Code Playgroud)
当我运行这个时,我收到以下错误消息:
Cannot read property 'callme' of undefined
Run Code Online (Sandbox Code Playgroud)
我已经运行了这个代码,只需要进行一些修改,如下所示,它可以工作.
class ProductController {
constructor(){}
create(){
console.log('Checking if the following logs:');
this.callme();
}
callme(){
console.log('yes');
}
}
let product = new ProductController();
product.create();
Run Code Online (Sandbox Code Playgroud)
为什么一个工作而另一个工作?救命!
当您将create方法作为方法传递时,它可能会如您所期望的那样在不同的上下文 ( ) 中调用this。您可以绑定它:
app.post('/product', productController.create.bind(productController));
Run Code Online (Sandbox Code Playgroud)
还有许多其他方法可以确保this引用正确的对象。
例如用函数(箭头或经典)包裹它:
app.post('/product', (...args) => productController.create(...args));
Run Code Online (Sandbox Code Playgroud)
或者在构造函数中绑定方法:
constructor() {
this.create = this.create.bind(this);
}
Run Code Online (Sandbox Code Playgroud)
您的方法正在反弹到Layerexpress内的类中,从而失去了其原始上下文。表达处理路由的方法是将每个路由包装在一个Layer类中,该类将路由回调分配给自己:
this.handle = fn;
Run Code Online (Sandbox Code Playgroud)
这就是您出现问题的地方,此分配会自动将函数上下文重新绑定到Layer。这是一个演示问题的简单示例:
function Example() {
this.message = "I have my own scope";
}
Example.prototype.logThis = function() {
console.log(this);
}
function ReassignedScope(logThisFn) {
this.message = "This is my scope now";
// simulation of what is happening within Express's Layer
this.logThis = logThisFn;
}
let example = new Example()
let scopeProblem = new ReassignedScope(example.logThis);
scopeProblem.logThis(); // This is my scope now
Run Code Online (Sandbox Code Playgroud)
其他人已经指出了解决方案,该解决方案是将您的方法显式绑定到ProductController实例:
app.post('/product', productController.create.bind(productController));
Run Code Online (Sandbox Code Playgroud)