नेस्टेड जावास्क्रिप्ट ऑब्जेक्ट्स तक पहुंचना और स्ट्रिंग पथ द्वारा किरणें


454

मेरे पास इस तरह की एक डेटा संरचना है:

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's वैल्यू' से भरा जाना चाहिए , जो कि "Part 1" है। Part2quantity के साथ एक ही बात जो 60 से भर गई।

वहाँ वैसे भी या तो शुद्ध जावास्क्रिप्ट या JQuery के साथ इसे प्राप्त करने के लिए है?


निश्चित नहीं है कि आप यहाँ क्या पूछ रहे हैं? आप part1.name को क्वेरी करने में सक्षम होना चाहते हैं और पाठ "part1.name" लौटा दिया है? या आप part1.name के भीतर संग्रहीत मान प्राप्त करना चाहते हैं?
बोनी

क्या आपने var part1name = someObject.part1name;`
राफे

1
@BonyT: मैं someObject.part1.name को क्वेरी करना चाहता हूं और इसका मान लौटाता हूं ("भाग 1")। हालाँकि, मैं चाहता हूं कि क्वेरी (मैंने इसे "कुंजी" कहा है) को एक चर 'part1name' में संग्रहीत किया जाए। आपके जवाब के लिए धन्यवाद। @ 3nigma: मेरे पास निश्चित रूप से है। लेकिन मेरा इरादा ऐसा नहीं है। उत्तर के लिए धन्यवाद।
कोमारुलोह

1
डुप्लिकेट उत्तर में, मुझे फियर का जवाब पसंद है stackoverflow.com/questions/8817394/…
स्टीव ब्लैक

जवाबों:


520

मैंने इसे कुछ इसी तरह के कोड के आधार पर बनाया है जो मेरे पास पहले से था, यह काम करता है:

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/ पर एक कार्यशील डेमो देखें

EDIT कुछ ने देखा कि यह कोड एक स्ट्रिंग को पास करने में त्रुटि करेगा, जहां बाईं ओर सबसे अनुक्रमणिका ऑब्जेक्ट के भीतर एक सही ढंग से नेस्टेड प्रविष्टि के अनुरूप नहीं है। यह एक वैध चिंता का विषय है, लेकिन IMHO को try / catchकॉल करते समय ब्लॉक के साथ सबसे अच्छा पता चलता है , बजाय इसके कि यह फ़ंक्शन चुपचाप undefinedएक अमान्य सूचकांक के लिए वापस आ जाए ।


19
यह खूबसूरती से काम करता है। कृपया इसे नोड पैकेज के रूप में लपेटकर इंटरनेट में योगदान करें।
t3dodson

14
@ t3dodson मैंने अभी-अभी किया: github.com/capaj/object-resolve-path बस इस बात का ध्यान रखें कि यह अच्छा नहीं खेलता है जब आपकी संपत्ति का नाम अपने आप में '[]' हो। रेगेक्स इसे 'के साथ बदल देगा।' और यह उम्मीद के
मुताबिक

20
उत्तम सामग्री; lodash लाइब्रेरी का उपयोग कर, एक भी कर सकते हैं:_.get(object, nestedPropertyString);
इआन

17
यह शायद टिप्पणियों के समुद्र में खो जाएगा, हालांकि यदि आप एक संपत्ति का प्रयास करते हैं और मौजूद नहीं हैं तो यह त्रुटियों का सामना करता है। तो 'part3[0].name.iDontExist'। यह देखने के लिए एक जांच जोड़ना oमें एक वस्तु है if inफिक्स मुद्दा। (आप इसके बारे में कैसे जाने कि यह आपके ऊपर है)। अपडेटेड
फिडेल

2
यह तो सोना है। हम एक विन्यास आधारित अनुप्रयोग है और यह थोड़े सहायक है! धन्यवाद!
क्रिस्चियन ओफ्फार

182

यह मेरे द्वारा उपयोग किया जाने वाला समाधान है:

function resolve(path, obj=self, separator='.') {
    var properties = Array.isArray(path) ? path : path.split(separator)
    return properties.reduce((prev, curr) => prev && prev[curr], obj)
}

उदाहरण उपयोग:

// accessing property path on global scope
resolve("document.body.style.width")
// or
resolve("style.width", document.body)

// accessing array indexes
// (someObject has been defined in the question)
resolve("part3.0.size", someObject) // returns '10'

// accessing non-existent properties
// returns undefined when intermediate properties are not defined:
resolve('properties.that.do.not.exist', {hello:'world'})

// accessing properties with unusual keys by changing the separator
var obj = { object: { 'a.property.name.with.periods': 42 } }
resolve('object->a.property.name.with.periods', obj, '->') // returns 42

// accessing properties with unusual keys by passing a property name array
resolve(['object', 'a.property.name.with.periods'], obj) // returns 42

सीमाएं:

  • []सरणी सूचकांकों के लिए कोष्ठक ( ) का उपयोग नहीं किया जा सकता है - यद्यपि विभाजक टोकन (जैसे, .) के बीच सरणी सूचक को निर्दिष्ट करना ऊपर दिखाए गए अनुसार ठीक काम करता है।

7
कम करना एक उत्कृष्ट समाधान है ( _.reduce()अंडरस्कोर या लॉज़ लाइब्रेरी से भी उपयोग कर सकते हैं )
अल्प

3
मुझे लगता selfहै कि शायद यहाँ अपरिभाषित है। क्या आपका मतलब है this?
प्लैटिनम एज़ुर

2
यहां पथ द्वारा मान सेट करने के लिए मेरा पूरक है: pastebin.com/jDp5sKT9
mroach

1
किसी को पता है कि इसे टाइपस्क्रिप्ट में कैसे पोर्ट करना है?
एडम प्लोचर

1
@ SC1000 अच्छा विचार। अधिकांश ब्राउज़र में डिफ़ॉल्ट पैरामीटर उपलब्ध होने से पहले यह उत्तर लिखा गया था। मैं इसे "फ़ंक्शन रिज़ॉल्यूशन (पथ, obj = self)" पर अपडेट करूंगा, क्योंकि वैश्विक ऑब्जेक्ट को डिफ़ॉल्ट के रूप में संदर्भित करना जानबूझकर है।
speigg

179

यह अब लॉश का उपयोग करके समर्थित है _.get(obj, property)Https://lodash.com/docs#get देखें

डॉक्स से उदाहरण:

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'

9
यह एकमात्र स्वीकृत उत्तर होना चाहिए, क्योंकि यह डॉट और ब्रैकेट सिंटैक्स दोनों के लिए एक ही काम करता है और यह तब विफल नहीं होता है, जब हमारे पास मार्ग में एक कुंजी के स्ट्रिंग में '[]' 'होता है।
कैपज

7
इस। साथ ही, यह समर्थन करता है_.set(...)
जोश सी।

अगर ओब्जेक्ट नहीं मिला तो क्या होगा?
डीडीवे

@DDave यदि ऑब्जेक्ट अपरिभाषित है या ऑब्जेक्ट नहीं है, _.getतो वही व्यवहार दिखाएगा जब प्रदान की गई ऑब्जेक्ट में कोई कुंजी नहीं मिलेगी। जैसे _.get(null, "foo") -> undefined, _.get(null, "foo", "bar") -> "bar"। हालाँकि यह व्यवहार डॉक्स में परिभाषित नहीं है इसलिए परिवर्तन के अधीन है।
इयान वॉकर-स्पैबर

5
@ कापज आप किद्दीन '? और कौन नहीं चाहता / लता का उपयोग नहीं कर सकता है?
आंद्रे फिगयेरिडो

74

ईएस 6 : वेनिला जेएस में केवल एक लाइन (यह त्रुटि देने के बजाय वापस नहीं आती है):

'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]||null, {a:{b:{c:1}}})

फ़ंक्शन का उपयोग करने के लिए तैयार है जो गलत, 0 और नकारात्मक संख्या को पहचानता है और पैरामीटर के रूप में डिफ़ॉल्ट मान स्वीकार करता है:

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

बोनस :

एक पथ सेट करने के लिए (@ रोब-गॉर्डन द्वारा अनुरोधित) आप उपयोग कर सकते हैं:

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

2
मुझे इस तकनीक से प्यार है। यह वास्तव में गड़बड़ है लेकिन मैं असाइनमेंट के लिए इस तकनीक का उपयोग करना चाहता था। let o = {a:{b:{c:1}}}; let str = 'a.b.c'; str.split('.').splice(0, str.split('.').length - 1).reduce((p,c)=>p&&p[c]||null, o)[str.split('.').slice(-1)] = "some new value";
लुट-गॉर्डन

1
मैं का उपयोग करने का विचार की तरह कम हो, लेकिन अपने तर्क के लिए बंद कर रहा है 0, undefinedऔर nullमूल्यों। {a:{b:{c:0}}}के nullबदले देता है 0। शायद अशक्त या अपरिभाषित के लिए स्पष्ट रूप से जाँच इन मुद्दों को स्पष्ट करेगा। (p,c)=>p === undefined || p === null ? undefined : p[c]
स्मूजमैकु

हाय @SmujMaiku, '0', 'अपरिभाषित' और 'अशक्त' के लिए सही ढंग से "फंक्शन रिटर्न" का उपयोग करने के लिए तैयार है, मैंने सिर्फ कंसोल पर परीक्षण किया है: solutionPath ({a: {b: {c: 0}}}, ' abc ', null) => 0; यह
जांचता है

यहाँ DefaultValue ने काम नहीं किया, Reflect.has(o, k) ? ...(ES6 Reflect.has ) का उपयोग कर काम किया
आंद्रे

setPathअंतिम चयनकर्ता की पहली घटना पर मूल्य निर्धारित करेगा। उदाहरण के लिए इसके बजाय let o = {}; setPath(o, 'a.a', 0)परिणाम । समाधान के लिए इस पोस्ट को देखें । {a: 0}{a: {a: 0}}
pkfm

62

आपको स्ट्रिंग को स्वयं पार्स करना होगा:

function getProperty(obj, prop) {
    var parts = prop.split('.');

    if (Array.isArray(parts)) {
        var last = parts.pop(),
        l = parts.length,
        i = 1,
        current = parts[0];

        while((obj = obj[current]) && i < l) {
            current = parts[i];
            i++;
        }

        if(obj) {
            return obj[last];
        }
    } else {
        throw 'parts is not valid array';
    }
}

यह आवश्यक है कि आप बिंदु संकेतन के साथ सरणी अनुक्रमित को भी परिभाषित करें:

var part3name1 = "part3.0.name";

यह पार्सिंग को आसान बनाता है।

डेमो


@ फेलिक्स क्लिंग: आपका समाधान मुझे वह प्रदान करता है जिसकी मुझे आवश्यकता है। और इसके लिए मैं आपको धन्यवाद देता हूं। लेकिन अलनीतक भी अलग-अलग तरीके प्रदान करते हैं और काम करने लगते हैं। चूंकि मैं केवल एक उत्तर चुन सकता हूं, इसलिए मैं अलनीतक उत्तर चुनूंगा। ऐसा नहीं कि उसका हल आपसे बेहतर है या ऐसा कुछ। वैसे भी, मैं वास्तव में आपके समाधान और आपके द्वारा दिए गए प्रयासों की सराहना करता हूं।
कोमलारोह

1
@Komaruloh: ओह, मैंने सोचा कि आप हमेशा अपने सवाल पर वोट के जवाब दे सकते हैं .... वैसे भी मैं कम या ज्यादा मज़ाक कर रहा था, मुझे अधिक प्रतिष्ठा की आवश्यकता नहीं है;) हैप्पी कोडिंग!
फेलिक्स क्लिंग

1
@ फेलिक्स क्लिंग: आपको वोट अप करने के लिए कम से कम 15 प्रतिष्ठा की आवश्यकता है। :) मेरा मानना ​​है कि आपको 69k + के साथ अधिक प्रतिष्ठा की आवश्यकता नहीं है। धन्यवाद
Komaruloh

@ फेलिक्स एफडब्ल्यूआईडब्ल्यू - []सिंटैक्स से संपत्ति सिंटैक्स में परिवर्तित करना बहुत तुच्छ है।
अलनीतक

4
यदि आप लूप को बदलते हैं while (l > 0 && (obj = obj[current]) && i < l)तो यह कोड बिना डॉट्स के भी काम करता है।
Snea

39

ऑब्जेक्ट के अंदर सरणियों / सरणियों के लिए भी काम करता है। अमान्य मानों के विरुद्ध रक्षात्मक।

/**
 * Retrieve nested item from object/array
 * @param {Object|Array} obj
 * @param {String} path dot separated
 * @param {*} def default value ( if result undefined )
 * @returns {*}
 */
function path(obj, path, def){
    var i, len;

    for(i = 0,path = path.split('.'), len = path.length; i < len; i++){
        if(!obj || typeof obj !== 'object') return def;
        obj = obj[path[i]];
    }

    if(obj === undefined) return def;
    return obj;
}

//////////////////////////
//         TEST         //
//////////////////////////

var arr = [true, {'sp ace': true}, true]

var obj = {
  'sp ace': true,
  arr: arr,
  nested: {'dotted.str.ing': true},
  arr3: arr
}

shouldThrow(`path(obj, "arr.0")`);
shouldBeDefined(`path(obj, "arr[0]")`);
shouldBeEqualToNumber(`path(obj, "arr.length")`, 3);
shouldBeTrue(`path(obj, "sp ace")`);
shouldBeEqualToString(`path(obj, "none.existed.prop", "fallback")`, "fallback");
shouldBeTrue(`path(obj, "nested['dotted.str.ing'])`);
<script src="https://cdn.rawgit.com/coderek/e7b30bac7634a50ad8fd/raw/174b6634c8f57aa8aac0716c5b7b2a7098e03584/js-test.js"></script>


10
धन्यवाद यह सबसे अच्छा और सबसे अच्छा जवाब है - jsfiddle.net/Jw8XB/1
डोमिनिक

@ बिना, मैं इस बात पर जोर देना चाहूंगा कि डॉट्स के साथ आइटम को अलग करना चाहिए। ब्रेस काम नहीं करेगा। सरणी में पहले आइटम का उपयोग करने के लिए Ie "0.sp इक्का"।
theZver

26

eval का उपयोग करना:

var part1name = eval("someObject.part1.name");

त्रुटि पर अपरिभाषित लौटने के लिए रैप

function path(obj, path) {
    try {
        return eval("obj." + path);
    } catch(e) {
        return undefined;
    }
}

http://jsfiddle.net/shanimal/b3xTw/

कृपया सामान्य ज्ञान और सावधानी का उपयोग करें, जब निष्कासन की शक्ति का उपयोग किया जाता है। यह एक प्रकाश कृपाण की तरह एक सा है, अगर आप इसे चालू करते हैं तो 90% संभावना है कि आप एक अंग को अलग कर देंगे। हर किसी के लिए नहीं।


7
Eval एक अच्छा विचार है या नहीं यह इस बात पर निर्भर करता है कि प्रॉपर्टी स्ट्रिंग डेटा कहां से आ रहा है। मुझे संदेह है कि आपके पास एक स्थिर "var p = 'abc'; eval (p);" के माध्यम से हैकर्स के टूटने का कोई कारण है; टाइप कॉल। यह उसके लिए बिल्कुल ठीक विचार है।
जेम्स विल्किंस

17

आप सरल निम्नलिखित चाल के साथ किसी भी बाहरी जावास्क्रिप्ट पुस्तकालय के बिना डॉट संकेतन के साथ एक गहरी वस्तु सदस्य का मूल्य प्राप्त करने का प्रबंधन कर सकते हैं:

new Function('_', 'return _.' + path)(obj);

आपके मामले में बस part1.nameसे मूल्य प्राप्त करने के लिए someObject:

new Function('_', 'return _.part1.name')(someObject);

यहाँ एक सरल फिडेल डेमो है: https://jsfiddle.net/harishanchu/oq5esowf/


3
function deep_value (obj, path) {नया फ़ंक्शन लौटाएँ ('o', 'return o।' + path) (obj); }
आर्कगेलज़िथ

14

यह शायद दिन की रोशनी को कभी नहीं देखेगा ... लेकिन यहां वैसे भी है।

  1. []ब्रैकेट सिंटैक्स को बदलें.
  2. .चरित्र पर विभाजित
  3. खाली तार निकालें
  4. पथ खोजें (अन्यथा undefined)

// "one liner" (ES6)

const deep_value = (obj, path) => 
  path
    .replace(/\[|\]\.?/g, '.')
    .split('.')
    .filter(s => s)
    .reduce((acc, val) => acc && acc[val], obj);
    
// ... and that's it.

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'
        }
        // ...
    ]
};

