नेस्टेड जावास्क्रिप्ट ऑब्जेक्ट कुंजी के अस्तित्व के लिए टेस्ट


691

यदि मेरे पास किसी वस्तु का संदर्भ है:

var test = {};

संभावित रूप से (लेकिन तुरंत नहीं) ने नेस्टेड ऑब्जेक्ट्स, जैसे कुछ:

{level1: {level2: {level3: "level3"}}};

गहरी नेस्टेड वस्तुओं में संपत्ति के अस्तित्व की जांच करने का सबसे अच्छा तरीका क्या है?

alert(test.level1);पैदावार undefined, लेकिन alert(test.level1.level2.level3);असफल।

मैं वर्तमान में ऐसा कुछ कर रहा हूं:

if(test.level1 && test.level1.level2 && test.level1.level2.level3) {
    alert(test.level1.level2.level3);
}

लेकिन मैं सोच रहा था कि क्या कोई बेहतर तरीका है।


1
यदि आप एक स्पर्शरेखीय संबंधित सवाल है कि हाल ही में पूछा गया था जांच करना चाह सकते stackoverflow.com/questions/2525943/...
अनुराग


प्रस्ताव के एक जोड़े: stackoverflow.com/a/18381564/1636522
पत्ती

आपके वर्तमान दृष्टिकोण में एक संभावित मुद्दा है यदि लेवल 3 संपत्ति झूठी है, तो उस स्थिति में, भले ही संपत्ति मौजूद हो, फिर भी पीछे हटना होगा, इस उदाहरण पर एक नजर डालते हैं, कृपया jsfiddle.net/maz9bLjx
गिब्बोके

10
बस आप ट्राई कैच का भी इस्तेमाल कर सकते हैं
राघवेंद्र

जवाबों:


487

यदि आपको ऐसा नहीं करना है, तो आपको इसे चरण दर चरण करना होगा TypeErrorक्योंकि यदि कोई एक सदस्य है nullया undefined, और आप किसी सदस्य को एक्सेस करने का प्रयास करते हैं, तो एक अपवाद फेंक दिया जाएगा।

आप या तो केवल catchअपवाद कर सकते हैं, या कई स्तरों के अस्तित्व का परीक्षण करने के लिए एक समारोह बना सकते हैं, कुछ इस तरह से:

function checkNested(obj /*, level1, level2, ... levelN*/) {
  var args = Array.prototype.slice.call(arguments, 1);

  for (var i = 0; i < args.length; i++) {
    if (!obj || !obj.hasOwnProperty(args[i])) {
      return false;
    }
    obj = obj[args[i]];
  }
  return true;
}

var test = {level1:{level2:{level3:'level3'}} };

checkNested(test, 'level1', 'level2', 'level3'); // true
checkNested(test, 'level1', 'level2', 'foo'); // false

ES6 अद्यतन:

यहाँ मूल फ़ंक्शन का एक छोटा संस्करण है, ES6 सुविधाओं और पुनरावृत्ति का उपयोग करके (यह उचित टेल कॉल फ़ॉर्म में भी है ):

function checkNested(obj, level,  ...rest) {
  if (obj === undefined) return false
  if (rest.length == 0 && obj.hasOwnProperty(level)) return true
  return checkNested(obj[level], ...rest)
}

हालाँकि, यदि आप किसी नेस्टेड प्रॉपर्टी का मूल्य प्राप्त करना चाहते हैं और न केवल उसके अस्तित्व की जाँच करना चाहते हैं, तो यहाँ एक सरल एक-लाइन फ़ंक्शन है:

function getNested(obj, ...args) {
  return args.reduce((obj, level) => obj && obj[level], obj)
}

const test = { level1:{ level2:{ level3:'level3'} } };
console.log(getNested(test, 'level1', 'level2', 'level3')); // 'level3'
console.log(getNested(test, 'level1', 'level2', 'level3', 'length')); // 6
console.log(getNested(test, 'level1', 'level2', 'foo')); // undefined
console.log(getNested(test, 'a', 'b')); // undefined

उपरोक्त फ़ंक्शन आपको नेस्टेड गुणों का मूल्य प्राप्त करने की अनुमति देता है, अन्यथा वापस आ जाएगा undefined

अद्यतन 2019-10-17:

वैकल्पिक श्रृंखलन प्रस्ताव पर स्टेज 3 पर पहुंच गया ECMAScript समिति प्रक्रिया , इस की अनुमति देगा आप सुरक्षित रूप से पहुँच गहरा नीडिंत गुण, टोकन का उपयोग करके करने के लिए ?., नए वैकल्पिक श्रृंखलन ऑपरेटर :

const value = obj?.level1?.level2?.level3 

यदि किसी भी स्तर तक पहुंच है nullयाundefined अभिव्यक्ति का समाधान होगाundefined

प्रस्ताव आपको सुरक्षित तरीके से कॉल करने की अनुमति देता है:

obj?.level1?.method();

ऊपर अभिव्यक्ति का उत्पादन करेगा undefinedअगर obj, obj.level1या obj.level1.methodकर रहे हैं nullयाundefined , अन्यथा यह समारोह कॉल करेंगे।

आप वैकल्पिक चैनिंग प्लगइन का उपयोग करके बैबिल के साथ इस सुविधा के साथ खेलना शुरू कर सकते हैं ।

चूंकि बाबेल 7.8.0, ES2020 डिफ़ॉल्ट रूप से समर्थित है

इस उदाहरण को Babel REPL पर जाँचें ।

Dअपडेट: दिसंबर २०१ ९:

वैकल्पिक चाइनिंग प्रस्ताव आखिरकार TC39 समिति की दिसंबर 2019 की बैठक में स्टेज 4 तक पहुंच गया । इसका मतलब है कि यह सुविधा ECMAScript 2020 स्टैंडर्ड का हिस्सा होगी ।


4
argumentsवास्तव में एक सरणी नहीं है। Array.prototype.slice.call(arguments)इसे एक औपचारिक सरणी में परिवर्तित करता है। जानें
deefour

