【问题标题】:javascript implementation of lodash "set" methodlodash“set”方法的javascript实现
【发布时间】:2019-07-11 00:37:37
【问题描述】:

找到this excellent code 用于_.get vanilla js 实现:

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

现在我正在寻找 _.set 的实现,我们将不胜感激。

【问题讨论】:

  • 你可以简单地复制 lodash 源代码方法.. import lodash.使用get,并复制转译后的代码
  • 我相信_.get 的这种实现过于简单化并且无法工作,例如具有数组索引或对象属性的数组/引用符号。所以你不能写get("a.b[3].c['prop']")

标签: javascript ecmascript-6 lodash


【解决方案1】:

我认为这可以覆盖它:

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

它比get 复杂一点,因为需要一些逻辑来创建对象中路径的缺失部分,覆盖阻碍的原始值,并确定新的孩子是否应该更好是一个数组或一个普通对象。

【讨论】:

  • lodash 文档示例,例如 _.set(object, 'a[0].b.c', 4) 和 _.set(object, ['x', '0', ' y', 'z'], 5);休息
  • @M.Suurland,感谢您的评论。答案已相应更新。
  • 精彩回答
【解决方案2】:

检查这个:

/**
 * @example
 * const obj = {id:1, address: {city: 'Minsk', street: 'Prityckogo 12'}}
 * setByString(obj, 'address.city', 'Grodno'); obj.address.city => 'Grodno'
 * setByString(obj, ['address', 'city'], 'Grodno'); obj.address.city => 'Grodno'
 * setByString(obj, ['address', city', 'phones'], {mobile: 1234, home: 222}); obj.address.city.phones.home => 222
*/

/**
* @param    {any}   input
* @return   {boolean}
*/

const isObject = (input) => (
  null !== input && 
    typeof input === 'object' &&
    Object.getPrototypeOf(input).isPrototypeOf(Object);
)

 **/
 * @param   {object}    obj
 * @param   {string}    path
 * @param   {any}       value
 */

const setByString = (obj, path, value) => {
  const pList = Array.isArray(path) ? path : path.split('.');
  const len = pList.length;
  // changes second last key to {}
  for (let i = 0; i < len - 1; i++) {
    const elem = pList[i];
    if (!obj[elem] || !isObject(obj[elem])) {
      obj[elem] = {};
    }
    obj = obj[elem];
  }

  // set value to second last key
  obj[pList[len - 1]] = value;
};

【讨论】:

    【解决方案3】:

    const set = (obj = {}, paths = [], value) => {
        const inputObj = obj === null ? {} : { ...obj };
    
        if (paths.length === 0) {
            return inputObj;
        }
    
        if (paths.length === 1) {
            const path = paths[0];
            inputObj[path] = value;
            return { ...inputObj, [path]: value };
        }
    
        const [path, ...rest] = paths;
        const currentNode = inputObj[path];
    
        const childNode = set(currentNode, rest, value);
    
        return { ...inputObj, [path]: childNode };
    };

    示例: 常量输入 = {};

    set(输入, ['a', 'b'], 'hello');

    结果: { a: { b: '你好' }}

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-18
      • 2014-09-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多