console.log(deep_value(someObject, "part1.name"));               // Part 1
console.log(deep_value(someObject, "part2.qty"));                // 60
console.log(deep_value(someObject, "part3[0].name"));            // Part 3A


11

यह एक लाइनर है जिसमें लॉश है।

const deep = { l1: { l2: { l3: "Hello" } } };
const prop = "l1.l2.l3";
const val = _.reduce(prop.split('.'), function(result, value) { return result ? result[value] : undefined; }, deep);
// val === "Hello"

या इससे भी बेहतर ...

const val = _.get(deep, prop);

या ES6 संस्करण w / कम करें ...

const val = prop.split('.').reduce((r, val) => { return r ? r[val] : undefined; }, deep);

Plunkr


7

मुझे लगता है कि आप इसके लिए पूछ रहे हैं:

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

आप इसके लिए पूछ सकते हैं:

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

जो दोनों काम करेंगे


या शायद आप इसके लिए पूछ रहे हैं

var partName = "part1";
var nameStr = "name";

var part1name = someObject[partName][nameStr];

अंत में आप इसके लिए पूछ सकते हैं

var partName = "part1.name";

var partBits = partName.split(".");

var part1name = someObject[partBits[0]][partBits[1]];

मुझे लगता है कि ओपी का आखिरी समाधान है। हालाँकि, स्ट्रिंग्स में Splitविधि नहीं है , बल्कि है split
दुरी