23
हो this'd अधिक कुशल एक बहुत करने के लिए var obj = arguments[0];और से शुरू var i = 1की प्रतिलिपि बनाने के बजाय argumentsवस्तु
Claudiu

2
मैंने तपस्या के लिए कोशिश / पकड़ के साथ एक संस्करण रखा, और कोई आश्चर्य नहीं - प्रदर्शन भयानक है (किसी कारण से सफारी को छोड़कर)। नीचे कुछ उत्तर दिए गए हैं जो कि बहुत अच्छे हैं, साथ में क्लाउडीयू का संशोधन भी है जो चयनित उत्तर की तुलना में काफी अधिक अच्छा है। यहाँ jsperf
netpoetica

3
ईएस 6 में argsचर घोषणा को हटाया जा सकता है और ...args इसे checkNestedविधि के दूसरे तर्क के रूप में इस्तेमाल किया जा सकता है । developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
वर्नोन

6
यह बहुत अचूक बात है। यदि कोई संपत्ति कुंजी बदलती है (वे करेंगे), तो परियोजना के सभी देवों को पूरे कोडबेस को 'स्ट्रिंग खोज' करना होगा। यह वास्तव में समस्या का समाधान नहीं है, क्योंकि यह एक बहुत बड़ी समस्या का परिचय देता है
Drenai

357

यहाँ एक पैटर्न है जिसे मैंने ओलिवर स्टील से उठाया है :

var level3 = (((test || {}).level1 || {}).level2 || {}).level3;
alert( level3 );

वास्तव में कि पूरा लेख इस बात की चर्चा है कि आप इसे जावास्क्रिप्ट में कैसे कर सकते हैं। वह एक मुहावरे के रूप में उपरोक्त वाक्य रचना (जो एक बार पढ़ने के बाद आपको इसकी आदत हो जाती है) का उपयोग करने पर नहीं बैठती है।


8
@ मुझे लगता है कि यह दिलचस्प है कि यह कितना संक्षिप्त है। लिंक्ड पोस्ट में प्रदर्शन विशेषताओं की विस्तृत चर्चा है। हाँ, यह हमेशा सभी परीक्षण करता है, लेकिन यह अस्थायी var बनाने से बचता है, और यदि आप हर बार एक नई खाली वस्तु बनाने के ओवरहेड को रोकना चाहते हैं, तो आप {} को एक अन्य नाम दे सकते हैं। 99% मामलों में मैं गति की उम्मीद नहीं करूंगा, और ऐसे मामलों में जहां यह प्रोफाइलिंग के लिए कोई विकल्प नहीं है।
गाबे मुथरत

9
@MuhammadUmer नहीं, मुद्दा (test || {})यह है कि यदि परीक्षण अपरिभाषित है, तो आप कर रहे हैं ({}.level1 || {})। बेशक, {}.level1अपरिभाषित है, तो इसका मतलब है कि आप कर रहे हैं {}.level2, और इसी तरह।
जोशुआ टेलर

3
@JoshuaTaylor: मुझे लगता है कि उसका मतलब है कि अगर testघोषित नहीं किया गया है, तो एक संदर्भ हो जाएगा , लेकिन यह एक समस्या नहीं है, क्योंकि अगर यह घोषित नहीं किया जाता है, तो एक बग को ठीक किया जाना है, इसलिए त्रुटि एक अच्छी बात है।

34
आपने कहा कि "जो आपको पढ़ने की आदत नहीं है वह एक बार पढ़ने के लिए तैयार हो जाता है" । खैर, ये ऐसे संकेत हैं जिन्हें आप पहले से ही जानते हैं कि यह एक गड़बड़ है । फिर इस समाधान का सुझाव क्यों दें? यह टाइपोस के लिए प्रवण है और पठनीयता के लिए बिल्कुल कुछ नहीं देता है। जरा देखो तो! मैं तो करने के लिए है एक बदसूरत लाइन लिखते हैं, यह हो asswell चाहिए पठनीय ; तो मैं बस के साथ जा रहा हूँif(test.level1 && test.level1.level2 && test.level1.level2.level3)
Sharky

8
जब तक मैं कुछ याद कर रहा हूँ, यह बूलियन अंत-संपत्तियों के लिए काम नहीं करेगा जो गलत हो सकता है ... दुख की बात है। वरना मुझे यह मुहावरा बहुत पसंद है।
T3db0t

261

अपडेट करें

लगता है कि आपकी सभी नेस्टेड प्रॉपर्टी की जरूरतों के लिए लॉश को जोड़ा गया है _.get

_.get(countries, 'greece.sparta.playwright')

https://lodash.com/docs#get


पिछला उत्तर

lodash उपयोगकर्ताओं का आनंद ले सकते lodash.contrib जो एक है जोड़ी तरीकों कि इस समस्या को कम

getPath

हस्ताक्षर: _.getPath(obj:Object, ks:String|Array)

दी गई कुंजियों के आधार पर किसी नेस्टेड ऑब्जेक्ट में किसी भी गहराई पर मूल्य प्राप्त होता है। कुंजियों को एक सरणी के रूप में या डॉट-पृथक स्ट्रिंग के रूप में दिया जा सकता है। undefinedयदि पथ तक नहीं पहुँचा जा सकता है, तो लौटाता है ।

var countries = {
        greece: {
            athens: {
                playwright:  "Sophocles"
            }
        }
    }
};

_.getPath(countries, "greece.athens.playwright");
// => "Sophocles"

_.getPath(countries, "greece.sparta.playwright");
// => undefined

_.getPath(countries, ["greece", "athens", "playwright"]);
// => "Sophocles"

_.getPath(countries, ["greece", "sparta", "playwright"]);
// => undefined

लोडश को वास्तव में _.isPathDefined (obj, pathString) विधि की आवश्यकता होती है।
मैथ्यू पायने

@MatthewPayne यह शायद अच्छा होगा, लेकिन यह वास्तव में आवश्यक नहीं है। आप इसे स्वयं वास्तव में आसानी से कर सकते हैंfunction isPathDefined(object, path) { return typeof _.getPath(object, path) !== 'undefined'; }
थोरोनो

