将点符号字符串转换为对象和查找引用对象

Convert dot notation string to object and lookup reference object

我有一个点符号数组,例如:

var base = ['a.b.c','a.e','h'];

我还有一个参考对象:

var reference = { 
  a: { 
    b: { 
      c:"Hello", 
      d:"you" 
    }, 
    e:"beautiful",
    f:"and"
  },
  g:"kind",
  h:"World" 
};

我需要用基本标记字符串构建一个对象,并从引用对象中获取值。不幸的是,我无法更改基础或参考。

我让它为数组的每个单独部分工作,但问题是当我尝试合并对象时。它用 a.e.

覆盖值 a.b.c

我想要的输出是:

var desiredOutput = { 
  a: { 
    b: { 
      c:"Hello" 
    }, 
    e:"beautiful" 
  }, 
  h:"World" 
};

但是,使用下面的代码,我的输出是:

var output = { 
    a: { 
        e: "beautiful" 
    },
    h: "World" 
};

如有任何帮助,我们将不胜感激。我仅限于 < ES5,但如果需要可以使用一些 polyfill,例如 Object.assign

function convert(base,reference) {
    var obj = {};

    var getObjectValue = function(string, reference) {
        var i = 0;
        while (reference && i < string.length) {
            reference = reference[string[i++]];
        }
        return reference;
    };

    for (var n = 0; n < base.length; n++) {    
        var s = base[n].split("."),
            x = obj;

        for(var i = 0; i < s.length-1; i++) {
            x = x[s[i]] = {}; 
        }

        x[s[i]] = getObjectValue(s,reference);
    }
    return obj;
}

var base = ['a.b.c','a.e','h'];

var reference = { 
  a: { 
    b: { 
      c:"Hello", 
      d:"you" 
    }, 
    e:"beautiful",
    f:"and"
  },
  g:"kind",
  h:"World" 
};

var desiredOutput = { 
  a: { 
    b: { 
      c:"Hello" 
    }, 
    e:"beautiful" 
  }, 
  h:"World" 
};

console.log(convert(base,reference));

与你

x = x[s[i]] = {}; 

您将无条件覆盖 s[i] 属性,即使它已经被填充。仅当另一个对象不存在时才分配一个新对象 属性.

if (x[s[i]]) {
  x = x[s[i]];
} else {
  x = x[s[i]] = {};
}

function convert(base,reference) {
    var obj = {};

    var getObjectValue = function(string, reference) {
        var i = 0;
        while (reference && i < string.length) {
            reference = reference[string[i++]];
        }
        return reference;
    };

    for (var n = 0; n < base.length; n++) {    
        var s = base[n].split("."),
            x = obj;

        for(var i = 0; i < s.length-1; i++) {
            if (x[s[i]]) {
              x = x[s[i]];
            } else {
              x = x[s[i]] = {};
            }
        }

        x[s[i]] = getObjectValue(s,reference);
    }

    return obj;

}

var base = ['a.b.c','a.e','h'];

var reference = { 
  a: { 
    b: { 
      c:"Hello", 
      d:"you" 
    }, 
    e:"beautiful",
    f:"and"
  },
  g:"kind",
  h:"World" 
};

var desiredOutput = { 
  a: { 
    b: { 
      c:"Hello" 
    }, 
    e:"beautiful" 
  }, 
  h:"World" 
};


console.log(convert(base,reference));

这就是我的处理方式:

var base = ['a.b.c','a.e','h'];
var reference = { 
  a: { 
    b: { 
      c:"Hello", 
      d:"you" 
    }, 
    e:"beautiful",
    f:"and"
  },
  g:"kind",
  h:"World" 
};

const results = {};
// Helper function to get the nested value from an array of properties:
const getVal = props => props.reduce((a, b) => a[b], reference);
for (const propStr of base) {
  // Turn string into an array of properties:
  const props = propStr.split('.');
  // Get nested value to assign at the end:
  const val = getVal(props);
  // Get last property to assign on the last object:
  const lastProp = props.pop();
  let obj = results;
  // Iterate through to the nested object on the `results`,
  // creating objects on the way only if they don't exist yet:
  while (props.length) {
    const prop = props.shift();
    if (obj[prop]) obj = obj[prop];
    else {
      obj[prop] = {};
      obj = obj[prop];
    }
  }
  obj[lastProp] = val;
}
console.log(results);

这可以在没有 while 循环的情况下实现!

我只使用了 es6 的 Array.prototype.reduce(和语义,但你可以 convert/transpile 你自己)。你也可以轻松poly/ponyfill它,见this article.

const base = ['a.b.c', 'a.e', 'h'];

const reference = { 
  a: { 
    b: { 
      c: 'Hello', 
      d: 'you' 
    }, 
    e: 'beautiful',
    f: 'and'
  },
  g: 'kind',
  h: 'World' 
};

const isObject = item => (item && typeof item === 'object' && !Array.isArray(item) && item !== null);

const pick = (obj, keys) => keys.split('.').reduce((prev, key) => {
  const ret = (prev || obj);
  if (isObject(ret) && key in ret) {
    return ret[key];
  }

  return prev;
}, null);

const extend = (target, source) => {
  if (isObject(target) && isObject(source)) {
    Object.keys(source).forEach((key) => {
      if (isObject(source[key])) {
        if (!target[key] || !isObject(target[key])) {
          target[key] = source[key];
        }
        extend(target[key], source[key]);
      } else {
        Object.assign(target, { [key]: source[key] });
      }
    });
  }
  return target || source;
};

const fromDotNotation = (dotNotation, value) => {
  const ret = {};
  dotNotation.split('.').reduce((prev, key, i, self) => {
    return prev[key] = (i === self.length - 1) ? value : prev[key] || {};
  }, ret);

  return ret;
}

const fromDotNotations = (source, dotNotations) => dotNotations.reduce((prev, dotNotation) => {
  return extend(prev, fromDotNotation(dotNotation, pick(source, dotNotation)));
}, {});

const output = fromDotNotations(reference, base);

console.log(JSON.stringify(output, null, 2));

在这里,我们希望能够从任何点符号构建一个对象,其尾部有一个初始值。我们将使用 plucking 方法从参考对象中选取初始值。遍历多个点符号,我们可以创建一个构造对象数组。简单地使用合并方法,我们可以创建一个目标对象,我们想要将我们构造的对象合并到其中。

我创建了以下代码片段以使用嵌套的 foreach 以简单的方式获得您想要的结果,希望这对您有所帮助。我在评论中描述了代码。

var reference = {
  a: {
    b: {
      c: "Hello",
      d: "you"
    },
    e: "beautiful",
    f: "and"
  },
  g: "kind",
  h: "World"
};

var base = ['a.b.c', 'a.e', 'h'];

var result = {};

base.forEach(str => {

  //split the base by `.`
  var arr = str.split('.');

  //get the value
  var val = arr.reduce((r, el) => r[el], reference);

  //set the initial temporary path of resulting object
  var tmp = result;

  arr.forEach((el, i) => {

    //set final property value into resulting object
    if (i == arr.length - 1)
      return tmp[el] = val;

    //create nested property in resulting object
    if (!tmp[el])
      tmp[el] = {};

    //update temporary path
    tmp = tmp[el];
  });
});

console.log(result)

试试这个:

deepLookup(input, targetObj) {
    const nsList = input.split('.');
    let found = targetObj;
    nsList.forEach(ns => {
        if (found.hasOwnProperty(ns)) {
            found = found[ns];
        } else {
            found = null;
        }
    });
    return found;
}