वास्तविक मैं पिछले एक पूछ रहा था। PartName वैरिएबल स्ट्रिंग से भरा है जो मान को कुंजी-संरचना दर्शाता है। आपका समाधान समझ में आता है। हालाँकि मुझे डेटा में विस्तारित गहराई के लिए संशोधित करने की आवश्यकता हो सकती है, जैसे 4-5 स्तर और अधिक। और मैं सोच रहा हूं कि क्या मैं इस के साथ समान रूप से सरणी और ऑब्जेक्ट का इलाज कर सकता हूं?
कोमारुलो

7

यहाँ मैं और तरीके प्रदान करता हूँ, जो कई मामलों में तेज़ लगते हैं:

विकल्प 1: स्प्लिट स्ट्रिंग ऑन। या [या] या 'या', इसे उल्टा करें, खाली आइटम छोड़ें।

function getValue(path, origin) {
    if (origin === void 0 || origin === null) origin = self ? self : this;
    if (typeof path !== 'string') path = '' + path;
    var parts = path.split(/\[|\]|\.|'|"/g).reverse(), name; // (why reverse? because it's usually faster to pop off the end of an array)
    while (parts.length) { name=parts.pop(); if (name) origin=origin[name]; }
    return origin;
}

विकल्प 2 (सबसे तेजी से, सिवाय eval): निम्न स्तर के चरित्र स्कैन (कोई regex / विभाजन / आदि, बस एक त्वरित चार स्कैन)। नोट: यह एक अनुक्रमित के लिए उद्धरण का समर्थन नहीं करता है।

