如何正确地从node.js模块返回一组实例

我想实例化一系列对象,每一个都暴露一个函数,然后将它们作为一个node.js模块返回,以便在我的项目的其他地方使用。

我试着用这个:

function Role(id, ext) { this.id = id; this.ext = ext || []; } Role.prototype.filter = function(req, res, next) { if (!req.user) return res.status(401).send({ "message": "unauthorized" }); if (req.user.role !== this.id && this.ext.indexOf(req.user.role) < 0) return res.status(403).send({ "mesage": "forbidden" }); return next(); }; var Roles = { admin: new Role("admin"), member: new Role("member", ["admin"]) // admin extends member }; module.exports = Roles; 

哪个不起作用,当我的其他模块中使用的任何实例调用filter时,this.id和this.ext没有被定义。

相反,这工作:

 var Role = function(id, ext) { var self = this; self.id = id; self.ext = ext || []; self.filter = function(req, res, next) { if (!req.user) return res.status(401).send({ "message": "unauthorized" }); if (req.user.role !== self.id && self.ext.indexOf(req.user.role) < 0) return res.status(403).send({ "mesage": "forbidden" }); return next(); }; } var Roles = { admin: new Role("admin"), member: new Role("member", ["admin"]) // admin extends member }; module.exports = Roles; 

…但看起来更不起眼

第一个构造有什么问题? 我很新的javascipt oop,但它看起来非常相似,我看到这里和那里有关如何定义类和实例方法与这种语言。

UPDATE

按照要求和澄清这里是如何在我的其他模块中调用函数:

 router.get('/', filter, Roles.admin.filter, function(req, res, next) { // doing some business }); 

this根据函数的调用方式改变它的值

与其他语言相比, this关键字在JavaScript中的作用不同。 我build议你阅读MDN网站上的指南 。

在你的情况下, this是设置为调用者的范围(我想是像restifyexpressjs库)。

你可以validation这一点

 Role.prototype.filter = function(req, res, next) {console.log(this)} 

在第二种情况下,你使用self来保存这个上下文。 如果你尝试使用this你会看到这个值和第一个例子是一样的。

所以你的两个例子以相同的方式工作,但是在第二个例子中,你用self = this作为解决方法。

解决方法

Javascript提供了3个函数来改变这个值,强制一个函数的作用域: apply()call()bind()

在你的情况我很确定bind()是最好的select。

在你的代码的某个地方,基于你正在使用的库,你有这样的东西:

 server.get('/route', Roles.filter); 

你需要改变它

 server.get('route', Roles.filter.bind(Roles)); 

现在,不知道如何调用函数,我相当肯定这是行不通的,但无论如何,你需要的是通过作为bind()类Roles的实例的参数。 通过这种方式, this将被设置为angular色实例的值。

bind(),apply()和call()之间的区别

我说我认为你需要使用bind(),因为它是三个不调用函数的函数中的唯一一个,只是设置范围。 在你的情况下,我认为你正在使用一个库来提供API(由于req,res,next ),所以你不想调用这个函数,只需要引用它。

调用()和apply()来调用函数。 它们之间的唯一区别是你如何传递参数: call()接受一个参数列表, apply()一个数组:

 function.call(scope, arg1, arg2, arg3); function.apply(scope, [arg1, arg2, arg3]); 

你正在放弃函数的上下文,所以你必须bind这个上下文,或者在调用的时候表示它

绑定示例:

 function Role(id, ext) { this.id = id; this.ext = ext || []; // you should understand, that bind creates new function, this time it ok. this.filter = this.filter.bind(this); } Role.prototype.filter = function(req, res, next) { if (!req.user) return res.status(401).send({ "message": "unauthorized" }); if (req.user.role !== this.id && this.ext.indexOf(req.user.role) < 0) return res.status(403).send({ "mesage": "forbidden" }); return next(); }; var Roles = { admin: new Role("admin"), member: new Role("member", ["admin"]) // admin extends member }; module.exports = Roles; 

“意思”的例子:

使用你的初始代码,但当调用方法使用callapplybind

 var filter = admin.filter; filter.call(admin, req, res, next); // just call filter.call(admin, [req, res, next]); // good when you are using arguments server.on('connect', admin.filter.bind(admin)); //if you need it as callback setTimeout(admin.filter.bind(admin, req, res, next)); // if you know // that one, who will call calback will not pass arguments itself.