Search code examples
javascriptprototype

Why myObject.function() throwing 'is not a function' error? (trying to learn functional instantiation)


I am trying to create a class using a function and giving it some props and a method. If I do the same thing in C# in class-based way and call the mothod this will work fine but in JS it gives me an error. My question is why it behaves in a different way.

code snippet:

function Animal (name) {
    let animal = {}
    animal.name = name;
    animal.eat = function (){ 
        console.log(`${this.name} is eating`)
    }
}

let myAnimal = new Animal('dog');
console.log(myAnimal.eat()); //Uncaught TypeError: myAnimal.eat is not a function at proto.js:11

Solution

  • well if Animal is going to act as a constructor of your sort of class, then you would need to write it like a proper constructor, i.e. drop the let animal = {} bit, and just set properties on this:

    function Animal (name) {
        this.name = name;
        this.eat = function (){ 
            console.log(`${this.name} is eating`)
        }
    }
    
    let myAnimal = new Animal('dog');
    myAnimal.eat();

    now this approach has the downside of creating a new function eat() for each instance of Animal instead of binding an existing function eat() to each instance, which is what happens normally with classes. that you can achieve by this:

    function Animal (name) {
        this.name = name;
    }
    
    Animal.prototype.eat = function (){ 
      console.log(`${this.name} is eating`)
    }
    
    let myAnimal = new Animal('dog');
    myAnimal.eat();

    which is actually the proper way people used to define classes in javascript before class was introduced.

    however, you can also drop the whole class-like concept, and just have an Animal() function that gives out an object with desired properties:

    function Animal (name) {
        let animal = {};
        animal.name = name;
        animal.eat = function (){ 
            console.log(`${this.name} is eating`)
        }
        
        return animal;
    }
    
    let myAnimal = Animal('dog');
    myAnimal.eat();

    note how in this approach you have let myAnimal = Animal('dog') instead of let myAnimal = new Animal('dog'), as Animal() is no longer a constructor.

    reminder: this is an explanation of how you can instantiate objects with a function, and by no means the recommended way of defining classes in javascript. in older environments, the prototype approach is the recommended way, for newer environments, just use class.