Question

I'm having difficulty understanding why this code isn't working. From what I can tell my syntax is correct but the console.log complains that my person object doesn't have a method setFirstName. Here's what I've got so far:

HTML

<input type="text" id="firstName">

JQuery

$(document).ready( function() {
    $("#firstName").on("change", getFirstName);

    var person = new Person();

    function Person() {
        this.firstName = "";
    }

    Person.prototype = {
        setFirstName: function(name) {
            this.firstName = name;
            console.log("My first name is: " + person.firstName);
        }
    }

    function getFirstName() {
        var firstName = $("#firstName").val();
        person.setFirstName(firstName);
    }
});

The console log displays this error and points to the "person.setFirstName(firstName)" line of code:

Uncaught TypeError: Object #<Person> has no method 'setFirstName'

It's puzzling to me that it recognizes the Person object exists but then doesn't see the method setFirstName. What have I done wrong? Help me master coders, you're my only hope.

Was it helpful?

Solution

The current code assigns the object literal to the prototype of Person. Instead, assign the function to the setFirstName property of Person.prototype:

Person.prototype.setFirstName = function(name) {
        this.firstName = name;
        console.log("My first name is: " + this.firstName);
}

Explanation

To understand the error, we must first understand how prototypes work in Javascript. When an instance of an object is created using a function constructor the instance's prototype is assigned the prototype of the constructor function.

function MyObject(){}
var myObj = new MyObject();
console.log(myObj.__proto__ == MyObject.prototype); //logs true

In the provided code, an instance of Person is created using the Person constructor function. This causes person to be assigned the prototype of Person.

var person = new Person();
function Person() {
    this.firstName = "";
}
console.log(person.__proto__); //logs Person{}

Then the object literal containing the setFirstName function is assigned to the prototype of Person.

Person.prototype = {
    setFirstName: function(name) {
        this.firstName = name;
        console.log("My first name is: " + person.firstName);
    }
}

At this point the Person prototype is assigned to the object literal with the function, however the instance person was created before the object literal was assigned to Person's prototype. The instance person's prototype does not refer to the object literal that was assigned to Person.prototype after its instantiation.

console.log(person.__proto__ == Person.prototype); //logs false

While not recommended, we could have resolved or avoided this issue by creating the person instance after the new prototype was assigned, such as:

$(document).ready( function() {
    $("#firstName").on("change", getFirstName);

    function Person() {
        this.firstName = "";
    }

    Person.prototype = {
        setFirstName: function(name) {
            this.firstName = name;
            console.log("My first name is: " + person.firstName);
        }
    }

    var person = new Person();
    function getFirstName() {
        var firstName = $("#firstName").val();
        person.setFirstName(firstName);
    }
});

It is much better to assign the method to a property of Person.prototype so that we do not create temporial coupling that dictates when an instance of Person can be created.

This article does an excellent job of explaining prototype and would be worth the read.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top