11
लोदाश की अपनी यह कार्यक्षमता स्वयं है:_.get(countries, 'greece.sparta.playwright', 'default'); // → 'default' _.has(countries, 'greece.spart.playwright') // → false
टॉम

इससे भी बेहतर होगा _.result
शिशिर अरोरा

यदि आपको कई अलग-अलग रास्तों पर विचार करने की आवश्यकता है: var url = _.get(e, 'currentTarget.myurl', null) || _.get(e, 'currentTarget.attributes.myurl.nodeValue', null) || null
साइमन हचिसन

210

मैंने नीचे परीक्षण के परिणामों के साथ इस प्रश्न के लिए प्रस्तावित सुझावों में से कुछ पर प्रदर्शन परीक्षण (धन्यवाद दर्ज करने के लिए cdMinix धन्यवाद ) किया है।

डिस्क्लेमर # 1 संदर्भ में तारों को बदलना अनावश्यक मेटा-प्रोग्रामिंग है और शायद सबसे अच्छा बचा है। शुरू करने के लिए अपने संदर्भों का ट्रैक न खोएं। इस प्रश्न के उत्तर से एक समान प्रश्न पढ़ें

अस्वीकरण # 2 हम यहां प्रति मिलीसेकंड लाखों ऑपरेशनों के बारे में बात कर रहे हैं। यह बहुत संभावना नहीं है कि इनमें से कोई भी अधिकांश उपयोग के मामलों में बहुत अंतर करेगा। जो भी चुनें सबसे अधिक समझ में आता है प्रत्येक की सीमाएं। मेरे लिए मैं कुछ reduceसुविधा के साथ जाना चाहूंगा ।

ऑब्जेक्ट रैप (ओलिवर स्टील द्वारा) - 34% - सबसे तेज

var r1 = (((test || {}).level1 || {}).level2 || {}).level3;
var r2 = (((test || {}).level1 || {}).level2 || {}).foo;

मूल समाधान (प्रश्न में सुझाया गया) - 45%

var r1 = test.level1 && test.level1.level2 && test.level1.level2.level3;
var r2 = test.level1 && test.level1.level2 && test.level1.level2.foo;

checkNested - 50%

function checkNested(obj) {
  for (var i = 1; i < arguments.length; i++) {
    if (!obj.hasOwnProperty(arguments[i])) {
      return false;
    }
    obj = obj[arguments[i]];
  }
  return true;
}

get_if_exist - 52%

function get_if_exist(str) {
    try { return eval(str) }
    catch(e) { return undefined }
}

validChain - ५४%

function validChain( object, ...keys ) {
    return keys.reduce( ( a, b ) => ( a || { } )[ b ], object ) !== undefined;
}

objHasKeys - 63%

function objHasKeys(obj, keys) {
  var next = keys.shift();
  return obj[next] && (! keys.length || objHasKeys(obj[next], keys));
}

nestedPropertyExists - 69%

function nestedPropertyExists(obj, props) {
    var prop = props.shift();
    return prop === undefined ? true : obj.hasOwnProperty(prop) ? nestedPropertyExists(obj[prop], props) : false;
}

_.get - 72%

deeptest - 86%

function deeptest(target, s){
    s= s.split('.')
    var obj= target[s.shift()];
    while(obj && s.length) obj= obj[s.shift()];
    return obj;
}

उदास जोकर - 100% - सबसे धीमा

var o = function(obj) { return obj || {} };

var r1 = o(o(o(o(test).level1).level2).level3);
var r2 = o(o(o(o(test).level1).level2).foo);

16
यह ध्यान दिया जाना चाहिए कि एक परीक्षण में जितना अधिक% है - SLOWER यह है
हिमस्खलन

2
क्या दर्ज है _.get()? यह उन उत्तरों की तुलना में कैसा प्रदर्शन करता है?
बेनीकटे

1
स्थिति के आधार पर इनमें से प्रत्येक विधि अन्य की तुलना में धीमी या तेज है। यदि सभी कुंजियाँ मिल जाती हैं तो "ऑब्जेक्ट रैप" सबसे तेज़ हो सकता है, लेकिन यदि कोई कुंजी नहीं मिली है तो "मूल समाधान / मूल समाधान" तेज हो सकता है।
badReiko

1
@evilReiko अगर कोई कुंजी नहीं मिलती है तो कोई भी तरीका धीमा होगा लेकिन एक दूसरे के अनुपात में यह अभी भी बहुत समान है। हालाँकि, आप सही हैं - यह किसी भी चीज़ से ज्यादा एक बौद्धिक व्यायाम है। हम यहां प्रति मिलियन एक लाख पुनरावृत्तियों के बारे में बात कर रहे हैं। मुझे ऐसा कोई उपयोग मामला नहीं दिखाई देता जहाँ इससे बहुत अंतर पड़ता। मुझे व्यक्तिगत रूप से सुविधा के लिए reduceया try/catchबाहर जाना होगा ।
यूनिटेरियो

