कैसे बचें 'अपरिभाषित' त्रुटियों की संपत्ति नहीं पढ़ सकते हैं?


118

मेरे कोड में, मैं एक ऐसी सरणी से निपटता हूं जिसमें कुछ वस्तुओं के साथ कुछ प्रविष्टियां होती हैं जो एक दूसरे के अंदर होती हैं, जहां कुछ नहीं होती हैं। यह कुछ इस तरह दिखता है:

// where this array is hundreds of entries long, with a mix
// of the two examples given
var test = [{'a':{'b':{'c':"foo"}}}, {'a': "bar"}];

यह मुझे समस्याएं दे रहा है क्योंकि मुझे कई बार सरणी के माध्यम से पुनरावृति करने की आवश्यकता है, और असंगति मुझे त्रुटियों को फेंक रही है जैसे:

for (i=0; i<test.length; i++) {
    // ok on i==0, but 'cannot read property of undefined' on i==1
    console.log(a.b.c);
}

मुझे पता है कि मैं कह सकता हूं if(a.b){ console.log(a.b.c)}, लेकिन यह उन मामलों में असाधारण रूप से थकाऊ है जहां 5 या 6 ऑब्जेक्ट्स एक-दूसरे से जुड़े हुए हैं। क्या कोई अन्य (आसान) तरीका है कि मैं इसे केवल कंसोल कर सकता हूं। यदि यह मौजूद है, लेकिन बिना किसी त्रुटि के?


3
त्रुटि शायद एक नियमित जावास्क्रिप्ट अपवाद है, इसलिए try..catchकथन का प्रयास करें । उस ने कहा, एक सरणी जिसमें बेतहाशा विषम तत्व होते हैं, मेरे लिए एक डिजाइन मुद्दा जैसा दिखता है।
मिलीमो

3
यदि आपकी संरचना वस्तुओं के अनुरूप नहीं है, तो अस्तित्व की जाँच में क्या गड़बड़ है? वास्तव में, मैं उपयोग करूंगा if ("b" in a && "c" in a.b)। यह "थकाऊ" हो सकता है, लेकिन यही आपको असंगतता के लिए मिलता है ... सामान्य तर्क।
इयान

2
आप गैर-मौजूदा गुणों का उपयोग क्यों करेंगे, आप यह नहीं जानते कि ऑब्जेक्ट कैसे दिखते हैं?
बेर्गी

9
मैं समझ सकता हूं कि कोई व्यक्ति सब कुछ क्रैश करने के लिए एक त्रुटि क्यों नहीं चाहेगा। आप हमेशा मौजूद या मौजूद नहीं होने के लिए किसी ऑब्जेक्ट के गुणों पर भरोसा नहीं कर सकते। यदि आपके पास कुछ ऐसा है जो इस घटना को संभाल सकता है कि ऑब्जेक्ट विकृत है, तो आप कोड बहुत अधिक कुशल और कम नाजुक हैं।
SSH यह

3
आपको आश्चर्य होगा कि वास्तविक जीवन स्थितियों में कितनी वस्तुएं / सरणियाँ विकृत होती हैं
OneMoreQuestion

जवाबों:


120

अपडेट :

  • यदि आप ECMAScript 2020 या बाद के अनुसार जावास्क्रिप्ट का उपयोग करते हैं, तो वैकल्पिक चैनिंग देखें ।
  • टाइपस्क्रिप्ट ने 3.7 संस्करण में वैकल्पिक चाइनिंग के लिए समर्थन जोड़ा है ।
// use it like this
obj?.a?.lot?.of?.properties

ECMASCript 2020 से पहले जावास्क्रिप्ट के लिए समाधान या संस्करण 3.7 से पुराने टाइपस्क्रिप्ट :

एक त्वरित समाधान ES6 तीर फ़ंक्शन के साथ एक कोशिश / कैच हेल्पर फ़ंक्शन का उपयोग कर रहा है :

function getSafe(fn, defaultVal) {
    try {
        return fn();
    } catch (e) {
        return defaultVal;
    }
}

