কীভাবে 'অপরিজ্ঞাত সম্পত্তি পড়া যায় না' এড়ানো যায়?


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
আমি বুঝতে পারি যে কেউ কেন সমস্ত কিছু ক্র্যাশ করতে ত্রুটি চায় না। আপনি সর্বদা কোনও অস্তিত্বের অস্তিত্ব বা অস্তিত্বের বৈশিষ্ট্যের উপর নির্ভর করতে পারবেন না। যদি আপনার এমন জায়গায় কিছু থাকে যা এই ইভেন্টটি পরিচালনা করতে পারে যে বস্তুটি ত্রুটিযুক্ত, তবে আপনার কোডটি অনেক বেশি দক্ষ এবং কম ভঙ্গুর।
এসএসএইচ এই

3
বাস্তব জীবনের পরিস্থিতিতে কতগুলি অবজেক্ট / অ্যারেগুলি
ত্রুটিযুক্ত

উত্তর:


120

আপডেট :

  • আপনি যদি ইসিএমএসক্রিপ্ট 2020 বা তার পরেও জাভাস্ক্রিপ্ট ব্যবহার করেন তবে alচ্ছিক শৃঙ্খলা দেখুন
  • টাইপসক্রিপ্ট সংস্করণে alচ্ছিক চেইনের জন্য সমর্থন যোগ করেছে 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)কারণ এটি 0 0 বা এমনকি "0" হলেও মিথ্যা ফিরে আসবে। পরিবর্তে পরীক্ষা করুন কিনাa.b !== undefined


1
আপনার প্রথম সম্পাদনার ক্ষেত্রে: এটি ন্যায়সঙ্গত; আমি তাদেরকে JSON গঠিত ডাটাবেসের এন্ট্রি সঙ্গে তার আচরণ করছি, এই ধরনের যে বস্তু ক্ষেত্র একাধিক মাত্রা আকার পরিবর্তন হবে (অর্থাত entries.users.messages.date ইত্যাদি, ডাটা আছে যেখানে সব ক্ষেত্রেই প্রবেশ।)
আরি

"যদি 0 টি হয় তবে এটি সত্য হবে" - না। typeof a.b === "undefined" && a.b!=null- প্রথমটির পরে দ্বিতীয় অংশটি করা অপ্রয়োজনীয় এবং এটি করা আরও বেশি if ("b" in a)
ইয়ান

@ ইয়ে হ্যাঁ, আমি স্পষ্টতই বোঝাতে চাইছিলাম অন্য উপায়ে, এটি "0" হলেও মিথ্যা ফিরে আসবে। দুর্দান্ত ক্যাচ
বেনজমিন গ্রুয়েনবাউম

@ বেনজামিন গ্রুয়েনবাউম ভাল লাগছে, নিশ্চিত ছিল না যে আপনি এটি বোঝাতে চাইছেন কিনা। এছাড়াও, আমি মনে করি আপনি typeof a.b !== "অপরিজ্ঞাত" && ab = = নাল - চান!==
ইয়ান

3
আপনি যদি ab&&bc&& console.log (abc) এর টেডিয়াম না চান তবে অবিচ্ছিন্নভাবে অবিচ্ছিন্নভাবে লগ করার একমাত্র উপায় এটি।
ব্রায়ান ক্রে

14

যদি আমি আপনার প্রশ্নটি সঠিকভাবে বুঝতে পারি তবে আপনি কোনও বস্তুর কোনও সম্পত্তি রয়েছে কিনা তা নির্ধারণের সবচেয়ে নিরাপদ উপায় চান want

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');
53

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

আমি ধর্মীয়ভাবে অপ্রয়োজনীয় ব্যবহার করি । এটি প্রতিটি স্তরের নীচে আপনার অবজেক্টে পরীক্ষা করে যতক্ষণ না হয় এটির জন্য যা আপনি জিজ্ঞাসা করা মানটি পায় বা এটি "অপরিজ্ঞাত" ফিরে আসে। কিন্তু কখনও ত্রুটি।


2
এটি লোডাসের মতো_.get
ফিলাইপ

ভাল চিৎকার! এখনও আপনার যদি লোডাসের অন্যান্য বৈশিষ্ট্যগুলির প্রয়োজন না হয় তবে দরকারী।
মার্চইনওয়ার্ডে

4

আপনি যদি ব্যাবেল ব্যবহার করেন তবে আপনি ইতিমধ্যে @ বাবেল / প্লাগইন-প্রস্তাব-alচ্ছিক-শাইনিং বাবেল প্লাগইন সহ alচ্ছিক চেইন সিনট্যাক্স ব্যবহার করতে পারেন । এটি আপনাকে এটি প্রতিস্থাপন করতে অনুমতি দেবে:

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

এর সাথে:

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

3

আমি কও শিউগাংয়ের উত্তরটি পছন্দ করি তবে প্রতিবার কল করার পরে getSafe ফাংশনে প্যারামিটার হিসাবে কোনও ফাংশনটি পাস করার আমি পছন্দ করি না। সহজ পরামিতি এবং খাঁটি 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)। Chrome এবং ফায়ারফক্সের সর্বশেষতম সংস্করণ চেষ্টা করা হয়েছে।
রিকার্ড ইলিমি

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, "চমৎকার") দিয়ে কাজ করে না। কেউ ব্যাখ্যা করল কেন?
Cao Shouguang

2

লোড্যাশের একটি getপদ্ধতি রয়েছে যা নীচে দেখানো হিসাবে default চ্ছিক তৃতীয় প্যারামিটার হিসাবে ডিফল্টর জন্য অনুমতি দেয়:

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. গণনামূলক প্রসঙ্গটি কোনও ফাংশন প্রয়োগের আগে একটি নাল চেক।

একটি নিষ্পাপ বাস্তবায়ন এইরকম দেখাবে:

Implementation এই বাস্তবায়ন কেবল উদাহরণের জন্য! এটি কীভাবে করা উচিত তা নয় এবং এটি বহু স্তরেও ভুল। তবে এটির আমি আপনাকে কী বলছি তার একটি ভাল ধারণা দেওয়া উচিত।

আপনি দেখতে পাচ্ছেন কিছুই ভাঙ্গতে পারে না:

  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)

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.