I'm trying to re-use a variable named user
in the following function:
UserModel.prototype.authenticate = function (doc, callback) {
// check to see if the username exists
this.users.findOne({ username: doc.username }, function (err, user) {
if (err || !user)
return callback(new Error('username not found'));
// hash the given password using salt from database
crypto.pbkdf2(doc.password, user.salt, 1, 32, function (err, derivedKey) {
if (err || user.password != derivedKey)
return callback(new Error('password mismatch'));
// explicitly define the user object
var user = {
_id: user._id,
type: user.type,
username: user.username,
displayname: user.displayname
};
return callback(err, user);
});
});
};
I attempt to redefine the user
variable inside of the pbkdf2
callback function. This does not work as I would expect. The lines where I compare user.password != derivedKey
breaks, because user
is undefined here during run-time. Shouldn't user
still be the instance from the findOne
callback method parameter? If I change either of the two user
variables to be called something else, it works.
I could just rename the variables, but that would still leave me wondering.
The problem is, you declare a variable called user
within the function-context:
var user = { };
This will overwrite / overlap the user
which was declared as formal parameter by the outer function-context. It does not help to declare that variable after your if-statement. Variables declared by var
and function declarations get hoisted up at parse-time, so infact, that var user
statement is placed just on top of your inner function.
The answer is that because of hoisting, even though you declare the variable users
(var users
) after you use it in other expressions (user.password != derivedKey
), it gets parsed first, leaving the original users
reference overwritten.
There are several docs on hoisting out there and it may be a good idea to take a peak at them.