कैसा प्रदर्शन है इसकी तुलनाtry { test.level1.level2.level3 } catch (e) { // some logger e }
लेक्स

46

आप किसी भी गहराई पर ऑब्जेक्ट प्रॉपर्टी को पढ़ सकते हैं, यदि आप स्ट्रिंग की तरह नाम को संभालते हैं 't.level1.level2.level3':।

window.t={level1:{level2:{level3: 'level3'}}};

function deeptest(s){
    s= s.split('.')
    var obj= window[s.shift()];
    while(obj && s.length) obj= obj[s.shift()];
    return obj;
}

alert(deeptest('t.level1.level2.level3') || 'Undefined');

undefinedयदि कोई खंड है तो यह वापस आ जाता है undefined


3
ध्यान देने योग्य बात यह है कि यह विधि बहुत ही निष्पादन योग्य है, कम से कम क्रोम में, कुछ मामलों में @Claudiu द्वारा चयनित उत्तर के संशोधित संस्करण की तुलना में बेहतर है। यहां प्रदर्शन परीक्षण देखें: jsperf.com/check-if-deep-property-exists-with-willnotthrow
netpoetica

28
var a;

a = {
    b: {
        c: 'd'
    }
};

function isset (fn) {
    var value;
    try {
        value = fn();
    } catch (e) {
        value = undefined;
    } finally {
        return value !== undefined;
    }
};

// ES5
console.log(
    isset(function () { return a.b.c; }),
    isset(function () { return a.b.c.d.e.f; })
);

यदि आप ES6 वातावरण में कोडिंग कर रहे हैं (या 6to5 का उपयोग करके ) तो आप तीर फ़ंक्शन सिंटैक्स का लाभ उठा सकते हैं :

// ES6 using the arrow function
console.log(
    isset(() => a.b.c),
    isset(() => a.b.c.d.e.f)
);

प्रदर्शन के संबंध में, उपयोग करने के लिए कोई प्रदर्शन दंड नहीं है try..catch संपत्ति सेट होने पर ब्लॉक है। संपत्ति के परेशान होने पर प्रदर्शन प्रभाव पड़ता है।

केवल उपयोग पर विचार करें _.has:

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

_.has(object, 'a');
// → true

_.has(object, 'a.b.c');
// → true

_.has(object, ['a', 'b', 'c']);
// → true

2
मुझे लगता है कि try-catchदृष्टिकोण सबसे अच्छा जवाब है। किसी ऑब्जेक्ट को उसके प्रकार के लिए क्वेरी करने और API मौजूद होने और उसके अनुसार विफल होने के बीच एक दार्शनिक अंतर है। उत्तरार्द्ध शिथिल टाइप की भाषाओं में अधिक उपयुक्त है। Stackoverflow.com/a/408305/2419669 पर देखें । की तुलना में try-catchदृष्टिकोण भी अधिक स्पष्ट है if (foo && foo.bar && foo.bar.baz && foo.bar.baz.qux) { ... }
यांगमिल्सथेओरी

24

कैसा रहेगा

try {
   alert(test.level1.level2.level3)
} catch(e) {
 ...whatever

}

15
मुझे नहीं लगता कि किसी वस्तु के अस्तित्व के लिए परीक्षण / कैच एक अच्छा तरीका है: कोशिश / कैच का मतलब अपवादों को संभालना है, न कि सामान्य परिस्थितियों जैसे कि यहां परीक्षण। मुझे लगता है कि प्रत्येक चरण में टाइपोफू == "अपरिभाषित") बेहतर है - और सामान्य तौर पर, यदि आप इस तरह के गहरे नेस्टेड गुणों के साथ काम कर रहे हैं तो संभवतः कुछ रिफैक्टिंग की आवश्यकता है। इसके अलावा, यदि कोई अपवाद फेंका जाता है, तो फायरबग (और किसी भी ब्राउज़र में जहां ब्रेक-ऑन-एरर चालू होता है) में कोशिश / कैच का कारण होगा।
सैम डटन

मैं इस पर वोट देता हूं, क्योंकि यदि आप अन्य समाधानों का उपयोग करते हैं तो ब्राउज़र दो बार अस्तित्व की जांच करेगा। कहते हैं कि आप sayacb = 2 to पर कॉल करना चाहते हैं। ब्राउज़र को मूल्य को संशोधित करने से पहले अस्तित्व की जांच करनी होगी (अन्यथा यह ओएस द्वारा पकड़ी गई मेमोरी त्रुटि होगी)।

4
प्रश्न अभी भी बना हुआ है: डायन एक ब्राउज़र के लिए तेजी से एक hasOwnProperty()एन कैच या एन कॉल सेट करने के लिए तेज़ है ?

14
यह फिर से खराब क्यों है? यह मुझे सबसे साफ दिखता है।
ऑस्टिन प्रार्थना

मैं कहूंगा: यदि आप उम्मीद करते हैं कि संपत्ति मौजूद है तो इसे एक कोशिश ब्लॉक में लपेटना ठीक है। यदि यह मौजूद नहीं है तो यह एक त्रुटि है। लेकिन अगर आप सिर्फ आलसी हैं और इस मामले के लिए कैच ब्लॉक में नियमित कोड डालते हैं कि संपत्ति मौजूद नहीं है / पकड़ने का दुरुपयोग नहीं किया गया है। यहाँ एक if / else या कुछ समान की आवश्यकता है।
robsch

18

ES6 उत्तर, अच्छी तरह से परीक्षण :)

const propExists = (obj, path) => {
    return !!path.split('.').reduce((obj, prop) => {
        return obj && obj[prop] ? obj[prop] : undefined;
    }, obj)
}

कोडपेन को पूर्ण परीक्षण कवरेज के साथ देखें


मैंने आपके परीक्षणों को फ्लैट प्रोप के मूल्य को 0 पर सेट करने में विफल कर दिया। आपको प्रकार के ज़बरदस्ती के बारे में ध्यान रखना चाहिए।
जर्मेन

@germain क्या यह आपके लिए काम करता है ? (मैं स्पष्ट रूप ===से अलग-अलग मिथकों के लिए तुलना करता हूं, और जोड़ा गया परीक्षण। यदि आपके पास बेहतर विचार है, तो मुझे बताएं)।
फ्रैंक नॉक

मैंने फ्लैट परीक्षण के मूल्य को फिर से स्थापित करने में आपके परीक्षणों को विफल कर दिया false। और तब आप अपने ऑब्जेक्ट में एक मान सेट करना चाह सकते हैं undefined(मुझे पता है कि यह अजीब है, लेकिन जेएस है)। मैं के लिए एक सकारात्मक झूठी मान सेट किए गए 'Prop not Found':const hasTruthyProp = prop => prop === 'Prop not found' ? false : true const path = obj => path => path.reduce((obj, prop) => { return obj && obj.hasOwnProperty(prop) ? obj[prop] : 'Prop not found' }, obj) const myFunc = compose(hasTruthyProp, path(obj))
जर्मेन

क्या आप मेरे कोडपेन (टॉप-राइट, आसान), सही और परीक्षण जोड़ सकते हैं, और मुझे आपका URL भेज सकते हैं? धन्यवाद =)
फ्रैंक नॉक