function getValue(path, origin) {
    if (origin === void 0 || origin === null) origin = self ? self : this;
    if (typeof path !== 'string') path = '' + path;
    var c = '', pc, i = 0, n = path.length, name = '';
    if (n) while (i<=n) ((c = path[i++]) == '.' || c == '[' || c == ']' || c == void 0) ? (name?(origin = origin[name], name = ''):(pc=='.'||pc=='['||pc==']'&&c==']'?i=n+2:void 0),pc=c) : name += c;
    if (i==n+2) throw "Invalid path: "+path;
    return origin;
} // (around 1,000,000+/- ops/sec)

विकल्प 3: ( नया : विकल्प 2 उद्धरण का समर्थन करने के लिए विस्तारित - थोड़ा धीमा, लेकिन अभी भी तेज)

function getValue(path, origin) {
    if (origin === void 0 || origin === null) origin = self ? self : this;
    if (typeof path !== 'string') path = '' + path;
    var c, pc, i = 0, n = path.length, name = '', q;
    while (i<=n)
        ((c = path[i++]) == '.' || c == '[' || c == ']' || c == "'" || c == '"' || c == void 0) ? (c==q&&path[i]==']'?q='':q?name+=c:name?(origin?origin=origin[name]:i=n+2,name='') : (pc=='['&&(c=='"'||c=="'")?q=c:pc=='.'||pc=='['||pc==']'&&c==']'||pc=='"'||pc=="'"?i=n+2:void 0), pc=c) : name += c;
    if (i==n+2 || name) throw "Invalid path: "+path;
    return origin;
}

