Confused by how to write OO Javascript to implement simple class pattern

I'm sure this has been asked before, but I am totally befuddled by OO Javascript so I cannot even recognize the same question.

I am trying to write the Javascript class that will execute the following common type of pattern:

var User=require('./models').User();

User.findUserById('1', function(err, user) {console.log(user)});


var newUser            = new User();

// set the user's local credentials
newUser.local.email    = 'simon@infoqual.net';
newUser.local.password = newUser.generateHash('hello');

// save the user
newUser.save(function(err) {
    if (err)
        throw err;
    console.log(newUser); //returns undefined for the attributes set above
    return newUser;
});

At present, none of my getter attributes make it to my inner save function. Here is the code for the whole class I am writing.

exports.User = User;

function User() {
    var user_uuid, local_email, local_password, user=this;

    function generateHash(password) {
        return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
    }

    function validPassword(password, password_compare) {
        return bcrypt.compareSync(password, password_compare);
    }

    function findUserByEmail(email, callback) {
        conn.query("SELECT * FROM users WHERE local_email=$1 LIMIT 1", [email], function (error, result) {
            //var user = this.User;
            if (!error) {
                if (result.rowCount > 0) {
                    local_email = result.rows[0].email;
                    user_uuid = result.rows[0].user_uuid;

                    //load rest of user obj
                    callback(error, user_uuid);
                }


            }
            callback(error, null);

        });


    }

    function findUserById(id, callback) {
        conn.query("SELECT * FROM users WHERE user_uuid='' || $1 LIMIT 1", [id], function (error, result) {
            if (result.rowCount > 0) {
                //update
                user_uuid = result.rows[0].user_uuid;
                local_email = result.rows[0].local_email;
                local_password = result.rows[0].local_password;
                callback(null, user_uuid);
            } else {
                callback(null, null);
            }
        });
    }

    function save(callback) {
        conn.query("SELECT * FROM users WHERE user_uuid='' || $1", [user_uuid], function (error, result) {
            if (error) throw error;
            if (result.rowCount > 0) {
                //update
                conn.query("UPDATE users SET local_email=$1, local_password=$2 WHERE user_uuid=$3", [local_email, local_password, user_uuid], function (error, result) {
                    if (error) throw error;

                    callback(error);
                })
            } else {
                //insert
                conn.query("INSERT INTO users (user_uuid, local_email, local_password) VALUES ($1, $2, $3)", [require('node-uuid').v1(), local_email, local_password], function (error, result) {
                    if (error) throw error;

                    callback(error);
                })
            }
        })
    }

    return {
        user_uuid: user_uuid,

        local: {
            email: local_email,
            password: local_password
        },
        facebook: {
            id: null,
            token: null,
            email: null,
            name: null
        },
        twitter: {
            id: null,
            token: null,
            displayName: null,
            username: null
        },
        google: {
            id: null,
            token: null,
            email: null,
            name: null
        },
        generateHash: generateHash,
        validPassword: validPassword,
        findUserByEmail: findUserByEmail,
        findUserById: findUserById,
        save: save

    }
};

Why does my inner .save function not have access to the local_email and local_password variables that were set in the constructor?

You're going to have to use this.local.local_email (and password) in your save function. Here's the reasoning:

In your constructor, you have local variables for local_email and local_password - these are the ones you're accessing in your save function; When save is called, it checks the local scope (save's own scope, and since these variables aren't there, it checks the next scope up - the constructor scope.

Now, you also have the returned object, which has local.local_email as a property. When the constructor is called, this property is set to undefined (if I'm following the logic correctly). When it's set later, that change only happens on the property on that object. It isn't reflected back to the constructor's local local_email.

So, your functions are accessing a local variable, while you're setting a new value on the property of an object.

I rewrote it this way and it appeared to work, but I am not entire sure why other than to say that I think in the previous example I was mixing different styles of doing JS OO:

var User=new require('./models').User;
var user=new User();

user.findUserById('1', function(err, user) {console.log(user)});


var newUser            = new User();

// set the user's local credentials
newUser.local_email    = 'simon@infoqual.net';
newUser.local_password = newUser.generateHash('hello');

// save the user
newUser.save(function(err) {
    if (err)
        throw err;
    console.log(newUser);

});

This calls:

exports.User = User;

function User() {
    var user=this;
    user.user_uuid=null;
    user.local_email=null;
    user.local_password=null;
    user.generateHash=function (password) {
        return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
    }
    user.validPassword=function (password, password_compare) {
        return bcrypt.compareSync(password, password_compare);
    }
    user.findUserByEmail=function (email, callback) {
        conn.query("SELECT * FROM users WHERE local_email=$1 LIMIT 1", [email], function (error, result) {
            //var user = this.User;
            if (!error) {
                if (result.rowCount > 0) {
                    user.local_email = result.rows[0].email;
                    user.user_uuid = result.rows[0].user_uuid;

                    //load rest of user obj
                    callback(error, user.user_uuid);
                }


            }
            callback(error, null);

        });


    }

    user.findUserById=function (id, callback) {
        conn.query("SELECT * FROM users WHERE user_uuid='' || $1 LIMIT 1", [id], function (error, result) {
            if (result.rowCount > 0) {
                //update
                user.user_uuid = result.rows[0].user_uuid;
                user.local_email = result.rows[0].local_email;
                user.local_password = result.rows[0].local_password;
                callback(null, user.user_uuid);
            } else {
                callback(null, null);
            }
        });
    }

    user.save=function (callback) {
        conn.query("SELECT * FROM users WHERE user_uuid='' || $1", [user.user_uuid], function (error, result) {
            if (error) throw error;
            if (result.rowCount > 0) {
                //update
                conn.query("UPDATE users SET local_email=$1, local_password=$2 WHERE user_uuid=$3", [user.local_email, user.local_password, user.user_uuid], function (error, result) {
                    if (error) throw error;

                    callback(error);
                })
            } else {
                //insert
                user.user_uuid=require('node-uuid').v1();
                conn.query("INSERT INTO users (user_uuid, local_email, local_password) VALUES ($1, $2, $3)", [user.user_uuid, user.local_email, user.local_password], function (error, result) {
                    if (error) throw error;

                    callback(error);
                })
            }
        })
    }
};