हालिया नोट: जब मैं चापलूसी कर रहा हूं कि इस उत्तर ने कई उत्थान प्राप्त किए हैं, तो मैं भी कुछ भयभीत हूं। अगर किसी को डॉट-नोटेशन स्ट्रिंग्स को "एक्सएबीसी" जैसे संदर्भों में बदलने की आवश्यकता है, तो यह (शायद) एक संकेत हो सकता है कि कुछ बहुत गलत चल रहा है (जब तक कि शायद आप कुछ अजीब deserialization प्रदर्शन कर रहे हों)।
यह कहना है, इस जवाब के लिए अपना रास्ता खोजने वाले नौसिखियों को खुद से सवाल पूछना चाहिए "मैं ऐसा क्यों कर रहा हूं?"
यह आम तौर पर ऐसा करने के लिए ठीक है अगर आपका उपयोग मामला छोटा है और आप प्रदर्शन के मुद्दों में नहीं चलेंगे, और आपको इसे अधिक जटिल बनाने के लिए अपने अमूर्त पर निर्माण करने की आवश्यकता नहीं होगी। वास्तव में, यदि यह कोड जटिलता को कम करेगा और चीजों को सरल रखेगा, तो आपको संभवतः आगे बढ़ना चाहिए और वही करना चाहिए जो ओपी पूछ रहा है। हालाँकि, अगर ऐसा नहीं है, तो विचार करें कि क्या इनमें से कोई भी लागू होता है:
केस 1 : अपने डेटा के साथ काम करने की प्राथमिक विधि के रूप में (उदाहरण के लिए आपके ऐप का डिफ़ॉल्ट रूप आस-पास से गुजरने वाली वस्तुओं के बारे में और उन्हें dereferencing करना)। जैसे पूछना "मैं एक स्ट्रिंग से एक फ़ंक्शन या चर नाम कैसे देख सकता हूं"।
- यह खराब प्रोग्रामिंग प्रैक्टिस है (विशेष रूप से अनावश्यक रूप से मेटाप्रोग्रामिंग, और फ़ंक्शन साइड साइड-इफ़ेक्ट-फ्री कोडिंग शैली का उल्लंघन करता है, और इसमें प्रदर्शन हिट होंगे)। इस मामले में खुद को खोजने वाले नोव्स को सरणी अभ्यावेदन के साथ काम करने पर विचार करना चाहिए, उदाहरण के लिए ['x', 'a', 'b', 'c'], या यदि संभव हो तो और भी कुछ प्रत्यक्ष / सरल / सीधा: पहली बार में स्वयं संदर्भों का ट्रैक (सबसे आदर्श यदि यह केवल क्लाइंट-साइड या केवल सर्वर-साइड है), आदि (एक पूर्व-मौजूदा अद्वितीय आईडी जोड़ने के लिए अयोग्य होगा, लेकिन इसका उपयोग तब किया जा सकता है जब युक्ति को अन्यथा इसकी आवश्यकता हो अस्तित्व की परवाह किए बिना।)
स्थिति 2 : क्रमबद्ध डेटा, या डेटा के साथ कार्य करना जो उपयोगकर्ता को प्रदर्शित किया जाएगा। जैसे डेट ऑब्जेक्ट के बजाय एक स्ट्रिंग "1999-12-30" के रूप में एक तारीख का उपयोग करना (जो कि टाइमज़ोन बग पैदा कर सकता है या सावधान नहीं होने पर क्रमबद्ध जटिलता जोड़ सकता है)। या आप जानते हैं कि आप क्या कर रहे हैं।
- यह शायद ठीक है। सावधान रहें कि कोई डॉट स्ट्रिंग्स नहीं हैं "।" आपके स्वीकृत इनपुट अंशों में।
यदि आप स्वयं को हर समय इस उत्तर का उपयोग करते हुए पाते हैं और स्ट्रिंग और एरे के बीच आगे-पीछे परिवर्तित करते हैं, तो आप खराब स्थिति में हो सकते हैं, और एक विकल्प पर विचार करना चाहिए।
यहाँ एक सुरुचिपूर्ण एक-लाइनर है जो अन्य समाधानों की तुलना में 10x छोटा है:
function index(obj,i) {return obj[i]}
'a.b.etc'.split('.').reduce(index, obj)
[संपादित करें] या ECMAScript 6 में:
'a.b.etc'.split('.').reduce((o,i)=>o[i], obj)
(ऐसा नहीं है कि मुझे लगता है कि eval हमेशा बुरा होता है, जैसा कि अन्य लोग सुझाव देते हैं कि यह (हालांकि यह आमतौर पर है), फिर भी वे लोग प्रसन्न होंगे कि यह विधि eval का उपयोग नहीं करती है। ऊपर obj.a.b.etcदिया गया objऔर स्ट्रिंग मिल जाएगा "a.b.etc"।)
उन लोगों के जवाब में जो अभी भी reduceईसीएमए -262 मानक (5 वें संस्करण) में होने के बावजूद उपयोग करने से डरते हैं , यहां एक दो-पंक्ति पुनरावर्ती कार्यान्वयन है:
function multiIndex(obj,is) { // obj,['1','2','3'] -> ((obj['1'])['2'])['3']
return is.length ? multiIndex(obj[is[0]],is.slice(1)) : obj
}
function pathIndex(obj,is) { // obj,'1.2.3' -> multiIndex(obj,['1','2','3'])
return multiIndex(obj,is.split('.'))
}
pathIndex('a.b.etc')
जेएस संकलक कर रहे अनुकूलन के आधार पर, आप यह सुनिश्चित करना चाहते हैं कि किसी भी नेस्टेड फ़ंक्शन को सामान्य तरीकों के माध्यम से हर कॉल पर फिर से परिभाषित नहीं किया जाता है (उन्हें एक क्लोजर, ऑब्जेक्ट या ग्लोबल नेमस्पेस में रखकर)।
संपादित करें :
टिप्पणियों में एक दिलचस्प सवाल का जवाब देने के लिए:
आप इसे एक सेटर में भी कैसे बदलेंगे? न केवल मूल्यों को पथ से लौटाना, बल्कि उन्हें सेट करना यदि कोई नया मान फ़ंक्शन में भेजा जाता है? - स्वेद जून 28 को 21:42 बजे
(sidenote: दुर्भाग्य से एक सेटर के साथ एक वस्तु लौट सकते हैं नहीं, कि के रूप में बुला सम्मेलन का उल्लंघन होगा, टिप्पणीकार के बजाय तरह दुष्प्रभाव के साथ एक सामान्य सेटर शैली समारोह की चर्चा करते हुए किया जा रहा है index(obj,"a.b.etc", value)कर रही है obj.a.b.etc = value।)
reduceशैली वास्तव में उस के लिए उपयुक्त नहीं है, लेकिन हम पुनरावर्ती कार्यान्वयन को संशोधित कर सकते हैं:
function index(obj,is, value) {
if (typeof is == 'string')
return index(obj,is.split('.'), value);
else if (is.length==1 && value!==undefined)
return obj[is[0]] = value;
else if (is.length==0)
return obj;
else
return index(obj[is[0]],is.slice(1), value);
}
डेमो:
> obj = {a:{b:{etc:5}}}
> index(obj,'a.b.etc')
5
> index(obj,['a','b','etc']) #works with both strings and lists
5
> index(obj,'a.b.etc', 123) #setter-mode - third argument (possibly poor form)
123
> index(obj,'a.b.etc')
123
... हालांकि व्यक्तिगत रूप से मैं एक अलग कार्य करने की सलाह दूंगा setIndex(...)। मैं एक साइड-नोट पर समाप्त करना चाहूंगा कि प्रश्न के मूल प्रस्तुतकर्ता को (चाहिए?) सूचकांकों के सरणियों (जो वे प्राप्त कर सकते हैं .split) के साथ काम कर सकते हैं , बजाय तार के; हालांकि आमतौर पर सुविधा समारोह में कुछ भी गलत नहीं है।
एक टिप्पणीकार ने पूछा:
सरणियों के बारे में क्या? "ab [4] .cd [1] [2] [3]" जैसा कुछ? -AlexS
जावास्क्रिप्ट एक बहुत ही अजीब भाषा है; सामान्य वस्तुओं में केवल उनकी संपत्ति की कुंजी के रूप में तार हो सकते हैं, इसलिए उदाहरण के लिए अगर xएक सामान्य वस्तु की तरह था x={}, तो x[1]बन जाएगा x["1"]... आप उस सही को पढ़ते हैं ... हाँ ...
जावास्क्रिप्ट एरर्स (जो स्वयं वस्तु के उदाहरण हैं) विशेष रूप से पूर्णांक कुंजियों को प्रोत्साहित करते हैं, भले ही आप कुछ ऐसा कर सकते थे x=[]; x["puppy"]=5;।
लेकिन सामान्य तौर पर (और अपवाद हैं), x["somestring"]===x.somestring(जब इसकी अनुमति हो; आप ऐसा नहीं कर सकते x.123)।
(ध्यान रखें कि जेएस संकलक जो भी आप उपयोग कर रहे हैं, चुन सकते हैं, हो सकता है, इन्हें नीचे सायन अभ्यावेदन के लिए संकलित करें यदि यह साबित कर सकता है कि यह युक्ति का उल्लंघन नहीं करेगा।)
तो आपके प्रश्न का उत्तर इस बात पर निर्भर करेगा कि क्या आप उन वस्तुओं को केवल पूर्णांक (आपके समस्या डोमेन में प्रतिबंध के कारण) स्वीकार करते हैं या नहीं। चलो मान नहीं। फिर एक मान्य अभिव्यक्ति एक आधार पहचानकर्ता का प्लस और कुछ .identifierएस प्लस कुछ ["stringindex"]एस है
यह तब के बराबर होगा a["b"][4]["c"]["d"][1][2][3], हालांकि हमें भी समर्थन करना चाहिए a.b["c\"validjsstringliteral"][3]। आपको एक मान्य स्ट्रिंग शाब्दिक पार्स करने के तरीके को देखने के लिए स्ट्रिंग शाब्दिकों पर पारिस्थितिकीय व्याकरण अनुभाग की जांच करनी होगी । तकनीकी रूप से आप भी जांचना चाहेंगे (मेरे पहले उत्तर के विपरीत) जो aएक मान्य जावास्क्रिप्ट पहचानकर्ता है ।
अपने प्रश्न का एक साधारण सवाल का जवाब हालांकि, अगर आपके तार अल्पविराम या कोष्ठक शामिल नहीं है , बस सेट में नहीं लंबाई 1+ वर्णों के क्रम मिलाने के लिए किया जाएगा ,या [या ]:
> "abc[4].c.def[1][2][\"gh\"]".match(/[^\]\[.]+/g)
// ^^^ ^ ^ ^^^ ^ ^ ^^^^^
["abc", "4", "c", "def", "1", "2", ""gh""]
यदि आपके तार में भागने के पात्र या "अक्षर नहीं हैं , और क्योंकि IdentifierNames StringLiterals का एक उपवर्ग है (मुझे लगता है कि ???) आप पहले अपने डॉट्स को बदल सकते हैं:
> var R=[], demoString="abc[4].c.def[1][2][\"gh\"]";
> for(var match,matcher=/^([^\.\[]+)|\.([^\.\[]+)|\["([^"]+)"\]|\[(\d+)\]/g;
match=matcher.exec(demoString); ) {
R.push(Array.from(match).slice(1).filter(x=>x!==undefined)[0]);
// extremely bad code because js regexes are weird, don't use this
}
> R
["abc", "4", "c", "def", "1", "2", "gh"]
बेशक, हमेशा सावधान रहें और कभी भी अपने डेटा पर भरोसा न करें। ऐसा करने के लिए कुछ बुरे तरीके जो कुछ उपयोग मामलों के लिए काम कर सकते हैं उनमें शामिल हैं:
// hackish/wrongish; preprocess your string into "a.b.4.c.d.1.2.3", e.g.:
> yourstring.replace(/]/g,"").replace(/\[/g,".").split(".")
"a.b.4.c.d.1.2.3" //use code from before
विशेष 2018 संपादित करें:
चलो पूर्ण-चक्र जाते हैं और सबसे अक्षम, भयावह-ओवरमेटप्रोग्राम किए गए समाधान करते हैं, जो हम साथ आ सकते हैं ... सिंटैक्टिकल शुद्धता हैमिस्टर के हित में । ES6 प्रॉक्सी ऑब्जेक्ट्स के साथ! ... आइए कुछ गुणों को भी परिभाषित करें जो (imho ठीक और अद्भुत हैं लेकिन) अनुचित रूप से लिखे गए पुस्तकालयों को तोड़ सकते हैं। आपको शायद इसका उपयोग करने से सावधान रहना चाहिए यदि आप प्रदर्शन, पवित्रता (आपका या दूसरों का), अपनी नौकरी आदि की परवाह करते हैं।
// [1,2,3][-1]==3 (or just use .slice(-1)[0])
if (![1][-1])
Object.defineProperty(Array.prototype, -1, {get() {return this[this.length-1]}}); //credit to caub
// WARNING: THIS XTREME™ RADICAL METHOD IS VERY INEFFICIENT,
// ESPECIALLY IF INDEXING INTO MULTIPLE OBJECTS,
// because you are constantly creating wrapper objects on-the-fly and,
// even worse, going through Proxy i.e. runtime ~reflection, which prevents
// compiler optimization
// Proxy handler to override obj[*]/obj.* and obj[*]=...
var hyperIndexProxyHandler = {
get: function(obj,key, proxy) {
return key.split('.').reduce((o,i)=>o[i], obj);
},
set: function(obj,key,value, proxy) {
var keys = key.split('.');
var beforeLast = keys.slice(0,-1).reduce((o,i)=>o[i], obj);
beforeLast[keys[-1]] = value;
},
has: function(obj,key) {
//etc
}
};
function hyperIndexOf(target) {
return new Proxy(target, hyperIndexProxyHandler);
}
डेमो:
var obj = {a:{b:{c:1, d:2}}};
console.log("obj is:", JSON.stringify(obj));
var objHyper = hyperIndexOf(obj);
console.log("(proxy override get) objHyper['a.b.c'] is:", objHyper['a.b.c']);
objHyper['a.b.c'] = 3;
console.log("(proxy override set) objHyper['a.b.c']=3, now obj is:", JSON.stringify(obj));
console.log("(behind the scenes) objHyper is:", objHyper);
if (!({}).H)
Object.defineProperties(Object.prototype, {
H: {
get: function() {
return hyperIndexOf(this); // TODO:cache as a non-enumerable property for efficiency?
}
}
});
console.log("(shortcut) obj.H['a.b.c']=4");
obj.H['a.b.c'] = 4;
console.log("(shortcut) obj.H['a.b.c'] is obj['a']['b']['c'] is", obj.H['a.b.c']);
आउटपुट:
obj है: {"a": {"b": {"c": 1, "d": 2}}}
(प्रॉक्सी ओवरराइड मिलता है) objHyper ['abc'] है: 1
(प्रॉक्सी ओवरराइड सेट) objHyper ['abc'] = 3, अब obj है: {"a": {"b": {"c": 3, "d": 2}}}
(पर्दे के पीछे) objHyper है: प्रॉक्सी {a: {…}}
(शॉर्टकट) obj.H ['abc'] = 4
(शॉर्टकट) obj.H ['abc'] obj ['a'] ['b'] ['c' है: 4
अक्षम विचार: आप इनपुट तर्क के आधार पर प्रेषण के लिए ऊपर संशोधित कर सकते हैं; या तो .match(/[^\]\[.]+/g)समर्थन करने के लिए विधि का उपयोग करें obj['keys'].like[3]['this'], या यदि instanceof Array, तो इनपुट के रूप में एक ऐरे को स्वीकार करें keys = ['a','b','c']; obj.H[keys]।
प्रति सुझाव है कि शायद आप 'नरम' NaN- शैली के तरीके में अपरिभाषित सूचकांकों को संभालना चाहते हैं (जैसे index({a:{b:{c:...}}}, 'a.x.c')बिना पढ़े टाइपर्रर के बजाय अनिर्धारित वापसी) ...:
1) यह 1-आयामी सूचकांक स्थिति ({}) ['जैसे'] == अपरिभाषित में "हमें एक त्रुटि फेंकने के बजाय अपरिभाषित लौटना चाहिए," के परिप्रेक्ष्य से समझ में आता है, इसलिए "हमें फेंकने के बजाय अपरिभाषित लौटना चाहिए" त्रुटि "एन-आयामी स्थिति में।
2) इसका मतलब यह नहीं है कि हम जो परिप्रेक्ष्य कर रहे हैं x['a']['x']['c'], उससे ऊपर के उदाहरण में टाइपर्रर के साथ असफल हो जाएंगे।
उसने कहा, आप अपने कम करने के कार्य को बदलकर यह काम करेंगे:
(o,i)=>o===undefined?undefined:o[i], या
(o,i)=>(o||{})[i]।
(जब आप अगली बार अनुक्रमणिका को अपरिभाषित कर रहे हों, या जब आप ऐसी असफलताओं की पर्याप्त रूप से दुर्लभ होने की उम्मीद करते हैं, तो प्रयोग करने पर आप लूप और ब्रेकिंग / रिटर्न के लिए उपयोग करके इसे और अधिक कुशल बना सकते हैं।)
evalबुराई है; इसे इस्तेमाल न करें