如何从节点.js模块正确返回一组实例

How to properly return a set of instances from a node.js module

本文关键字:实例 一组 返回 节点 js 模块      更新时间:2023-09-26

我想实例化一系列对象,每个对象公开一个函数,然后将它们作为节点.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;

这不起作用,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很陌生,但它看起来与我在这里和那里看到的关于如何使用这种语言定义类和实例方法的内容非常相似。

更新

根据要求并澄清一下,这是我的另一个模块中如何调用函数:

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

你正在失去函数的上下文,所以你必须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.
this根据

函数的调用方式更改其值

与其他语言相比,this关键字在 JavaScript 中的工作方式不同。我建议您阅读MDN网站上的指南。

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

您可以验证是否执行

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

在第二种情况下,您可以使用self来保存this的上下文。如果您尝试使用this您将看到this的值与第一个示例相同。

因此,您的两个示例以相同的方式工作,但在第二个示例中,您使用self = this作为解决方法。

解决方法

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

在您的情况下,我很确定bind()是最佳选择。

在你的代码中的某个地方,根据你正在使用的库,你有类似的东西:

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

您需要将其更改为

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

现在,不知道你如何调用函数,我很确定这行不通,但无论如何,你需要的是作为bind()类角色实例的参数传递。这样this将设置为该角色实例的值。

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

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

call() 和 apply() 改为调用函数。它们之间的唯一区别是你传递参数的方式:call()接受参数列表,apply()数组:

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