3

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.

user1463028
  • 73
  • 2
  • 4

3 Answers3

4

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;
}
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • If the OP wants to keep the API, then jQuery is a good start but if the OP is prepared to change (simplify) the API a purpose built extend can be shorter, more efficient and more robust (e.g. the jQuery *isPlainObject* is pretty ordinary and not necessary, nor is *isFunction* or *isArray*). – RobG Jul 25 '12 at 09:52
  • What RobG said, the jQuery implementation seems like a quite a bit of code. I was wondering if there's any workarounds, or other ways to tackle this issue. – user1463028 Jul 26 '12 at 09:43
  • 1
    I'm trying to make an easy-to-use, independent code snippet that's basically just one function with a few methods inside. Kind of like a jQuery plugin, but without dependency on jQuery. I'd want to let the user define all the options in a single object for the sake of readable code, but I want to define default values for everything so the user doesn't need to change anything if he's happy with the default looks and functionality. – user1463028 Jul 26 '12 at 09:53
  • @user1463028: I was just referring to jQuery's as an example of a fairly thoroughly-done version that's survived a lot of use. The fundamental point is that it's just a recursive use of `for..in`. I've added a very basic one, but why not use something that's been thoroughly tested instead? Yes, it will take a bit more time to understand and unpick, but... :-) Best, – T.J. Crowder Jul 26 '12 at 09:56
0

You can emulate jQuery's api "extend", just like upstairs said. I think there's no better way to manage to do this. So, I think jQuery's api is appropriate.

jasonjifly
  • 347
  • 1
  • 3
  • 15
0

In ES6 it was introduced spread operator.

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

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

References:

vee
  • 4,506
  • 5
  • 44
  • 81