How to avoid "Cannot read Property ... of Undefined" error?

Asked

Viewed 15,150 times

10

Considering the following code:

var a = {};

if (a.b.c !== undefined) {
  console.log("definido!");
} else {
  console.log("indefinido!");
}

Is there any way to check each property without having to test one by one?

What I want is the result of a if similar to the following, but simplified:

var a = {};

if (a !== undefined && a.b !== undefined && a.b.c !== undefined) {
  console.log("definido!");
} else {
  console.log("indefinido!");
}

5 answers

11


Don’t like this solution too much, but can capture the exception that will be generated because of the error:

var a = {};

try {
    console.log(a.b.c);
} catch (e) {
    console.log("indefinido");
}

I put in the Github for future reference.

If you just want to simplify without deleting the individual check you can take advantage of the short-Circuit, if it is only nesting of complex objects, if any of the nested members checked are scalars can give false negative:

var a = {};

if (a && a.b && a.b.c) {
    console.log("definido!");
} else {
    console.log("indefinido!");
}

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

if (a && a.b && a.b.c) {
    console.log("definido!");
} else {
    console.log("indefinido!");
}

I put in the Github for future reference.

You can also create an abstraction. You can create a function or use a prompt that does the heavy lifting.

There’s a few more possibilities, but it’s too much gambit.

  • 1

    Problem of the second approach is that if the value of a, a.b or a.b.c for false, 0 or empty string the output will be undefined

  • @jbueno is true, I made the reservation

  • bigown and @jbueno I know it runs a little bit from the question, but you think that thus it gets really bad?

  • @Sorack can’t tell if it’s abuse of Object.prototype because I have little experience with JS, I don’t think so. It seems to me that in this case could eliminate the exception capture and verify each property and is undefined. Not that I’m wrong, but I hate to use exception to solve problems that can be solved with a better mechanism. I don’t like the syntax. I would encapsulate one of the two solutions I passed you in a simple function (the first works in all cases)

  • @bigown got it, I made a change to not need to avail myself of the exception. Value anyway, in case you’re curious thus. I used recursion to get the result

10

I ended up using the information of the 3 responses proposed so far. Reading the answer from @Linq I saw that the name of the resource is null Propagation and that, although it does not exist in Javascript, has great chances to be implemented in the near future.

On the basis of the above, I took into account the reply of @Robertofagundes and I decided to use a function for that.

Seeing the @Maniero response I used the concepts he presented and arrived at the following temporary resolution (until implementing in Javascript):

Object.prototype.hasProperty = function(signature) {
  var finalProperty = this;
  var property;
  var child;

  if (signature === undefined) {
    return true;
  }

  if (signature instanceof String) {
    signature = signature.split('.');
  }

  if (signature.constructor !== Array) {
    signature = [signature];
  }

  if (signature.length === 0) {
    return true;
  }

  property = signature.shift();
  child = this[property]; 

  if (child === undefined) {
    return false;
  } else {
    return child.hasProperty(signature);
  }
}

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

if (a.hasProperty(['b', 'c'])) {
  console.log("definido!");
} else {
  console.log("indefinido!");
}

9

The name of this resource is null Propagation and this does not exist in Javascript.

You can use the lodash to do something similar. It has a function called get, that takes as parameter the object, the properties you want to access and the value default for the return, if the specified properties cannot be found.

// Exemplo onde a propriedade não existe

var a = {};
var result = _.get(a, 'b.c', 'Indefinido');
console.log(result);

// Exemplo onde a propriedade existe

var obj = { innerObj: { innerObj1: 'Teste' } };
var valor = _.get(obj, 'innerObj.innerObj1', 'Indefinido');
console.log(valor);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

  • thanks for naming the resource. Knowing the name I could see that there is a discussion so that you have a resource for what I am wanting in ES7.

  • Yes, I saw this a few days ago, too, but I couldn’t find relevant information from reliable sources, so I thought it best not to quote.

  • Now you have the feature. They called it "optional chaining".

5

You can use a recursive function to perform this work in this way:

function verificarArrayUnsigned(array){
  var isUnsigned = false;
  if (typeof array !== "unsigned"){
    for (var i = 0; i < array.length; i++){
      if (typeof array[i] === "array"){
        isUnsigned = verificarArrayUnsigned(array[i]);
      } else {
        if (typeof array[i] === "unsigned"){
          isUnsigned = true;
        }
      }
      if (isUnsigned){
        break;
      }
    }
  } else {
    isUnsigned = true;
  }
  
  return isUnsigned;
}

In this function you can pass both an array and a variable.

3

The TypeError message "Cannot read Property ... of Undefined" is launched when trying to access a property at some value of the type undefined or null.

The other answers to this question indicate several tricks to solve error problem in chained accesses.

From Ecmascript 2020, you can use the syntax of optional chaining, short-circuiting the expression for undefined as soon as ownership access to null or undefined is effective. By using the ?. instead of . for access, the error in question is not.

Example:

const obj = {
  super: {
    nested: {
      prop: 'Value'
    }
  }
};

if (obj?.super?.nested?.prop) {
  console.log('`obj.super.nested.prop` existe.');
}

// Note o operador lógico NOT (verifica que não existe)
//  ↓
if (!obj?.super?.nested?.undefinedProp) {
  console.log('`obj.super.nested.undefinedProp` NÃO existe.');
}

I will not dwell on the syntax much, since this matter has already been dealt with in this other answer. Also has the documentation.

  • At the time I asked the question there was still optional chaining in JS (it is even cited in some of the answers). I gave a +1 for making the question more complete! Thank you!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.