MongoDB连接回调内给类属性赋值报Cannot set property of undefined错误
报错原因
你遇到的报错本质是普通函数的this指向问题:
- 你给
mongodb.connect()传入的是普通function类型的回调,这类回调的this不会继承外层constructor的作用域指向类实例,在严格模式下默认值为undefined,因此你尝试给this.dbo赋值时就会触发类型错误。 - 你打印
db.db('mydb')可以正常输出,是因为这个值是回调函数的入参衍生的结果,和this指向没有关联,自然不会受影响。
解决方法
下面给出3种常用的可行方案:
方案1:将回调替换为箭头函数(最简便)
箭头函数没有独立的this,会自动继承外层作用域的this指向,也就是类的实例对象,修改后代码如下:
class Database { constructor() { this.db_url = "mongodb://127.0.0.1:27017/"; let mongodb = require("mongodb").MongoClient; // 把普通function改为箭头函数 mongodb.connect(this.db_url, { useUnifiedTopology: true }, (err, db) => { if (err) throw err; this.dbo = db.db('mydb'); }) } }
方案2:提前缓存this指向
在构造函数顶部提前把类实例的this存为一个临时变量,回调里直接用这个变量操作属性即可:
class Database { constructor() { // 提前缓存this指向 const _this = this; this.db_url = "mongodb://127.0.0.1:27017/"; let mongodb = require("mongodb").MongoClient; mongodb.connect(this.db_url, { useUnifiedTopology: true }, function(err, db) { if (err) throw err; // 用缓存的_this赋值 _this.dbo = db.db('mydb'); }) } }
方案3:用bind绑定this指向
通过Function.prototype.bind()手动把回调函数的this绑定为类实例:
class Database { constructor() { this.db_url = "mongodb://127.0.0.1:27017/"; let mongodb = require("mongodb").MongoClient; mongodb.connect(this.db_url, { useUnifiedTopology: true }, function(err, db) { if (err) throw err; this.dbo = db.db('mydb'); // 绑定this指向当前类实例 }.bind(this)) } }
额外优化建议
目前mongodb官方的Node.js SDK已经支持Promise写法,你可以用async/await替代回调写法,逻辑更清晰也更容易维护,不过注意构造函数不能直接标记为async,你可以选择封装静态初始化方法来实现:
class Database { constructor() { this.db_url = "mongodb://127.0.0.1:27017/"; this.mongodb = require("mongodb").MongoClient; } // 单独写异步初始化方法 async init() { const db = await this.mongodb.connect(this.db_url, { useUnifiedTopology: true }); this.dbo = db.db('mydb'); } } // 使用示例 (async () => { const db = new Database(); await db.init(); // 后续就可以正常使用db.dbo操作数据库 })();
内容的提问来源于stack exchange,提问作者bshanky
相关产品推荐
相关产品推荐