// use it like this
getSafe(() => obj.a.lot.of.properties);

// or add an optional default value
getSafe(() => obj.a.lot.of.properties, 'nothing');

कार्य स्निपेट:

देखें इस लेख जानकारी के लिए।


2
मुझे यह पसंद है! केवल एक चीज जो मैं जोड़ूंगा वह है सांत्वना। पकड़ के अंदर, ताकि आप त्रुटि के बारे में जान सकें लेकिन यह जारी है।
रब्बी शुकी गुर

पुन: फेंकने के बिना सभी अपवादों को पकड़ना बुरा है , और आम तौर पर निष्पादन के अपेक्षित प्रवाह के हिस्से के रूप में अपवादों का उपयोग करना भी महान नहीं है - भले ही इस मामले में यह बहुत अच्छी तरह से निहित है।
ह्यूगो

50

आप जो कर रहे हैं वह एक अपवाद को बढ़ाता है (और ठीक ही तो)।

आप हमेशा कर सकते हैं

try{
   window.a.b.c
}catch(e){
   console.log("YO",e)
}

लेकिन मैं आपके उपयोग के मामले के बारे में नहीं सोचूंगा।

आप डेटा तक क्यों पहुँच रहे हैं, 6 स्तर नेस्टेड हैं कि आप अपरिचित हैं? क्या उपयोग मामला यह उचित है?

आमतौर पर, आप वास्तव में यह सत्यापित करना चाहेंगे कि आप किस प्रकार की वस्तु के साथ काम कर रहे हैं।

इसके अलावा, एक साइड नोट पर आपको कथनों का उपयोग नहीं करना चाहिए if(a.b)क्योंकि यह गलत है यदि ab 0 है या भले ही वह "0" है। इसके बजाय अगर जाँच करेंa.b !== undefined


1
आपके पहले संपादन के संबंध में: यह उचित है; मैं JSON संरचित डेटाबेस प्रविष्टियों के साथ काम कर रहा हूं, जैसे कि ऑब्जेक्ट कई स्तरों के फ़ील्ड्स (जैसे। प्रविष्टियाँ .users.messages.date आदि), जहाँ सभी मामलों में डेटा दर्ज नहीं हैं)
Ari

"यह सच है अगर एब 0 है" - नोप। typeof a.b === "undefined" && a.b!=null- पहले के बाद दूसरे भाग को करने के लिए अनावश्यक, और यह सिर्फ करने के लिए और अधिक समझ में आता हैif ("b" in a)
इयान

@ हाँ, मैं स्पष्ट रूप से इसका मतलब यह था कि यह चारों ओर है, अगर यह "0" है तो भी यह गलत होगा। नाइस पकड़
बेंजामिन Gruenbaum

