Search code examples
javascriptobjectpropertiesdefaultextend

Replacing object's properties with properties from another object in JavaScript, without libraries


I've been using jQuery.extend to replace default properties like this

var Car = function(options){
    var defaultOptions = {
        color: "hotpink",
        seats: {
            material: "fur",
            color: "black",
            count: 4
        },
        wheels: 4
    }
    this.options = $.extend(true,{},defaultOptions,options); 
}

var myCar = new Car({
    color: "blue",
    seats: {
        count: 2,
        material: "leather"
    }
});

alert(myCar.options.color); // "blue"
alert(myCar.options.seats.color); // "black"
alert(myCar.options.seats.count); // 2

While it works great, I'd like to know the best way to achieve similar results without any libraries. I just want to define some default settings in a function and replace them with settings from arguments, would be an overkill to include a library every time I do that.


Solution

  • Basically it's just a recursive use of for..in. You can see the full source of jQuery's implementation in the source code (the line number on that will rot over time, but it's likely to remain in core.js).

    Here's a very basic off-the-cuff:

    function deepCopy(src, dest) {
        var name,
            value,
            isArray,
            toString = Object.prototype.toString;
    
        // If no `dest`, create one
        if (!dest) {
            isArray = toString.call(src) === "[object Array]";
            if (isArray) {
                dest = [];
                dest.length = src.length;
            }
            else { // You could have lots of checks here for other types of objects
                dest = {};
            }
        }
    
        // Loop through the props
        for (name in src) {
            // If you don't want to copy inherited properties, add a `hasOwnProperty` check here
            // In our case, we only do that for arrays, but it depends on your needs
            if (!isArray || src.hasOwnProperty(name)) {
                value = src[name];
                if (typeof value === "object") {
                    // Recurse
                    value = deepCopy(value);
                }
                dest[name] = value;
            }
        }
    
        return dest;
    }