Search code examples
javascriptinheritanceapplymixinsdelegation

How is a new object instantiated from a function that only invokes another constructor function?


function Product(name, price) {
    this.name = name;
    this.price = price;
}
  
function Food(name, price) {
    Product.call(this, name, price); 
}

const item = new Food('cheese', 50)

console.log(item.name)

I don't get this. How is the new object item instantiated from the Food function when it's not a constructor, but it only contains another function which is then invoked with the call() method that passes this which refers to the newly instantiated object? How is the Product function becoming the constructor of the item object? I don't understand how is that transfer happening, since Food is not a constructor, and Product.call() does not return the content of the Product function which would've made the Food function a constructor.

Can somebody explain this to me?


Solution

  • You might want to consider the following snippets:

    const item = {
        name: 'cheese',
        price: 50,
    };
    

    is absolutely equivalent to

    const item = {};
    item.name = 'cheese';
    item.price = 50;
    

    is (apart from the prototype of item) equivalent to

    function Food() {}
    const item = Object.create(Food.prototype);
    item.name = 'cheese';
    item.price = 50;
    

    is absolutely equivalent to

    function Food() {}
    const item = new Food();
    item.name = 'cheese';
    item.price = 50;
    

    is absolutely equivalent to

    function Food(name, price) {
        this.name = name;
        this.price = price;
    }
    const item = new Food('cheese', 50);
    

    is absolutely equivalent to

    function setProductProperties(obj, name, price) {
        obj.name = name;
        obj.price = price;
    }
    function Food(name, price) {
        setProductProperties(this, name, price); 
    }
    const item = new Food('cheese', 50);
    

    is absolutely equivalent to the code in your question

    function Product(name, price) {
        this.name = name;
        this.price = price;
    }  
    function Food(name, price) {
        Product.call(this, name, price); 
    }
    const item = new Food('cheese', 50);
    

    They all have the same outcome - an item object with properties .name and .price. The difference is only in how they achieve that, with varying levels of abstraction through function calls. Having constructors just makes it easier to instantiate multiple objects with the same shape, defining that shape only in a single place.