Mongoose pre save使用了不正确的"this"上下文?

jaw*_*g35 4 javascript mongoose mongodb node.js ecmascript-6

任何人都可以弄清楚下面我的代码有什么问题吗?

从文档中看起来this,Mongoose .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);
Run Code Online (Sandbox Code Playgroud)

保存用户时,出现以下错误[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();
});
Run Code Online (Sandbox Code Playgroud)

如果我删除它.pre('save')然后它保存罚款当然.我正在使用的Mongoose版本是4.2.6.

Ale*_* B. 6

这里的问题是一个胖箭头功能.您必须使用简单的函数重写回调.这里以小例子来展示差异

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
Run Code Online (Sandbox Code Playgroud)


jaw*_*g35 5

我弄清楚了这个问题.事实证明,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();
        });
    });
});
Run Code Online (Sandbox Code Playgroud)

感谢Michelem让我觉得ES6可能是罪魁祸首.