javascript implementation of lodash “set” method

Tags: , ,



Found this excellent code for _.get vanilla js implementation:

const get = (obj, path, defaultValue) => path.split(".")
.reduce((a, c) => (a && a[c] ? a[c] : (defaultValue || null)), obj)

Now I’m looking for _.set implementation, any help would be appreciated.

Answer

I think this could cover it:

const set = (obj, path, value) => {
    if (Object(obj) !== obj) return obj; // When obj is not an object
    // If not yet an array, get the keys from the string-path
    if (!Array.isArray(path)) path = path.toString().match(/[^.[]]+/g) || []; 
    path.slice(0,-1).reduce((a, c, i) => // Iterate all of them except the last one
         Object(a[c]) === a[c] // Does the key exist and is its value an object?
             // Yes: then follow that path
             ? a[c] 
             // No: create the key. Is the next key a potential array-index?
             : a[c] = Math.abs(path[i+1])>>0 === +path[i+1] 
                   ? [] // Yes: assign a new array object
                   : {}, // No: assign a new plain object
         obj)[path[path.length-1]] = value; // Finally assign the value to the last key
    return obj; // Return the top-level object to allow chaining
};

// Demo
var obj = { test: true };
set(obj, "test.1.it", "hello");
console.log(obj); // includes an intentional undefined value

It is a bit more complex than get, because there is some logic needed to create missing parts of the path in the object, to overwrite primitive values that stand in the way, and to determine whether a new child should better be an array or a plain object.



Source: stackoverflow