Borune
Borune

Reputation: 29

Javascript: make an deep clone/extend/copy function that does not make any garbage for GC

I would like to make an extendDeep() function that does not make any garbage for GC.

The garbage collector need to be as inactive as possible. ref.: https://www.scirra.com/blog/76/how-to-write-low-garbage-real-time-javascript

This is the extendDeep() function I want to modify:

function extendDeep(parent, child) {
    var i, toStr = Object.prototype.toString,
        astr = "[object Array]";

    child = child || {};

    for (i in parent) {
        if (parent.hasOwnProperty(i)) {
            if (typeof parent[i] === 'object') {
                child[i] = (toStr.call(parent[i]) === astr) ? [] : {};
                extendDeep(parent[i], child[i]);
            } else {
                child[i] = parent[i];
            }
        }
    }
    return child;
}

The function does not have to return anything. since the retuned object is why the garbage is made.

It is assumed that all the propertis of the parent object is available by reference (reuse of objects)

Upvotes: 1

Views: 616

Answers (3)

Programming Guy
Programming Guy

Reputation: 7461

This is actually a more interesting question than I first thought. After reading the suggested link it is clear the articles author is advocating object pooling. So something like

function Pool(fConstructor, nMaxSize, fCleanFunction) {
    this.aObjectPool = [];
    this.nMaxSize = nMaxSize;
    this.fCleanFunction = fCleanFunction;
    this.fConstructor = fConstructor;
}

Pool.prototype.get = function() {
    return this.aObjectPool.pop() || new this.fConstructor();
}

Pool.prototype.recycle = function(oObject) {
    if (aObjectPool.length < this.nMaxSize) {
        fCleanFunction(oObject);
        this.aObjectPool.push(oObject);
    }
}       

function wipeArray(aArray) {
    aArray.length = 0;
}

function wipeObject(oObject) {
    for (var p in obj) {
        if (obj.hasOwnProperty(p)) {
            delete obj[p];
        }
    }
};

var oArrayPool = new Pool(Array, 50, wipeArray);

var oObjectPool = new Pool(Object, 50, wipeObject);

could be used to implement the pool. Then you'd replace the []'s and {}'s in the extend deep function with pool.get()'s.

Of course, for this to work you'd also need to ensure you were recycling old objects and arrays rather than just leaving them for garbage collection.

Upvotes: 0

Mike Samuel
Mike Samuel

Reputation: 120546

A JS interpreter might avoid creating a string when doing toStr.call(parent[i]) but if you can't rely on them doing that optimization then you can avoid creating strings in the very common case by changing

toStr.call(parent[i]) === astr

to

parent[i] instanceof Array  // Is a regular array.
|| (!(parent[i] instanceof Object)  // Is cross-frame
    && 'number' === typeof parent[i].length  // Might be an array
    && toStr.call(parent[i]) === astr)  // So check the hidden [[Class]] property.

If you know you're dealing with objects created by constructors from the same frame (so no cross-frame object sharing) then you can get by with just

parent[i] instanceof Array

Upvotes: 1

Programming Guy
Programming Guy

Reputation: 7461

The 1st thing you need to decide is whether you want a clone or a copy, they are 2 different things.

The code you have given does a copy (and not a great one, because the use of hasOwnProperty means you could easily end up with non functional copies). A clone would be something like.

function Clone(){}
function clone(object) {        
    Clone.prototype = object;

    return new Clone();
}

var objectToClone = {};
var clonedObject = clone(objectToClone);

The difference being that for a copy, changes to the original object will not affect the copy. For a clone, changes to the original object will affect the clone unless the clone has overwritten the property.

Upvotes: 0

Related Questions