Search code examples
javascriptperformancejavascript-objects

JS - Is there a memory/performance difference between an external function to modify objects, compared to an internal function?


Say I'm creating lots of objects in the following way:

function Bird() {
    this.prop1 = 1;
    this.prop2 = 2;

    ...
}

const bird1 = new Bird();
const bird2 = new Bird();

Is it more memory- or resource-intensive to have the same function nested within every Bird object, compared to a single external function?

Internal:

function Bird() {
    this.prop1 = 1;
    this.prop2 = 2;

    this.modFunc = function() {
        this.prop1 = this.prop1 * 10;
    }
}

const bird = new Bird();

bird.modFunc();

External:

function Bird() {
    this.prop1 = 1;
    this.prop2 = 2;
}

function modFunc(b) {
    b.prop1 = b.prop1 * 10;
}

const bird = new Bird();

modFunc(bird);

This is purely educational for myself. I'm not (currently) dealing with anything where I have so many objects that this makes any sort of difference. But if there were many millions or more objects, would one have an advantage over the other?

To me, the latter seems more efficient, with the external function. Because with the internal version, I could do something like:

bird.modFunc = function() {...};

and rewrite the internal function. So each object must therefor have its own internal reference to its own internal function. Right?


Solution

  • There's a small memory difference. With an internal function, every Bird instance will have a modFunc property that points to the function. With an external function, there's just one global variable containing that function.

    Also, each of these properties will refer to a distinct function. It might be possible for the compiler to arrange for them to share code, but there will still be memory overhead for the function headers.

    The normal way to add this function would be to define it on the prototype, not a global variable:

    Bird.prototype.modFunc = function() {
        this.prop1 = this.prop1 * 10;
    }
    
    bird = new Bird();
    bird.modFunc();
    

    This has the same memory overhead as the global variable, but it doesn't affect the global namespace. It has a small time expense, because looking up the function name requires following the prototype chain. But I think most JavaScript engines will optimize this in the JIT compiler, since prototype functions are at the heart of OOP in JS.