Safely setting object properties with dot notation strings in JavaScript What my function does:
Safely sets object properties with dot notation strings in JavaScript.
That is to say, it allows setting a nested property on an object using a string such as &quot;a.b.c&quot;.
For example: set(obj, &quot;a.b.c&quot;, value) would be equivalent to a.b.c = value
Some notes on intended behavior

When setting a property at a given path, if any portion of that path doesn't exist, it should be created
When creating a path portion, if the next key in the path is NOT an integer, the current portion should be created as an object
When creating a path portion, if the next key in the path is an integer, the current portion should be created as an array

Why?
I'd like to be able to set deeply nested properties on an object in an environment where I can't be sure that all the properties in the path will always exist and I don't want to deal with the logic of checking for and setting each key manually in more than one place. This allows me to quickly set the needed value without caring if the keys were present previously or not.


/**
 * Set the value for the given object for the given path
 * where the path can be a nested key represented with dot notation
 *
 * @param {object} obj   The object on which to set the given value
 * @param {string} path  The dot notation path to the nested property where the value should be set
 * @param {mixed}  value The value that should be set
 * @return {mixed}
 *
 */
function set(obj, path, value) {
    // protect against being something unexpected
    obj = typeof obj === 'object' ? obj : {};
    // split the path into and array if its not one already
    var keys = Array.isArray(path) ? path : path.split('.');
    // keep up with our current place in the object
    // starting at the root object and drilling down
    var curStep = obj;
    // loop over the path parts one at a time
    // but, dont iterate the last part,
    for (var i = 0; i &lt; keys.length - 1; i++) {
        // get the current path part
        var key = keys[i];

        // if nothing exists for this key, make it an empty object or array
        if (!curStep[key] &amp;&amp; !Object.prototype.hasOwnProperty.call(curStep, key)){
            // get the next key in the path, if its numeric, make this property an empty array
            // otherwise, make it an empty object
            var nextKey = keys[i+1];
            var useArray = /^\+?(0|[1-9]\d*)$/.test(nextKey);
            curStep[key] = useArray ? [] : {};
        }
        // update curStep to point to the new level
        curStep = curStep[key];
    }
    // set the final key to our value
    var finalStep = keys[keys.length - 1];
    curStep[finalStep] = value;
};



/** Usage **/

console.log('setting non existant a.b.c to "some value":');
var test = {};
set(test, 'a.b.c', 'some value');
console.log(test);

console.log('updating a.b.c to "some new value":');
set(test, 'a.b.c', 'some new value');
console.log(test);

console.log('setting non existant a.b.0 to "some value":');
var test = {};
set(test, 'a.b.0', 'some value');
console.log(test);

console.log('updating a.b.0 to "some new value":'); 
set(test, 'a.b.0', 'some new value');
console.log(test);
obj = typeof obj === 'object' ? obj : {};


When obj argument points to something other than object you will create one. Like in set("foo", "a.b.c", "Yay!"). I guess you want to return it at function end or it will be lost.

Other notes:


/^\+?(0|[1-9]\d*)$/ allows + in integer key inputs
you may use isNaN(+nextKey) instead of regular expression, but beware float or signed numbers
finalStep is a bit misleading name. You may use key = keys[keys.length - 1] instead.