एक (विशाल) 3 पार्टी पुस्तकालय के लिए भाग रहा है ... संभव है, लेकिन मेरी प्राथमिकता नहीं।
फ्रैंक नोके

17

आप भी babc 7 के साथ मिलकर tc39 वैकल्पिक चैनिंग प्रस्ताव का उपयोग कर सकते हैं - tc39- प्रस्ताव-वैकल्पिक-चेनिंग

कोड इस तरह दिखेगा:

  const test = test?.level1?.level2?.level3;
  if (test) alert(test);

ध्यान दें कि यह सिंटैक्स लगभग निश्चित रूप से बदल जाएगा, क्योंकि कुछ TC39 सदस्यों को आपत्तियां हैं।
झपट्ट GOFUNDME RELICENSING

शायद लेकिन यह समय में किसी न किसी रूप में उपलब्ध होगा, और यह एकमात्र ऐसी चीज है जो मायने रखती है .. यह उन विशेषताओं में से एक है जो मुझे जेएस में सबसे ज्यादा याद आती है।
गोरान।

11

मैंने एक पुनरावर्ती दृष्टिकोण की कोशिश की:

function objHasKeys(obj, keys) {
  var next = keys.shift();
  return obj[next] && (! keys.length || objHasKeys(obj[next], keys));
}

! keys.length ||प्रत्यावर्तन से बाहर किक इसलिए यह कोई कुंजी परीक्षण के लिए छोड़ दिया साथ समारोह नहीं चलता है। टेस्ट:

obj = {
  path: {
    to: {
      the: {
        goodKey: "hello"
      }
    }
  }
}

console.log(objHasKeys(obj, ['path', 'to', 'the', 'goodKey'])); // true
console.log(objHasKeys(obj, ['path', 'to', 'the', 'badKey']));  // undefined

मैं इसका उपयोग अज्ञात कुंजी / मूल्यों के साथ वस्तुओं के एक गुच्छा के एक अनुकूल HTML दृश्य को प्रिंट करने के लिए कर रहा हूं, उदाहरण के लिए:

var biosName = objHasKeys(myObj, 'MachineInfo:BiosInfo:Name'.split(':'))
             ? myObj.MachineInfo.BiosInfo.Name
             : 'unknown';

9

मुझे लगता है कि निम्नलिखित स्क्रिप्ट अधिक पठनीय प्रतिनिधित्व देती है।

एक समारोह घोषित करें:

var o = function(obj) { return obj || {};};

फिर इसे इस तरह उपयोग करें:

if (o(o(o(o(test).level1).level2).level3)
{

}

मैं इसे "उदास मसख़रा तकनीक" कहता हूं क्योंकि यह साइन ओ का उपयोग कर रहा है (


संपादित करें:

यहां टाइपस्क्रिप्ट के लिए एक संस्करण है

यह संकलित समय पर टाइप चेक देता है (साथ ही साथ अगर आप किसी उपकरण का उपयोग करते हैं जैसे विजुअल स्टूडियो)

export function o<T>(someObject: T, defaultValue: T = {} as T) : T {
    if (typeof someObject === 'undefined' || someObject === null)
        return defaultValue;
    else
        return someObject;
}

उपयोग समान है:

o(o(o(o(test).level1).level2).level3

लेकिन इस बार intellisense काम करता है!

साथ ही, आप एक डिफ़ॉल्ट मान सेट कर सकते हैं:

o(o(o(o(o(test).level1).level2).level3, "none")


1
मुझे यह पसंद है, क्योंकि यह ईमानदार है और आपके चेहरे पर एक "अपरिभाषित" फेंकता है जब आप अपने Objectप्रकार को नहीं जानते हैं । +1।

1
जब तक आप कोष्ठक में बयान रखने आप भी कॉल कर सकते हैं यह खुश जोकर तकनीक (ओ
Sventies

धन्यवाद Sventies। मुझे आपकी टिप्पणी अच्छी लगी। यह देखने में काफी अच्छा कोण है - ऐसी स्थितियां ज्यादातर "इफ्स" में उपयोग की जाती हैं और हमेशा बाहरी कोष्ठक से घिरी रहती हैं। तो, हाँ, यह वास्तव में एक खुश मसख़रा वास्तव में है :)))
वेगनहंटर

तुम सच में इस एक के लिए जाने के लिए कोष्ठक के साथ प्यार में होने की जरूरत है ...
Bastien7

7

functionपूरी परियोजना में एक वैश्विक और उपयोग बनाएँ

इसे इस्तेमाल करे

function isExist(arg){
   try{
      return arg();
   }catch(e){
      return false;
   }
}

let obj={a:5,b:{c:5}};

console.log(isExist(()=>obj.b.c))
console.log(isExist(()=>obj.b.foo))
console.log(isExist(()=>obj.test.foo))

अगर हालत

if(isExist(()=>obj.test.foo)){
   ....
}

बहुत अच्छा काम करता है। सरल और कुशल
gbland777

6

एक सरल तरीका यह है:

try {
    alert(test.level1.level2.level3);
} catch(e) {
    alert("undefined");    // this is optional to put any output here
}

try/catchजब उच्च स्तर के किसी भी परीक्षण, test.level1 के रूप में ऐसी वस्तुओं के लिए मामलों पकड़ता, test.level1.level2 परिभाषित नहीं कर रहे हैं।


6

मैंने प्रॉक्सी का उपयोग करते हुए किसी का कोई उदाहरण नहीं देखा

तो मैं अपने साथ आ गया। इसके बारे में महान बात यह है कि आपको तारों को प्रक्षेपित करने की आवश्यकता नहीं है। आप वास्तव में एक चेन-सक्षम ऑब्जेक्ट फ़ंक्शन वापस कर सकते हैं और इसके साथ कुछ जादुई चीजें कर सकते हैं। तुम भी कार्यों को बुला सकते हैं और गहरी वस्तुओं की जांच के लिए सरणी अनुक्रमित प्राप्त कर सकते हैं

उपरोक्त कोड तुल्यकालिक सामान के लिए ठीक काम करता है। लेकिन आप इस अजाक्स कॉल जैसी अतुल्यकालिक चीज़ का परीक्षण कैसे करेंगे? आप उसे कैसे परखेंगे? यदि यह 500 http त्रुटि लौटाता है तो क्या प्रतिक्रिया नहीं है?

window.fetch('https://httpbin.org/get')
.then(function(response) {
  return response.json()
})
.then(function(json) {
  console.log(json.headers['User-Agent'])
})

सुनिश्चित करें कि आप कुछ कॉलबैक से छुटकारा पाने के लिए async / प्रतीक्षा का उपयोग कर सकते हैं। लेकिन क्या होगा अगर आप इसे और भी जादुई तरीके से कर सकते हैं? कुछ इस तरह दिखता है:

fetch('https://httpbin.org/get').json().headers['User-Agent']

आपको शायद आश्चर्य है कि सभी वादे और .thenश्रृंखलाएं कहां हैं ... यह उन सभी के लिए अवरुद्ध हो सकता है जो आप जानते हैं ... लेकिन वादे के साथ एक ही प्रॉक्सी तकनीक का उपयोग करके आप वास्तव में कभी भी एक फ़ंक्शन लिखे बिना इसके अस्तित्व के लिए गहरी नेस्टेड जटिल पथ का परीक्षण कर सकते हैं।


अगर किसी को दिलचस्पी है, तो मैंने npm
अंतहीन

5

इस जवाब के आधार पर , मैं इस जेनेरिक फ़ंक्शन के साथ आया, ES2015जिसके उपयोग से समस्या का समाधान होगा

function validChain( object, ...keys ) {
    return keys.reduce( ( a, b ) => ( a || { } )[ b ], object ) !== undefined;
}

var test = {
  first: {
    second: {
        third: "This is not the key your are looking for"
    }
  }
}

if ( validChain( test, "first", "second", "third" ) ) {
    console.log( test.first.second.third );
}

1
यहाँ मेरा अंतिम दृष्टिकोण हैfunction validChain (object, path) { return path.split('.').reduce((a, b) => (a || { })[b], object) !== undefined }
जेम्स हैरिंगटन

5

नेस्टेड ऑब्जेक्ट प्रॉपर्टी को सुरक्षित रूप से प्राप्त करने के लिए मैंने एक छोटा सा फंक्शन बनाया है।

function getValue(object, path, fallback, fallbackOnFalsy) {
    if (!object || !path) {
        return fallback;
    }

    // Reduces object properties to the deepest property in the path argument.
    return path.split('.').reduce((object, property) => {
       if (object && typeof object !== 'string' && object.hasOwnProperty(property)) {
            // The property is found but it may be falsy.
            // If fallback is active for falsy values, the fallback is returned, otherwise the property value.
            return !object[property] && fallbackOnFalsy ? fallback : object[property];
        } else {
            // Returns the fallback if current chain link does not exist or it does not contain the property.
            return fallback;
        }
    }, object);
}

या एक सरल लेकिन थोड़ा अपठनीय संस्करण:

function getValue(o, path, fb, fbFalsy) {
   if(!o || !path) return fb;
   return path.split('.').reduce((o, p) => o && typeof o !== 'string' && o.hasOwnProperty(p) ? !o[p] && fbFalsy ? fb : o[p] : fb, o);
}

या उससे भी छोटा लेकिन झूठा झंडा लगाने के बिना:

function getValue(o, path, fb) {
   if(!o || !path) return fb;
   return path.split('.').reduce((o, p) => o && typeof o !== 'string' && o.hasOwnProperty(p) ? o[p] : fb, o);
}

मेरे पास परीक्षण है:

const obj = {
    c: {
        a: 2,
        b: {
            c: [1, 2, 3, {a: 15, b: 10}, 15]
        },
        c: undefined,
        d: null
    },
    d: ''
}

और यहाँ कुछ परीक्षण हैं:

// null
console.log(getValue(obj, 'c.d', 'fallback'));

// array
console.log(getValue(obj, 'c.b.c', 'fallback'));

// array index 2
console.log(getValue(obj, 'c.b.c.2', 'fallback'));

// no index => fallback
console.log(getValue(obj, 'c.b.c.10', 'fallback'));

प्रलेखन के साथ सभी कोड देखने के लिए और मैंने जिन परीक्षणों की कोशिश की है, आप मेरे github gist की जांच कर सकते हैं: https://gist.github.com/vsambor/3df9ad75ff3de489bbcb7b8c60beebf4#file-javascriptgetnestedvalues-js


4

@ CMS के उत्कृष्ट उत्तर का एक छोटा, ES5 संस्करण:

// Check the obj has the keys in the order mentioned. Used for checking JSON results.  
var checkObjHasKeys = function(obj, keys) {
  var success = true;
  keys.forEach( function(key) {
    if ( ! obj.hasOwnProperty(key)) {
      success = false;
    }
    obj = obj[key];
  })
  return success;
}

एक समान परीक्षण के साथ:

var test = { level1:{level2:{level3:'result'}}};
utils.checkObjHasKeys(test, ['level1', 'level2', 'level3']); // true
utils.checkObjHasKeys(test, ['level1', 'level2', 'foo']); // false

इसके साथ एकमात्र मुद्दा यह है कि यदि अपरिभाषित कुंजियों के कई स्तर हैं, तो आपको एक टाइपर्रर मिलता है, जैसेcheckObjHasKeys(test, ['level1', 'level2', 'asdf', 'asdf']);
जेकेएस

1
एक अधिक उपयुक्त तरीका हर है , जिसका मूल्य सीधे लौटाया जा सकता है।
रॉबग ऑग

शायद बदल success = false;जाए return false। आपको पता होना चाहिए कि एक बार जब आप इसे तोड़ देते हैं, तो इसे शून्य या अपरिभाषित होने के बाद कुछ भी गहरा नहीं हो सकता है। यह गहरी नेस्टेड वस्तुओं पर त्रुटियों को रोक देगा, क्योंकि वे स्पष्ट रूप से मौजूद नहीं हैं।
वेड

4

मुझे लगता है कि यह एक मामूली सुधार है (1-लाइनर बन जाता है):

   alert( test.level1 && test.level1.level2 && test.level1.level2.level3 )

यह काम करता है क्योंकि && ऑपरेटर अंतिम मूल्यांकन का मूल्यांकन करता है (और यह शॉर्ट-सर्किट)।


4

यदि संपत्ति मौजूद है, तो मुझे लौटाए जाने वाले मूल्य की तलाश थी, इसलिए मैंने सीएमएस द्वारा उत्तर को संशोधित किया। यहाँ मैं क्या लेकर आया हूँ:

function getNestedProperty(obj, key) {
  // Get property array from key string
  var properties = key.split(".");

  // Iterate through properties, returning undefined if object is null or property doesn't exist
  for (var i = 0; i < properties.length; i++) {
    if (!obj || !obj.hasOwnProperty(properties[i])) {
      return;
    }
    obj = obj[properties[i]];
  }

  // Nested property found, so return the value
  return obj;
}


Usage:

getNestedProperty(test, "level1.level2.level3") // "level3"
getNestedProperty(test, "level1.level2.foo") // undefined


3

सीएमएस द्वारा दिया गया उत्तर, नल चेक के लिए निम्नलिखित संशोधन के साथ ठीक काम करता है

function checkNested(obj /*, level1, level2, ... levelN*/) 
      {
             var args = Array.prototype.slice.call(arguments),
             obj = args.shift();

            for (var i = 0; i < args.length; i++) 
            {
                if (obj == null || !obj.hasOwnProperty(args[i]) ) 
                {
                    return false;
                }
                obj = obj[args[i]];
            }
            return true;
    }

3

निम्नलिखित विकल्पों को इस उत्तर से शुरू किया गया था । दोनों के लिए एक ही पेड़:

var o = { a: { b: { c: 1 } } };

अपरिभाषित होने पर खोजना बंद करें

var u = undefined;
o.a ? o.a.b ? o.a.b.c : u : u // 1
o.x ? o.x.y ? o.x.y.z : u : u // undefined
(o = o.a) ? (o = o.b) ? o.c : u : u // 1

एक-एक करके प्रत्येक स्तर को सुनिश्चित करें

var $ = function (empty) {
    return function (node) {
        return node || empty;
    };
}({});

$($(o.a).b).c // 1
$($(o.x).y).z // undefined

3

मुझे पता है कि यह सवाल पुराना है, लेकिन मैं इसे सभी वस्तुओं में जोड़कर एक विस्तार की पेशकश करना चाहता था। मुझे पता है कि लोग विस्तारित ऑब्जेक्ट कार्यक्षमता के लिए ऑब्जेक्ट प्रोटोटाइप का उपयोग करने के लिए डूब जाते हैं, लेकिन मुझे ऐसा करने से कुछ भी आसान नहीं लगता है। इसके अलावा, यह अब Object.defineProperty विधि के साथ अनुमत है।

Object.defineProperty( Object.prototype, "has", { value: function( needle ) {
    var obj = this;
    var needles = needle.split( "." );
    for( var i = 0; i<needles.length; i++ ) {
        if( !obj.hasOwnProperty(needles[i])) {
            return false;
        }
        obj = obj[needles[i]];
    }
    return true;
}});

अब, किसी भी वस्तु में किसी भी संपत्ति के लिए परीक्षण करने के लिए आप बस कर सकते हैं:

if( obj.has("some.deep.nested.object.somewhere") )

यहाँ इसका परीक्षण करने के लिए एक jsfiddle है, और विशेष रूप से इसमें कुछ jQuery शामिल हैं जो कि अगर आप संपत्ति को enumerable बनने के कारण Object.prototype को सीधे संशोधित करते हैं तो टूट जाता है। यह 3 पार्टी पुस्तकालयों के साथ ठीक काम करना चाहिए।


3

यह सभी वस्तुओं और सरणियों के साथ काम करता है :)

उदाहरण के लिए:

if( obj._has( "something.['deep']['under'][1][0].item" ) ) {
    //do something
}

यह मेरे ब्रायन के उत्तर का उन्नत संस्करण है

मैंने संपत्ति के नाम के रूप में _हास का इस्तेमाल किया क्योंकि यह मौजूदा संपत्ति के साथ संघर्ष कर सकता है (उदा: नक्शे)

Object.defineProperty( Object.prototype, "_has", { value: function( needle ) {
var obj = this;
var needles = needle.split( "." );
var needles_full=[];
var needles_square;
for( var i = 0; i<needles.length; i++ ) {
    needles_square = needles[i].split( "[" );
    if(needles_square.length>1){
        for( var j = 0; j<needles_square.length; j++ ) {
            if(needles_square[j].length){
                needles_full.push(needles_square[j]);
            }
        }
    }else{
        needles_full.push(needles[i]);
    }
}
for( var i = 0; i<needles_full.length; i++ ) {
    var res = needles_full[i].match(/^((\d+)|"(.+)"|'(.+)')\]$/);
    if (res != null) {
        for (var j = 0; j < res.length; j++) {
            if (res[j] != undefined) {
                needles_full[i] = res[j];
            }
        }
    }

    if( typeof obj[needles_full[i]]=='undefined') {
        return false;
    }
    obj = obj[needles_full[i]];
}
return true;
}});