JSPerf: http://jsperf.com/ways-to-dereference-a-delimited-property-ring/3

"eval (...)" अभी भी राजा है (हालांकि प्रदर्शन बुद्धिमान है)। यदि आपके पास सीधे अपने नियंत्रण में संपत्ति पथ हैं, तो 'eval' का उपयोग करने के साथ कोई समस्या नहीं होनी चाहिए (विशेषकर यदि गति वांछित है)। यदि संपत्ति के रास्ते "तार पर" ( लाइन पर ? लोल: पी) खींच रहे हैं , तो हां, सुरक्षित होने के लिए कुछ और का उपयोग करें। केवल एक बेवकूफ यह कहेगा कि कभी भी "eval" का उपयोग न करें, क्योंकि इसका उपयोग करने के अच्छे कारण हैं । इसके अलावा, "इसका उपयोग डौग क्रॉकफोर्ड के JSON पार्सर में किया जाता है ।" यदि इनपुट सुरक्षित है, तो कोई समस्या नहीं है। सही काम के लिए सही उपकरण का उपयोग करें, बस।


6

बस मामले में, किसी को भी 2017 में या बाद में इस सवाल का दौरा करने और एक आसान तरीका याद रखने के लिए, यहाँ जावास्क्रिप्ट में Nested ऑब्जेक्ट्स को बिना बाँधे जाने के बारे में एक विस्तृत ब्लॉग पोस्ट है

अपरिभाषित त्रुटि की संपत्ति 'फू' नहीं पढ़ सकते हैं

ऐरे रिड्यूस का उपयोग करके नेस्टेड ऑब्जेक्ट तक पहुंचें

आइए इस उदाहरण संरचना को लेते हैं

const user = {
    id: 101,
    email: 'jack@dev.com',
    personalInfo: {
        name: 'Jack',
        address: [{
            line1: 'westwish st',
            line2: 'washmasher',
            city: 'wallas',
            state: 'WX'
        }]
    }
}

नेस्टेड सरणियों का उपयोग करने में सक्षम होने के लिए, आप अपनी सरणी कम उपयोग लिख सकते हैं।

