【问题标题】:Mongoose pre save is using incorrect "this" context?Mongoose 预保存使用了不正确的“this”上下文?
【发布时间】:2016-02-19 20:36:55
【问题描述】:

谁能弄清楚我下面的代码有什么问题?

从文档看来,Mongoose 中的 this .pre('save') 方法应该是模型本身,但在我下面的代码中 this 最终是一个空对象。

const Mongoose = require('./lib/database').Mongoose;
const Bcrypt = require('bcrypt');

const userSchema = new Mongoose.Schema({
    email: { type: String, required: true, index: { unique: true } },
    password: { type: String, required: true }
});

userSchema.pre('save', (next) => {

    const user = this;

    Bcrypt.genSalt((err, salt) => {

        if (err) {
            return next(err);
        }

        Bcrypt.hash(user.password, salt, (err, encrypted) => {

            if (err) {
                return next(err);
            }

            user.password = encrypted;
            next();
        });
    });
});

const User = Mongoose.model('User', userSchema);

保存用户时,我收到以下错误[Error: data and salt arguments required]

function createUser(email, password, next) {

    const user = new User({
        email: email,
        password: password
    });

    user.save((err) => {

        if (err) {
            return next(err);
        }

        return next(null, user);
    });
}

createUser('test@email.com', 'testpassword', (err, user) => {

    if (err) {
        console.log(err);
    }
    else {
        console.log(user);
    }

    process.exit();
});

如果我删除.pre('save'),那么它当然可以保存。我使用的 Mongoose 版本是 4.2.6。

【问题讨论】:

  • 首先,为什么要使用const?改用var,然后在脚本引用记录而不是模型中的this
  • 我正在使用const,因为这些变量永远不会改变。我尝试更改为var 并且代码运行相同。

标签: javascript node.js mongodb mongoose ecmascript-6


【解决方案1】:

这里的问题是fat arrow functions。你必须用简单的函数重写你的回调。这里展示差异的小例子

var obj = {};

obj.func1 = function () {
    console.log(this === obj);
};

obj.func2 = () => {
    console.log(this === obj);
};

obj.func1(); // true
obj.func1.bind(obj)(); // true

obj.func2(); // false
obj.func2.bind(obj)(); // false

【讨论】:

  • 谢谢。我刚刚弄清楚了这一点,并在您发布此内容时写下了自己的答案。
  • 它们只是“箭头函数”,而不是“胖箭头函数”。
  • 一个箭头函数表达式(也称为胖箭头函数)(с) MDN
  • 谢谢!一千遍谢谢你!无法弄清楚发生了什么,因为我似乎按照信中的每一条说明进行操作......作为一个 js 菜鸟,箭头函数和简单函数之间的区别还没有留在我的脑海中。这个肯定会的!再次感谢。
【解决方案2】:

我能够找出问题所在。事实证明,ES6 中的箭头函数保留了声明作用域的上下文,而不是使用调用作用域的上下文,因此将代码更改为以下解决了问题。

userSchema.pre('save', function (next) {

    Bcrypt.genSalt((err, salt) => {

        if (err) {
            return next(err);
        }

        Bcrypt.hash(this.password, salt, (err, encrypted) => {

            if (err) {
                return next(err);
            }

            this.password = encrypted;
            next();
        });
    });
});

感谢 Michelem 让我知道 ES6 可能是罪魁祸首。

【讨论】:

  • 同样使用箭头函数从声明范围中捕获this,不再需要声明user 变量。
  • 箭头函数导致了我的问题,感谢您指出上下文/范围提示!
【解决方案3】:

我认为应该是:

userSchema.pre('save', (next) => {

    var user = this;

    // Try this
    // console.log(user);

    Bcrypt.genSalt(function (err, salt) {

        if (err) {
            return next(err);
        }

        Bcrypt.hash(user.password, salt, null, function (err, encrypted) {

            if (err) {
                return next(err);
            }

            user.password = encrypted;
            next();
        });
    });
});

但请检查用户是否是正确的对象。

【讨论】:

  • 还是不行。除了将 const 更改为 var 并将语法更改回 ES5 之外,这段代码与我的代码有何不同?
猜你喜欢
  • 2021-10-16
  • 2018-06-27
  • 2016-09-18
  • 2015-12-07
  • 1970-01-01
  • 1970-01-01
  • 2016-02-01
  • 1970-01-01
  • 2012-09-17
相关资源
最近更新 更多