यहाँ की बेला है


3

यहाँ मेरा इस पर ले लो - इन समाधानों में से अधिकांश नेस्टेड सरणी के मामले को अनदेखा करते हैं:

    obj = {
        "l1":"something",
        "l2":[{k:0},{k:1}],
        "l3":{
            "subL":"hello"
        }
    }

मैं जाँच करना चाहता हूँ obj.l2[0].k

नीचे दिए गए फ़ंक्शन के साथ, आप कर सकते हैं deeptest('l2[0].k',obj)

यदि वस्तु मौजूद है तो फ़ंक्शन सही वापस आएगा, अन्यथा गलत

function deeptest(keyPath, testObj) {
    var obj;

    keyPath = keyPath.split('.')
    var cKey = keyPath.shift();

    function get(pObj, pKey) {
        var bracketStart, bracketEnd, o;

        bracketStart = pKey.indexOf("[");
        if (bracketStart > -1) { //check for nested arrays
            bracketEnd = pKey.indexOf("]");
            var arrIndex = pKey.substr(bracketStart + 1, bracketEnd - bracketStart - 1);
            pKey = pKey.substr(0, bracketStart);
			var n = pObj[pKey];
            o = n? n[arrIndex] : undefined;

        } else {
            o = pObj[pKey];
        }
        return o;
    }

    obj = get(testObj, cKey);
    while (obj && keyPath.length) {
        obj = get(obj, keyPath.shift());
    }
    return typeof(obj) !== 'undefined';
}