const getNestedObject = (nestedObj, pathArr) => {
    return pathArr.reduce((obj, key) =>
        (obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObj);
}

// pass in your object structure as array elements
const name = getNestedObject(user, ['personalInfo', 'name']);

// to access nested array, just pass in array index as an element the path array.
const city = getNestedObject(user, ['personalInfo', 'address', 0, 'city']);
// this will return the city from the first address item.

न्यूनतम पुस्तकालय टाइपिंग से निपटने के लिए एक उत्कृष्ट प्रकार भी है जो आपके लिए यह सब करता है।

टाइप करने के साथ, आपका कोड इस तरह दिखाई देगा

const city = t(user, 'personalInfo.address[0].city').safeObject;

अस्वीकरण: मैं इस पैकेज का लेखक हूं।


6

AngularJS

Speigg का दृष्टिकोण बहुत साफ और स्वच्छ है, हालांकि मुझे यह उत्तर स्ट्रिंग मार्ग द्वारा AngularJS $ स्कोप गुणों तक पहुँचने के समाधान की खोज करते समय मिला और थोड़ा संशोधन के साथ यह काम करता है:

$scope.resolve = function( path, obj ) {
    return path.split('.').reduce( function( prev, curr ) {
        return prev[curr];
    }, obj || this );
}

इस फंक्शन को अपने रूट कंट्रोलर में रखें और इसे किसी भी चाइल्ड स्कोप की तरह इस्तेमाल करें:

$scope.resolve( 'path.to.any.object.in.scope')

देखें कि AngularJS को$scope.$eval AngularJS के साथ करने का एक और तरीका है।
जार्जियावग

3

मुझे अभी तक स्ट्रिंग पथ के साथ सभी कार्यों को करने के लिए एक पैकेज नहीं मिला है, इसलिए मैंने अपना खुद का त्वरित छोटा पैकेज लिखना बंद कर दिया है जो डालने (), गेट () (डिफ़ॉल्ट रिटर्न के साथ), सेट () और हटाने का समर्थन करता है ( ) संचालन।

आप गैर-शब्द वर्णों के साथ डॉट नोटेशन, ब्रैकेट्स, संख्या सूचकांकों, स्ट्रिंग संख्या गुणों और कुंजियों का उपयोग कर सकते हैं। नीचे सरल उपयोग:

> var jsocrud = require('jsocrud');

...

// Get (Read) ---
> var obj = {
>     foo: [
>         {
>             'key w/ non-word chars': 'bar'
>         }
>     ]
> };
undefined

> jsocrud.get(obj, '.foo[0]["key w/ non-word chars"]');
'bar'

https://www.npmjs.com/package/jsocrud

https://github.com/vertical-knowledge/jsocrud


3
/**
 * Access a deep value inside a object 
 * Works by passing a path like "foo.bar", also works with nested arrays like "foo[0][1].baz"
 * @author Victor B. https://gist.github.com/victornpb/4c7882c1b9d36292308e
 * Unit tests: http://jsfiddle.net/Victornpb/0u1qygrh/
 */
function getDeepVal(obj, path) {
    if (typeof obj === "undefined" || obj === null) return;
    path = path.split(/[\.\[\]\"\']{1,2}/);
    for (var i = 0, l = path.length; i < l; i++) {
        if (path[i] === "") continue;
        obj = obj[path[i]];
        if (typeof obj === "undefined" || obj === null) return;
    }
    return obj;
}

के साथ काम करता है

getDeepVal(obj,'foo.bar')
getDeepVal(obj,'foo.1.bar')
getDeepVal(obj,'foo[0].baz')
getDeepVal(obj,'foo[1][2]')
getDeepVal(obj,"foo['bar'].baz")
getDeepVal(obj,"foo['bar']['baz']")
getDeepVal(obj,"foo.bar.0.baz[1]['2']['w'].aaa[\"f\"].bb")

3

सरल कार्य, एक स्ट्रिंग या सरणी पथ के लिए अनुमति देता है।

function get(obj, path) {
  if(typeof path === 'string') path = path.split('.');

  if(path.length === 0) return obj;
  return get(obj[path[0]], path.slice(1));
}

const obj = {a: {b: {c: 'foo'}}};

console.log(get(obj, 'a.b.c')); //foo

या

console.log(get(obj, ['a', 'b', 'c'])); //foo

यदि आप उत्तर के रूप में कोड पोस्ट करने जा रहे हैं, तो कृपया बताएं कि कोड प्रश्न का उत्तर क्यों देता है।
टिसन टी।


2

हालांकि कम करना अच्छा है, मुझे आश्चर्य है कि कोई भी इसका इस्तेमाल नहीं करता है:

function valueForKeyPath(obj, path){
        const keys = path.split('.');
        keys.forEach((key)=> obj = obj[key]);
        return obj;
    };

परीक्षा


आप भी जाँच नहीं कर रहे हैं कि क्या वास्तव में मौजूद है। यह अविश्वसनीय है।
कारल्स अल्कोले

डिफ़ॉल्ट रूप से @CarlesAlcolea न तो जांच करेगा कि क्या किसी वस्तु की कुंजी मौजूद है: a.b.cयदि bआपकी वस्तु में कोई संपत्ति नहीं है तो एक अपवाद को बढ़ाएगा । आप कुछ चुपचाप गलत मुख्यपथ (जो मैं अनुशंसा नहीं करते) को आउट की जरूरत है, आप अभी भी इस एक के साथ foreach जगह ले सकता हैkeys.forEach((key)=> obj = (obj||{})[key]);
Flavien Volken

मैं इसे एक वस्तु के माध्यम से चलाता हूं जो एक घुंघराले ब्रेस को याद कर रही थी, मेरी बुरी :)
कार्ल्स अल्कोली

1

अभी हाल ही में एक ही प्रश्न था और सफलतापूर्वक https://npmjs.org/package/tea-properties का उपयोग किया गया था, जिसमें setऑब्जेक्ट या सरणियों को भी शामिल किया गया था:

प्राप्त:

var o = {
  prop: {
    arr: [
      {foo: 'bar'}
    ]
  }
};

var properties = require('tea-properties');
var value = properties.get(o, 'prop.arr[0].foo');

assert(value, 'bar'); // true

सेट:

var o = {};

var properties = require('tea-properties');
properties.set(o, 'prop.arr[0].foo', 'bar');

assert(o.prop.arr[0].foo, 'bar'); // true

"इस मॉड्यूल को बंद कर दिया गया है। chaijs / pathval का उपयोग करें।"
पैट्रिक फिशर

1

@ Webjay के जवाब से प्रेरित: https://stackoverflow.com/a/46008856/4110122

मैंने यह फ़ंक्शन बनाया है जिसका उपयोग आप ऑब्जेक्ट में किसी भी मान को प्राप्त / सेट / अनसेट करने के लिए कर सकते हैं

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

        let level = 0;
        var Return_Value;
        Path.reduce((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;
    }
}

इसके प्रयेाग के लिए:

 // Set
 Object_Manager(Obj,[Level1,Level2,Level3],New_Value, 'Set');

 // Get
 Object_Manager(Obj,[Level1,Level2,Level3],'', 'Get');

 // Unset
 Object_Manager(Obj,[Level1,Level2,Level3],'', 'Unset');

1

मैं रिएक्ट के साथ ऑनलाइन-शॉप विकसित कर रहा हूं। मैंने मूल स्टेट को अपडेट करने के लिए कॉपी स्टेट ऑब्जेक्ट में वैल्यू बदलने की कोशिश की। ऊपर दिए गए उदाहरणों ने मेरे लिए काम नहीं किया है, क्योंकि उनमें से अधिकांश नकल किए गए ऑब्जेक्ट की संरचना को बदलते हैं। मुझे गहरी नेस्टेड ऑब्जेक्ट गुणों के मूल्यों को एक्सेस करने और बदलने के लिए फ़ंक्शन का काम करने का उदाहरण मिला: https://lowrey.me/create-an-object-by-path-in-javascript-2/ यहां यह है:

const createPath = (obj, path, value = null) => {
  path = typeof path === 'string' ? path.split('.') : path;
  let current = obj;
  while (path.length > 1) {
    const [head, ...tail] = path;
    path = tail;
    if (current[head] === undefined) {
      current[head] = {};
    }
    current = current[head];
  }
  current[path[0]] = value;
  return obj;
};

1

अलनीतक के जवाब के आधार पर ।

मैंने पॉलीफ़िल को एक चेक में लपेट दिया, और फ़ंक्शन को एक ही जंजीर में कमी कर दिया।

if (Object.byPath === undefined) {
  Object.byPath = (obj, path) => path
    .replace(/\[(\w+)\]/g, '.$1')
    .replace(/^\./, '')
    .split(/\./g)
    .reduce((ref, key) => key in ref ? ref[key] : ref, obj)
}

const data = {
  foo: {
    bar: [{
      baz: 1
    }]
  }
}

console.log(Object.byPath(data, 'foo.bar[0].baz'))


0

यदि आपको कोडिंग समय पर यह जानने के बिना अलग-अलग नेस्टेड कुंजी तक पहुंचने की आवश्यकता है (यह उन्हें संबोधित करने के लिए तुच्छ होगा) आप सरणी संकेतन एक्सेसर का उपयोग कर सकते हैं:

var part1name = someObject['part1']['name'];
var part2quantity = someObject['part2']['qty'];
var part3name1 =  someObject['part3'][0]['name'];

वे डॉट नोटेशन एक्सेसर के बराबर हैं और उदाहरण के लिए रनटाइम पर भिन्न हो सकते हैं:

var part = 'part1';
var property = 'name';

var part1name = someObject[part][property];

के बराबर है

var part1name = someObject['part1']['name'];

या

var part1name = someObject.part1.name;

मुझे आशा है कि यह पता आपके सवाल ...

संपादित करें

मैं ऑब्जेक्ट वैल्यू तक पहुँचने के लिए एक प्रकार की xpath क्वेरी का उपयोग करने के लिए एक स्ट्रिंग का उपयोग नहीं करूंगा । जैसा कि आपको क्वेरी को पार्स करने के लिए एक फ़ंक्शन को कॉल करना होगा और उस मान को पुनः प्राप्त करना होगा जो मैं किसी अन्य पथ का अनुसरण करूंगा (नहीं:

var part1name = function(){ return this.part1.name; }
var part2quantity = function() { return this['part2']['qty']; }
var part3name1 =  function() { return this.part3[0]['name'];}

// usage: part1name.apply(someObject);

या, यदि आप लागू पद्धति से असहज हैं

var part1name = function(obj){ return obj.part1.name; }
var part2quantity = function(obj) { return obj['part2']['qty']; }
var part3name1 =  function(obj) { return obj.part3[0]['name'];}

// usage: part1name(someObject);

कार्य छोटे, स्पष्ट होते हैं, दुभाषिया आपको सिंटैक्स त्रुटियों और इतने पर आपके लिए जांचते हैं।

वैसे, मुझे लगता है कि सही समय पर किया गया एक साधारण काम पर्याप्त होगा ...


दिलचस्प। लेकिन मेरे मामले में, someObject अभी तक इनिशियलाइज़ है जब मैं part1name को वैल्यू असाइन करता हूँ। मैं केवल संरचना जानता हूं। यही कारण है कि मैं संरचना का वर्णन करने के लिए स्ट्रिंग का उपयोग करता हूं। और कुछ ओबजेक्ट से मेरे डेटा को क्वेरी करने के लिए इसका उपयोग करने में सक्षम होने की उम्मीद है। अपने विचार साझा करने के लिए धन्यवाद। :)
कोमारुलोह

@Komaruloh: मुझे लगता है कि आप लिखेंगे कि ऑब्जेक्ट अभी तक इनिशियलाइज़ नहीं हुआ है जब आप अपना वैरिएबल बनाते हैं। वैसे मुझे बात नहीं आती, आप उपयुक्त समय पर असाइनमेंट क्यों नहीं कर सकते?
आइनेकी

यह उल्लेख नहीं करने के बारे में क्षमा करें कि someObject अभी तक आरंभीकृत नहीं हुआ है। कारण के रूप में, someObject वेब सेवा के माध्यम से लाया जाता है। और मैं हेडर की एक सरणी रखना चाहता हूं जिसमें part1name, part2qty आदि शामिल हों, ताकि मैं हेडर ऐरे के माध्यम से सिर्फ लूप कर सकूं और मैं part1name वैल्यू के आधार पर वह मान प्राप्त कर सकूं जो 'key' / someObject के पथ के रूप में था।
कोमलारोह

0

यहाँ समाधान केवल गहरी नेस्टेड कुंजियों तक पहुँचने के लिए हैं। मुझे कुंजियों तक पहुंचने, जोड़ने, संशोधन करने और हटाने के लिए एक की आवश्यकता थी। मैंने ये ढूंढ निकाला:

var deepAccessObject = function(object, path_to_key, type_of_function, value){
    switch(type_of_function){
        //Add key/modify key
        case 0: 
            if(path_to_key.length === 1){
                if(value)
                    object[path_to_key[0]] = value;
                return object[path_to_key[0]];
            }else{
                if(object[path_to_key[0]])
                    return deepAccessObject(object[path_to_key[0]], path_to_key.slice(1), type_of_function, value);
                else
                    object[path_to_key[0]] = {};
            }
            break;
        //delete key
        case 1:
            if(path_to_key.length === 1){
                delete object[path_to_key[0]];
                return true;
            }else{
                if(object[path_to_key[0]])
                    return deepAccessObject(object[path_to_key[0]], path_to_key.slice(1), type_of_function, value);
                else
                    return false;
            }
            break;
        default:
            console.log("Wrong type of function");
    }
};
  • path_to_key: एक सरणी में पथ। आप इसे अपने द्वारा प्रतिस्थापित कर सकते हैं string_path.split(".")
  • type_of_function: पहुँचने के लिए 0 (किसी भी मान को पास न करें value), 0 जोड़ने और संशोधित करने के लिए। 1 हटाने के लिए।

0

अलनीतक के उत्तर का निर्माण:

if(!Object.prototype.byString){
  //NEW byString which can update values
Object.prototype.byString = function(s, v, o) {
  var _o = o || this;
      s = s.replace(/\[(\w+)\]/g, '.$1'); // CONVERT INDEXES TO PROPERTIES
      s = s.replace(/^\./, ''); // STRIP A LEADING DOT
      var a = s.split('.'); //ARRAY OF STRINGS SPLIT BY '.'
      for (var i = 0; i < a.length; ++i) {//LOOP OVER ARRAY OF STRINGS
          var k = a[i];
          if (k in _o) {//LOOP THROUGH OBJECT KEYS
              if(_o.hasOwnProperty(k)){//USE ONLY KEYS WE CREATED
                if(v !== undefined){//IF WE HAVE A NEW VALUE PARAM
                  if(i === a.length -1){//IF IT'S THE LAST IN THE ARRAY
                    _o[k] = v;
                  }
                }
                _o = _o[k];//NO NEW VALUE SO JUST RETURN THE CURRENT VALUE
              }
          } else {
              return;
          }
      }
      return _o;
  };

}

यह आपको एक मूल्य निर्धारित करने की अनुमति देता है!

मैंने एक npm पैकेज बनाया है और इसके साथ github भी


0

एक स्ट्रिंग के बजाय एक सरणी का उपयोग नेस्टेड ऑब्जेक्ट्स और सरणियों को स्वीकार करने के लिए किया जा सकता है जैसे: ["my_field", "another_field", 0, "last_field", 10]

यहाँ एक उदाहरण है जो इस सरणी प्रतिनिधित्व के आधार पर एक क्षेत्र को बदल देगा। मैं कुछ ऐसा उपयोग कर रहा हूं, जो नियंत्रित इनपुट फ़ील्ड के लिए react.js में है जो नेस्टेड संरचनाओं की स्थिति को बदलते हैं।

let state = {
        test: "test_value",
        nested: {
            level1: "level1 value"
        },
        arr: [1, 2, 3],
        nested_arr: {
            arr: ["buh", "bah", "foo"]
        }
    }

function handleChange(value, fields) {
    let update_field = state;
    for(var i = 0; i < fields.length - 1; i++){
        update_field = update_field[fields[i]];
    }
    update_field[fields[fields.length-1]] = value;
}

handleChange("update", ["test"]);
handleChange("update_nested", ["nested","level1"]);
handleChange(100, ["arr",0]);
handleChange('changed_foo', ["nested_arr", "arr", 3]);
console.log(state);

0

पिछले उत्तर के आधार पर, मैंने एक फ़ंक्शन बनाया है जो ब्रैकेट्स को भी संभाल सकता है। लेकिन बंटवारे के कारण उनके अंदर कोई बिंदु नहीं है।

function get(obj, str) {
  return str.split(/\.|\[/g).map(function(crumb) {
    return crumb.replace(/\]$/, '').trim().replace(/^(["'])((?:(?!\1)[^\\]|\\.)*?)\1$/, (match, quote, str) => str.replace(/\\(\\)?/g, "$1"));
  }).reduce(function(obj, prop) {
    return obj ? obj[prop] : undefined;
  }, obj);
}

0

// (IE9+) Two steps

var pathString = "[0]['property'].others[3].next['final']";
var obj = [{
  property: {
    others: [1, 2, 3, {
      next: {
        final: "SUCCESS"
      }
    }]
  }
}];

// Turn string to path array
var pathArray = pathString
    .replace(/\[["']?([\w]+)["']?\]/g,".$1")
    .split(".")
    .splice(1);

// Add object prototype method
Object.prototype.path = function (path) {
  try {
    return [this].concat(path).reduce(function (f, l) {
      return f[l];
    });
  } catch (e) {
    console.error(e);
  }
};

// usage
console.log(obj.path(pathArray));
console.log(obj.path([0,"doesNotExist"]));


0

के साथ कार्य करना Underscoreहै propertyया propertyOf:

var test = {
  foo: {
    bar: {
      baz: 'hello'
    }
  }
}
var string = 'foo.bar.baz';


// document.write(_.propertyOf(test)(string.split('.')))

document.write(_.property(string.split('.'))(test));
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>

शुभ लाभ...

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.