简体   繁体   中英

JavaScript: Convert string and concatenate it to dynamically create an object property reference

I'm creating an API where values are passed by the server via data attribute, so the JS can use to retrieve information... My JS makes a AJAX call and a JSON object is returned...

{
    "data": {
        "results": {
            "type": [
                {
                    "cars" : {
                        "brands": {
                            "ford" : {},
                            "honda" : {}
                        }
                    }
                }
            ]
        }
    }
}

In order to get the brand, I just type

let brand = data.result.type[0].cars.brands.ford

this way I can get the results I need, but I need to build this path dynamically, by joining 2 partials of the path. Like I said in the beginning of the question, some info are passed via data attribute and the info is type[0].cars.brands.ford ... I need to join this to data.result in my code. I'm currently being able to get the desired result by using eval() , like so

entry.querySelectorAll('[data-brand]').forEach((e) =>
    let brand = eval('data.result.' + e.dataset.brand);
)

I know many of you will say that using eval() is bad and I'm very aware of it, but I just could not find a better way to make this to happen and there is another issue, when the brand, let's say, nissan is not on the JSON, I get an error TypeError: Cannot read property 'nissan' of undefined ... One could avoid this, by checking if the property exist, before continuing the code, but I don't know how to do this kind of test when eval() is involved.

So... basically, what I need, is a better way to dynamically build the property path, that can be tested to see if the property exist...

Thanks in advance...

const brand = e.dataset.brand.split(".").reduce((obj,id) => obj[id] || {}, data.results);

That doenst support brackets, so do:

type.0.whatever.keys

To return undefined for non existent keys (instead of an empty object):

const brand = e.dataset.brand.split(".").reduce((obj,id) => (obj || {} )[id], data.results);

You can check if data.result has the property first, and only then make your variable brand:

if(data.result.hasOwnProperty(e.dataset.brand)){
    let brand = data.result[e.dataset.brand];
}

You can String#match to find all keys, then iterate the keys using Array#reduce , and get the key value from the object:

 const obj = {"data":{"results":{"type":[{"cars":{"brands":{"ford":{"name":"ford"},"honda":{"name":"honda"}}}}]}}}; const brand = 'data.results.type[0].cars.brands.ford'; const getPathValue = (src, path) => path.match(/[^.\\[\\]]+/g) .reduce((p, k) => typeof p === 'object' ? p[k] : p, src); const brandOBj = getPathValue(obj, brand); console.log(brandOBj); 

You can check ie the lodash get method which allows you to access values of object using path.

If lodash is too big for you, just review their implementation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM