我有一个这样的数据结构:

var someObject = {
    'part1' : {
        'name': 'Part 1',
        'size': '20',
        'qty' : '50'
    },
    'part2' : {
        'name': 'Part 2',
        'size': '15',
        'qty' : '60'
    },
    'part3' : [
        {
            'name': 'Part 3A',
            'size': '10',
            'qty' : '20'
        }, {
            'name': 'Part 3B',
            'size': '5',
            'qty' : '20'
        }, {
            'name': 'Part 3C',
            'size': '7.5',
            'qty' : '20'
        }
    ]
};

我想使用这些变量访问数据:

var part1name = "part1.name";
var part2quantity = "part2.qty";
var part3name1 = "part3[0].name";

part1name应该用someObject.part1.name的值填充,即“Part 1”。part2quantity也是一样,它的容量是60。

有没有办法实现这与纯javascript或JQuery?


当前回答

mohamed Hamouday' Answer的扩展将填补缺失的关键

function Object_Manager(obj, Path, value, Action, strict) 
{
    try
    {
        if(Array.isArray(Path) == false)
        {
            Path = [Path];
        }

        let level = 0;
        var Return_Value;
        Path.reduce((a, b)=>{
            console.log(level,':',a, '|||',b)
            if (!strict){
              if (!(b in a)) a[b] = {}
            }


            level++;
            if (level === Path.length)
            {
                if(Action === 'Set')
                {
                    a[b] = value;
                    return value;
                }
                else if(Action === 'Get')
                {
                    Return_Value = a[b];
                }
                else if(Action === 'Unset')
                {
                    delete a[b];
                }
            } 
            else 
            {
                return a[b];
            }
        }, obj);
        return Return_Value;
    }

    catch(err)
    {
        console.error(err);
        return obj;
    }
}

例子


obja = {
  "a": {
    "b":"nom"
  }
}

// Set
path = "c.b" // Path does not exist
Object_Manager(obja,path.split('.'), 'test_new_val', 'Set', false);

// Expected Output: Object { a: Object { b: "nom" }, c: Object { b: "test_new_value" } }

其他回答

请注意,以下选项并不适用于所有有效的unicode属性名(但据我所知,其他选项也不适用)。