var obj = {
    "l1":"level1",
    "arr1":[
        {"k":0},
        {"k":1},
        {"k":2}
    ],
    "sub": {
       	"a":"letter A",
        "b":"letter B"
    }
};
console.log("l1: " + deeptest("l1",obj));
console.log("arr1[0]: " + deeptest("arr1[0]",obj));
console.log("arr1[1].k: " + deeptest("arr1[1].k",obj));
console.log("arr1[1].j: " + deeptest("arr1[1].j",obj));
console.log("arr1[3]: " + deeptest("arr1[3]",obj));
console.log("arr2: " + deeptest("arr2",obj));


3

अब हम reduceनेस्टेड कुंजियों के माध्यम से लूप का उपयोग कर सकते हैं :

// @params o<object>
// @params path<string> expects 'obj.prop1.prop2.prop3'
// returns: obj[path] value or 'false' if prop doesn't exist

const objPropIfExists = o => path => {
  const levels = path.split('.');
  const res = (levels.length > 0) 
    ? levels.reduce((a, c) => a[c] || 0, o)
    : o[path];
  return (!!res) ? res : false
}

const obj = {
  name: 'Name',
  sys: { country: 'AU' },
  main: { temp: '34', temp_min: '13' },
  visibility: '35%'
}

const exists = objPropIfExists(obj)('main.temp')
const doesntExist = objPropIfExists(obj)('main.temp.foo.bar.baz')

console.log(exists, doesntExist)


3

आप इसे पुनरावर्ती फ़ंक्शन का उपयोग करके कर सकते हैं। यह तब भी काम करेगा जब आप सभी नेस्टेड ऑब्जेक्ट कुंजी नाम नहीं जानते हैं।

function FetchKeys(obj) {
    let objKeys = [];
    let keyValues = Object.entries(obj);
    for (let i in keyValues) {
        objKeys.push(keyValues[i][0]);
        if (typeof keyValues[i][1] == "object") {
            var keys = FetchKeys(keyValues[i][1])
            objKeys = objKeys.concat(keys);
        }
    }
    return objKeys;
}

let test = { level1: { level2: { level3: "level3" } } };
let keyToCheck = "level2";
let keys = FetchKeys(test); //Will return an array of Keys

if (keys.indexOf(keyToCheck) != -1) {
    //Key Exists logic;
}
else {
    //Key Not Found logic;
}

2

थेरोडोड (safeRead) पर यहाँ एक फंक्शन आयोजित किया गया है जो सुरक्षित तरीके से ऐसा करेगा ... अर्थात

safeRead(test, 'level1', 'level2', 'level3');

यदि कोई संपत्ति अशक्त या अपरिभाषित है, तो एक खाली स्ट्रिंग लौटा दी जाती है


मुझे यह तरीका पसंद है क्योंकि यह
टेंपलेटिंग के

2

पिछली टिप्पणी के आधार पर , यहां एक और संस्करण है जहां मुख्य वस्तु को परिभाषित नहीं किया जा सकता है:

// Supposing that our property is at first.second.third.property:
var property = (((typeof first !== 'undefined' ? first : {}).second || {}).third || {}).property;

2

मैंने अपना स्वयं का फ़ंक्शन लिखा है जो वांछित पथ लेता है, और एक अच्छा और बुरा कॉलबैक फ़ंक्शन है।

function checkForPathInObject(object, path, callbackGood, callbackBad){
    var pathParts = path.split(".");
    var currentObjectPath = object;

    // Test every step to see if it exists in object
    for(var i=0; i<(pathParts.length); i++){
        var currentPathPart = pathParts[i];
        if(!currentObjectPath.hasOwnProperty(pathParts[i])){
            if(callbackBad){
                callbackBad();
            }
            return false;
        } else {
            currentObjectPath = currentObjectPath[pathParts[i]];
        }
    }

    // call full path in callback
    callbackGood();
}

उपयोग:

var testObject = {
    level1:{
        level2:{
            level3:{
            }
        }
    }
};


checkForPathInObject(testObject, "level1.level2.level3", function(){alert("good!")}, function(){alert("bad!")}); // good

checkForPathInObject(testObject, "level1.level2.level3.levelNotThere", function(){alert("good!")}, function(){alert("bad!")}); //bad

हालाँकि मैं आपको अपने कोड को अपने उत्तर में
davewoodhall

2
//Just in case is not supported or not included by your framework
//***************************************************
Array.prototype.some = function(fn, thisObj) {
  var scope = thisObj || window;
  for ( var i=0, j=this.length; i < j; ++i ) {
    if ( fn.call(scope, this[i], i, this) ) {
      return true;
    }
  }
  return false;
};
//****************************************************

function isSet (object, string) {
  if (!object) return false;
  var childs = string.split('.');
  if (childs.length > 0 ) {
    return !childs.some(function (item) {
      if (item in object) {
        object = object[item]; 
        return false;
      } else return true;
    });
  } else if (string in object) { 
    return true;
  } else return false;
}

var object = {
  data: {
    item: {
      sub_item: {
        bla: {
          here : {
            iam: true
          }
        }
      }
    }
  }
};

console.log(isSet(object,'data.item')); // true
console.log(isSet(object,'x')); // false
console.log(isSet(object,'data.sub_item')); // false
console.log(isSet(object,'data.item')); // true
console.log(isSet(object,'data.item.sub_item.bla.here.iam')); // true
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.