给定一个JavaScript对象,

var obj = { a: { b: '1', c: '2' } }

和字符串

"a.b"

我怎么把字符串转换成点符号呢

var val = obj.a.b

如果字符串只是'a',我可以使用obj[a]。但这个更复杂。我想应该有什么简单的方法,但现在想不起来了。


当前回答

几年后,我发现它可以处理范围和数组。如[b] [c] .d.etc

function getScopedObj(scope, str) {
  let obj=scope, arr;

  try {
    arr = str.split(/[\[\]\.]/) // split by [,],.
      .filter(el => el)             // filter out empty one
      .map(el => el.replace(/^['"]+|['"]+$/g, '')); // remove string quotation
    arr.forEach(el => obj = obj[el])
  } catch(e) {
    obj = undefined;
  }

  return obj;
}

window.a = {b: {c: {d: {etc: 'success'}}}}

getScopedObj(window, `a.b.c.d.etc`)             // success
getScopedObj(window, `a['b']["c"].d.etc`)       // success
getScopedObj(window, `a['INVALID']["c"].d.etc`) // undefined

其他回答

var find = function(root, path) {
  var segments = path.split('.'),
      cursor = root,
      target;

  for (var i = 0; i < segments.length; ++i) {
   target = cursor[segments[i]];
   if (typeof target == "undefined") return void 0;
   cursor = target;
  }

  return cursor;
};

var obj = { a: { b: '1', c: '2' } }
find(obj, "a.b"); // 1

var set = function (root, path, value) {
   var segments = path.split('.'),
       cursor = root,
       target;

   for (var i = 0; i < segments.length - 1; ++i) {
      cursor = cursor[segments[i]] || { };
   }

   cursor[segments[segments.length - 1]] = value;
};

set(obj, "a.k", function () { console.log("hello world"); });

find(obj, "a.k")(); // hello world

解决方案:

function deepFind(key, data){
  return key.split('.').reduce((ob,i)=> ob?.[i], data)
}

用法:

const obj = {
   company: "Pet Shop",
   person: {
      name: "John"
   },
   animal: {
      name: "Lucky"
   }
}

const company = deepFind("company", obj) 
const personName = deepFind("person.name", obj) 
const animalName = deepFind("animal.name", obj) 

function at(obj, path, val = undefined) { // If path is an Array, if (Array.isArray(path)) { // it returns the mapped array for each result of the path return path.map((path) => at(obj, path, val)); } // Uniting several RegExps into one const rx = new RegExp( [ /(?:^(?:\.\s*)?([_a-zA-Z][_a-zA-Z0-9]*))/, /(?:^\[\s*(\d+)\s*\])/, /(?:^\[\s*'([^']*(?:\\'[^']*)*)'\s*\])/, /(?:^\[\s*"([^"]*(?:\\"[^"]*)*)"\s*\])/, /(?:^\[\s*`([^`]*(?:\\`[^`]*)*)`\s*\])/, ] .map((r) => r.source) .join("|") ); let rm; while (rm = rx.exec(path.trim())) { // Matched resource let [rf, rp] = rm.filter(Boolean); // If no one matches found, if (!rm[1] && !rm[2]) { // it will replace escape-chars rp = rp.replace(/\\(.)/g, "$1"); } // If the new value is set, if ("undefined" != typeof val && path.length == rf.length) { // assign a value to the object property and return it return (obj[rp] = val); } // Going one step deeper obj = obj[rp]; // Removing a step from the path path = path.substr(rf.length).trim(); } if (path) { throw new SyntaxError(); } return obj; } // Test object schema let o = { a: { b: [ [ { c: { d: { '"e"': { f: { g: "xxx" } } } } } ] ] } }; // Print source object console.log(JSON.stringify(o)); // Set value console.log(at(o, '.a["b"][0][0].c[`d`]["\\"e\\""][\'f\']["g"]', "zzz")); // Get value console.log(at(o, '.a["b"][0][0].c[`d`]["\\"e\\""][\'f\']["g"]')); // Print result object console.log(JSON.stringify(o));

如果希望多次解除对同一路径的引用,为每个点符号路径构建函数实际上具有迄今为止最好的性能(扩展James Wilkins在上面的评论中链接到的性能测试)。

var path = 'a.b.x';
var getter = new Function("obj", "return obj." + path + ";");
getter(obj);

Using the Function constructor has some of the same drawbacks as eval() in terms of security and worst-case performance, but IMO it's a badly underused tool for cases where you need a combination of extreme dynamism and high performance. I use this methodology to build array filter functions and call them inside an AngularJS digest loop. My profiles consistently show the array.filter() step taking less than 1ms to dereference and filter about 2000 complex objects, using dynamically-defined paths 3-4 levels deep.

当然,类似的方法也可以用于创建setter函数:

var setter = new Function("obj", "newval", "obj." + path + " = newval;");
setter(obj, "some new val");

我不清楚你的问题是什么。给定你的对象,obj。a.b会给你原来的2。如果你想操纵字符串使用括号,你可以这样做:

var s = 'a.b';
s = 'obj["' + s.replace(/\./g, '"]["') + '"]';
alert(s); // displays obj["a"]["b"]