const PATTERN = /[\^|\[|\.]([$|\w]+)/gu function propValue(o, s) { const names = [] for(let [, name] of [...s.matchAll(PATTERN)]) names.push(name) return names.reduce((p, propName) => { if(!p.hasOwnProperty(propName)) throw 'invalid property name' return p[propName] }, o) } let path = 'myObject.1._property2[0][0].$property3' let o = { 1: { _property2: [ [{ $property3: 'Hello World' }] ] } } console.log(propValue(o, path)) // 'Hello World'

我只是基于一些类似的代码,我已经有了,它似乎工作:

Object.byString = function(o, s) {
    s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
    s = s.replace(/^\./, '');           // strip a leading dot
    var a = s.split('.');
    for (var i = 0, n = a.length; i < n; ++i) {
        var k = a[i];
        if (k in o) {
            o = o[k];
        } else {
            return;
        }
    }
    return o;
}

用法::

Object.byString(someObj, 'part3[0].name');

在http://jsfiddle.net/alnitak/hEsys/上可以看到一个工作演示

有些人注意到,如果传递的字符串中最左边的索引与对象中正确嵌套的条目不对应,这段代码将抛出错误。这是一个有效的问题,但我认为最好在调用时使用try / catch块来解决,而不是让这个函数对于无效的索引无声地返回undefined。

ES6:只有一行在Vanila JS(它返回null如果没有找到,而不是给出错误):

'path.string'.split('.').reduce((p,c)=>p&&p[c]||null, MyOBJ)

或例子:

'a.b.c'.split('.').reduce((p,c)=>p&&p[c]||null, {a:{b:{c:1}}})

可选链接操作符:

'a.b.c'.split('.').reduce((p,c)=>p?.[c], {a:{b:{c:1}}})

对于一个也识别false, 0和负数并接受默认值作为参数的ready to use函数:

const resolvePath = (object, path, defaultValue) => path
   .split('.')
   .reduce((o, p) => o ? o[p] : defaultValue, object)

示例:

resolvePath(window,'document.body') => <body>
resolvePath(window,'document.body.xyz') => undefined
resolvePath(window,'document.body.xyz', null) => null
resolvePath(window,'document.body.xyz', 1) => 1

奖金:

要设置路径(由@rob-gordon请求),您可以使用:

const setPath = (object, path, value) => path
   .split('.')
   .reduce((o,p,i) => o[p] = path.split('.').length === ++i ? value : o[p] || {}, object)

例子:

let myVar = {}
setPath(myVar, 'a.b.c', 42) => 42
console.log(myVar) => {a: {b: {c: 42}}}

使用[]访问数组:

const resolvePath = (object, path, defaultValue) => path
   .split(/[\.\[\]\'\"]/)
   .filter(p => p)
   .reduce((o, p) => o ? o[p] : defaultValue, object)

例子:

const myVar = {a:{b:[{c:1}]}}
resolvePath(myVar,'a.b[0].c') => 1
resolvePath(myVar,'a["b"][\'0\'].c') => 1

现在lodash使用_支持这一点。get (obj,财产)。看到https://lodash.com/docs

文档中的例子:

var object = { 'a': [{ 'b': { 'c': 3 } }] };

_.get(object, 'a[0].b.c');
// → 3

_.get(object, ['a', '0', 'b', 'c']);
// → 3

_.get(object, 'a.b.c', 'default');
// → 'default'

从@Alnitak answer开始,我构建了这个源代码,它下载了一个实际的.JSON文件并对其进行处理,为每一步打印到控制台解释字符串,以及在传递错误键的情况下的更多细节:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
  <script>
function retrieveURL(url) {
        var client = new XMLHttpRequest();
        prefix = "https://cors-anywhere.herokuapp.com/"
        client.open('GET', prefix + url);
        client.responseType = 'text';
        client.onload = function() {
            response = client.response; // Load remote response.
            console.log("Response received.");
            parsedJSON  = JSON.parse(response);
            console.log(parsedJSON);
            console.log(JSONitemByPath(parsedJSON,"geometry[6].obs[3].latituade"));
            return response;
        };
        try {
            client.send();
        } catch(e) {
            console.log("NETWORK ERROR!");
            console.log(e);
        }
}



function JSONitemByPath(o, s) {
    structure = "";
    originalString = s;
    console.log("Received string: ", s);
    s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
    console.log("Converted to   : ", s);
    s = s.replace(/^\./, '');           // strip a leading dot
    var a = s.split('.');

    console.log("Single keys to parse: ",a);

    for (var i = 0, n = a.length; i < n; ++i) {
        var k = a[i];
        if (k in o) {
            o = o[k];
            console.log("object." + structure +  a[i], o);
            structure +=  a[i] + ".";
        } else {
            console.log("ERROR: wrong path passed: ", originalString);
            console.log("       Last working level: ", structure.substr(0,structure.length-1));
            console.log("       Contents: ", o);
            console.log("       Available/passed key: ");
            Object.keys(o).forEach((prop)=> console.log("       "+prop +"/" + k));
            return;
        }
    }
    return o;
}


function main() {
    rawJSON = retrieveURL("http://haya2now.jp/data/data.json");
}

</script>
  </head>
  <body onload="main()">
  </body>
</html>

输出的例子:

Response received.
json-querier.html:17 {geometry: Array(7), error: Array(0), status: {…}}
json-querier.html:34 Received string:  geometry[6].obs[3].latituade
json-querier.html:36 Converted to   :  geometry.6.obs.3.latituade
json-querier.html:40 Single keys to parse:  (5) ["geometry", "6", "obs", "3", "latituade"]
json-querier.html:46 object.geometry (7) [{…}, {…}, {…}, {…}, {…}, {…}, {…}]
json-querier.html:46 object.geometry.6 {hayabusa2: {…}, earth: {…}, obs: Array(6), TT: 2458816.04973593, ryugu: {…}, …}
json-querier.html:46 object.geometry.6.obs (6) [{…}, {…}, {…}, {…}, {…}, {…}]
json-querier.html:46 object.geometry.6.obs.3 {longitude: 148.98, hayabusa2: {…}, sun: {…}, name: "DSS-43", latitude: -35.4, …}
json-querier.html:49 ERROR: wrong path passed:  geometry[6].obs[3].latituade
json-querier.html:50        Last working level:  geometry.6.obs.3
json-querier.html:51        Contents:  {longitude: 148.98, hayabusa2: {…}, sun: {…}, name: "DSS-43", latitude: -35.4, …}
json-querier.html:52        Available/passed key: 
json-querier.html:53        longitude/latituade
json-querier.html:53        hayabusa2/latituade
json-querier.html:53        sun/latituade
json-querier.html:53        name/latituade
json-querier.html:53        latitude/latituade
json-querier.html:53        altitude/latituade
json-querier.html:18 undefined