@BenjaminGruenbaum अच्छा लगता है, अगर आपको लगता है कि यह निश्चित नहीं था। इसके अलावा, मुझे लगता है कि आप चाहते हैं typeof a.b !== "अपरिभाषित" && ab! = Null` - ध्यान दें!==
इयान

3
यदि आप ab && abc && कंसोल.log (abc) के tedium नहीं करना चाहते हैं तो यह अज्ञात लॉग को लगातार लॉग करने का एकमात्र तरीका है।
ब्रायन क्रे

14

यदि मैं आपके प्रश्न को सही ढंग से समझ रहा हूं, तो आप यह निर्धारित करना चाहते हैं कि किसी वस्तु में कोई संपत्ति है या नहीं।

सबसे आसान तरीका inऑपरेटर का उपयोग करना है

window.a = "aString";
//window should have 'a' property
//lets test if it exists
if ("a" in window){
    //true
 }

if ("b" in window){
     //false
 }

बेशक आप इसे जितना चाहें उतना घोंसला बना सकते हैं

if ("a" in window.b.c) { }

यकीन नहीं होता अगर यह मदद करता है।


9
आप इसे सुरक्षित रूप से जितना चाहें उतना घोंसला नहीं दे सकते। यदि window.bअपरिभाषित हो तो क्या होगा ? आपको एक प्रकार की त्रुटि मिलेगी:Cannot use 'in' operator to search for 'c' in undefined
ट्रेवर

13

यदि आप लॉश का उपयोग कर रहे हैं , तो आप उनके "है" फ़ंक्शन का उपयोग कर सकते हैं। यह मूल "में" के समान है, लेकिन पथ की अनुमति देता है।

var testObject = {a: {b: {c: 'walrus'}}};
if(_.has(testObject, 'a.b.c')) {
  //Safely access your walrus here
}

2
सबसे अच्छा, हम _.get()आसानी से पढ़ने के लिए डिफ़ॉल्ट रूप से उपयोग कर सकते हैं:_.get(object, 'a.b.c', 'default');
Ifnot

12

इसे इस्तेमाल करे। यदि a.bअपरिभाषित है, तो यह ifबिना किसी अपवाद के कथन को छोड़ देगा ।

if (a.b && a.b.c) {
  console.log(a.b.c);
}

5

गहरी या जटिल जोंस ऑब्जेक्ट के साथ काम करते समय यह एक सामान्य मुद्दा है, इसलिए मैं कई चेक को ट्राई / पकड़ने या एम्बेड करने से बचने की कोशिश करता हूं जो कोड को अपठनीय बना देगा, मैं आमतौर पर काम करने के लिए अपने सभी प्रॉसीक में कोड के इस छोटे से टुकड़े का उपयोग करता हूं।

/* ex: getProperty(myObj,'aze.xyz',0) // return myObj.aze.xyz safely
 * accepts array for property names: 
 *     getProperty(myObj,['aze','xyz'],{value: null}) 
 */
function getProperty(obj, props, defaultValue) {
    var res, isvoid = function(x){return typeof x === "undefined" || x === null;}
    if(!isvoid(obj)){
        if(isvoid(props)) props = [];
        if(typeof props  === "string") props = props.trim().split(".");
        if(props.constructor === Array){
            res = props.length>1 ? getProperty(obj[props.shift()],props,defaultValue) : obj[props[0]];
        }
    }
    return typeof res === "undefined" ? defaultValue: res;
}


4

मैं धार्मिक रूप से undefsafe का उपयोग करता हूं । यह प्रत्येक स्तर तक आपकी वस्तु का परीक्षण करता है जब तक कि यह आपके द्वारा मांगे गए मूल्य को प्राप्त नहीं करता है, या यह "अपरिभाषित" देता है। लेकिन कभी त्रुटि नहीं हुई।


2
यह लताड़ के समान है_.get
फिल्प

अच्छा चिल्लाओ! अभी भी उपयोगी है अगर आपको अन्य सुविधाओं की ज़रूरत नहीं है।
14

4

यदि आप बैबल का उपयोग करते हैं, तो आप पहले से ही @ बैबल / प्लगइन-प्रपोजल-ऑप्शनल-चैनिंग बैबल प्लगइन के साथ वैकल्पिक चैनिंग सिंटैक्स का उपयोग कर सकते हैं । यह आपको इसे बदलने की अनुमति देगा:

console.log(a && a.b && a.b.c);

इसके साथ:

console.log(a?.b?.c);

3

मुझे काओ श्वेगंग का उत्तर पसंद है, लेकिन जब भी मैं कॉल करता हूं, मुझे एक फ़ंक्शन को गेटसेफ़ फ़ंक्शन में पैरामीटर के रूप में पारित करने का शौक नहीं होता है। मैंने सरल मापदंडों और शुद्ध ES5 को स्वीकार करने के लिए getSafe फ़ंक्शन को संशोधित किया है।

/**
* Safely get object properties.    
* @param {*} prop The property of the object to retrieve
* @param {*} defaultVal The value returned if the property value does not exist
* @returns If property of object exists it is returned, 
*          else the default value is returned.
* @example
* var myObj = {a : {b : 'c'} };
* var value;
* 
* value = getSafe(myObj.a.b,'No Value'); //returns c 
* value = getSafe(myObj.a.x,'No Value'); //returns 'No Value'
* 
* if (getSafe(myObj.a.x, false)){ 
*   console.log('Found')
* } else {
*  console.log('Not Found') 
* }; //logs 'Not Found'
* 
* if(value = getSafe(myObj.a.b, false)){
*  console.log('New Value is', value); //logs 'New Value is c'
* }
*/
function getSafe(prop, defaultVal) {
  return function(fn, defaultVal) {
    try {
      if (fn() === undefined) {
        return defaultVal;
      } else {
        return fn();
      }
    } catch (e) {
      return defaultVal;
    }
  }(function() {return prop}, defaultVal);
}

यह वास्तव में साथ काम नहीं करते getSafe(myObj.x.c)। क्रोम और फ़ायरफ़ॉक्स के नवीनतम संस्करणों की कोशिश की।
रिकार्ड एलिमै

2

यदि संपत्ति अपरिभाषित है, तो स्ट्रैट के उत्तर में, मान 'अपरिभाषित' सेट डिफ़ॉल्ट मान के बजाय वापस कर दिया जाएगा। यह कभी-कभी बग पैदा कर सकता है। निम्नलिखित सुनिश्चित करेगा कि डिफॉल्टवैल हमेशा वापस आ जाएगी जब या तो संपत्ति या ऑब्जेक्ट अपरिभाषित हो।

const temp = {};
console.log(getSafe(()=>temp.prop, '0'));

function getSafe(fn, defaultVal) {
    try {
        if (fn() === undefined) {
            return defaultVal
        } else {
            return fn();
        }

    } catch (e) {
        return defaultVal;
    }
}

मेरे कोड के हार्डी ले रॉक्स का उन्नत संस्करण myObj = {} getSafe () => myObj.ab, "अच्छा") के साथ काम नहीं करता है, जबकि मेरा काम करता है। कोई क्यों समझाता है?
काओ शौगंग

2

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

const myObject = {
  has: 'some',
  missing: {
    vars: true
  }
}
const path = 'missing.const.value';
const myValue = _.get(myObject, path, 'default');
console.log(myValue) // prints out default, which is specified above
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>


2

कल्पना करें कि हम कार्यों की एक श्रृंखला को लागू करना चाहते हैं xयदि और केवल अगर xगैर-अशक्त है:

if (x !== null) x = a(x);
if (x !== null) x = b(x);
if (x !== null) x = c(x);

अब कहते हैं कि हमें ऐसा करने की आवश्यकता है y:

if (y !== null) y = a(y);
if (y !== null) y = b(y);
if (y !== null) y = c(y);

और इसके समान z:

if (z !== null) z = a(z);
if (z !== null) z = b(z);
if (z !== null) z = c(z);

जैसा कि आप एक उचित अमूर्तता के बिना देख सकते हैं, हम बार-बार कोड को दोहराएंगे। ऐसा अमूर्त पहले से मौजूद है: शायद सन्यासी।

हो सकता है कि इकाई दोनों एक मूल्य और एक कम्प्यूटेशनल संदर्भ रखती है:

  1. मोनाड मूल्य को सुरक्षित रखता है और इस पर कार्य करता है।
  2. कम्प्यूटेशनल संदर्भ एक फ़ंक्शन लागू करने से पहले एक अशक्त जांच है।

एक भोली कार्यान्वयन इस तरह दिखेगा:

⚠️ यह कार्यान्वयन केवल दृष्टांत प्रयोजन के लिए है! यह नहीं है कि यह कैसे किया जाना चाहिए और कई स्तरों पर गलत है। हालाँकि इससे आपको एक बेहतर विचार मिल सकता है कि मैं किस बारे में बात कर रहा हूँ।

जैसा कि आप देख सकते हैं कि कुछ भी नहीं टूट सकता है:

  1. हम अपने मूल्य पर कार्यों की एक श्रृंखला लागू करते हैं
  2. यदि किसी भी बिंदु पर, मान शून्य (या अपरिभाषित) हो जाता है, तो हम अभी कोई फ़ंक्शन लागू नहीं करते हैं।

const abc = obj =>
  Maybe
    .of(obj)
    .map(o => o.a)
    .map(o => o.b)
    .map(o => o.c)
    .value;

const values = [
  {},
  {a: {}},
  {a: {b: {}}},
  {a: {b: {c: 42}}}
];

console.log(

  values.map(abc)

);
<script>
function Maybe(x) {
  this.value = x; //-> container for our value
}

Maybe.of = x => new Maybe(x);

Maybe.prototype.map = function (fn) {
  if (this.value == null) { //-> computational context
    return this;
  }
  return Maybe.of(fn(this.value));
};
</script>


परिशिष्ट 1

मैं यह नहीं समझा सकता कि यह कौन से भिक्षु हैं क्योंकि यह इस पद का उद्देश्य नहीं है और वहां के लोग मुझसे बेहतर हैं। हालांकि एरिक इलियट ने हिस्टरी ब्लॉग पोस्ट में कहा कि जावास्क्रिप्ट मोनड्स मेड सिंपल :

अपने कौशल स्तर या श्रेणी सिद्धांत की समझ के बावजूद, मठों का उपयोग करने से आपके कोड के साथ काम करना आसान हो जाता है। भिक्षुओं का लाभ उठाने में विफल रहने से आपका कोड कठिन हो सकता है (जैसे, कॉलबैक नरक, नेस्टेड सशर्त शाखाएं, अधिक वाचालता)।


परिशिष्ट 2

यहां बताया गया है कि शायद मैं आपकी समस्या को हल करूं से इकाई

const prop = key => obj => Maybe.fromNull(obj[key]);

const abc = obj =>
  Maybe
    .fromNull(obj)
    .flatMap(prop('a'))
    .flatMap(prop('b'))
    .flatMap(prop('c'))
    .orSome('🌯')
    
const values = [
  {},
  {a: {}},
  {a: {b: {}}},
  {a: {b: {c: 42}}}
];

console.log(

  values.map(abc)

);
<script src="https://www.unpkg.com/monet@0.9.0/dist/monet.js"></script>
<script>const {Maybe} = Monet;</script>


0

मैंने पहले इसका उत्तर दिया और आज एक समान जांच कर रहा हूं। यह जांचने के लिए एक सरलीकरण किया जाता है कि क्या नेस्टेड डॉटेड प्रॉपर्टी मौजूद है। आप अपने लक्ष्य को पूरा करने के लिए मूल्य, या कुछ डिफ़ॉल्ट लौटने के लिए इसे संशोधित कर सकते हैं।

function containsProperty(instance, propertyName) {
    // make an array of properties to walk through because propertyName can be nested
    // ex "test.test2.test.test"
    let walkArr = propertyName.indexOf('.') > 0 ? propertyName.split('.') : [propertyName];

    // walk the tree - if any property does not exist then return false
    for (let treeDepth = 0, maxDepth = walkArr.length; treeDepth < maxDepth; treeDepth++) {

        // property does not exist
        if (!Object.prototype.hasOwnProperty.call(instance, walkArr[treeDepth])) {
            return false;
        }

        // does it exist - reassign the leaf
        instance = instance[walkArr[treeDepth]];

    }

    // default
    return true;

}

आपके प्रश्न में आप कुछ ऐसा कर सकते हैं:

let test = [{'a':{'b':{'c':"foo"}}}, {'a': "bar"}];
containsProperty(test[0], 'a.b.c');


0

आप संपत्ति प्राप्त करने से पहले एक डिफ़ॉल्ट मान देकर त्रुटि से बच सकते हैं

var test = [{'a':{'b':{'c':"foo"}}}, {'a': "bar"}];

for (i=0; i<test.length; i++) {
    const obj = test[i]
    // No error, just undefined, which is ok
    console.log(((obj.a || {}).b || {}).c);
}

यह सरणियों के साथ भी बढ़िया काम करता है:

const entries = [{id: 1, name: 'Scarllet'}]
// Giving a default name when is empty
const name = (entries.find(v => v.id === 100) || []).name || 'no-name'
console.log(name)

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