1

I was messing around with Javascript prototypes, and I don't understand why this works:

function User(un) {
    this.username = un;
}

User.prototype.method_name = function() {
    return this.username;
};

var user = new User("Michael");

console.log(user.method_name());

But this doesn't:

function User(un) {
    this.username = un;
    return{
        getUsername: function (){
            return username;
        },
        setUsername: function(username) {
            username = un;
        }
    };
}

User.prototype.method_name = function() {
    return this.username;
};

var user = new User("Michael");    
console.log(user.method_name());

Why does adding the "return" statement throw Object #<Object> has no method 'method_name'?

2 Answers 2

4

Because in the second example, the object you return isn't a new "User" instance, but a plain Object instance.

When you use the new key word with a constructor, the object returned by default inherits from the constructor's prototype, so you have an inheritance chain like:

user -> User.prototype -> Object.prototype -> null

If you return some other object, it doesn't inherit from the constructor and you have an inheritance chain like:

user -> Object.prototype -> null
Sign up to request clarification or add additional context in comments.

3 Comments

+1, also OP the behavior for returning objects from a constructor is defined at step 9 of ES5 #13.2.2
Doesn't the first example return also, just undefined? I don't see why explicitly returning something has an effect on how new operates.
@M1Reeder—in non–strict mode, a function called with new must return an object, so if you don't specify one, or attempt to return a primitive, it returns the object referenced by this, which is the new instance. If you do return some other object, then it isn't an instance.
3

Returning an object circumvents the usual return value of a constructor, which is the this variable. Instead of returning this, you're returning some other object, and that object doesn't have a username property or a method_name method. This is roughly what happens at each point in the code:

function User(un) {
    this.username = un; // puts username on the 'this' object

    // returns an entirely different, unrelated object that doesn't use User's prototype
    return{
        getUsername: function (){
            return un;
        },
        setUsername: function(username) {
            un = username;
        }
    };
}

// sets method_name on the prototype of the 'this' object for User
User.prototype.method_name = function() {
    return this.username;
};

var user = new User("Michael"); // passes a new User.prototype as the implicit 'this' in the User function   
console.log(user.method_name());

Instead, try this:

function User(un) {
    this.username = un;
    this.getUsername = function (){
        return un;
    };
    this.setUsername = function(username) {
        un = username;
    };
}
User.prototype.method_name = function() {
    return this.username;
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.