5

I want to check if an object exists, and has a property. Currently I get a "myObject is undefined" error that stops the check.

How can I make the following still work correctly even when myObject may not exist?

if (myObject.myProperty) {
  ...
} else {
  ...
}

I am trying to just even check if a object / variable exists but getting an error:

if (foo) { console.log('hello'); } gives the error Uncaught ReferenceError: foo is not defined. Here is a jsfiddle http://jsfiddle.net/cfUss/

4 Answers 4

9

You can use the "short circuit" && operator:

if (myObject && myObject.myProperty) { 
    ...
}

If myObject is "falsey" (e.g. undefined) the && operator won't bother trying to evaluate the right-hand expression, thereby avoiding the attempt to reference a property of a non-existent object.

The variable myObject must have course already have been declared, the test above is for whether it has been assigned a defined value.

Sign up to request clarification or add additional context in comments.

4 Comments

Ok that's what I was trying and it's still failing... will paste a copy of the code
if (foo) { ... } gives the error Uncaught ReferenceError: foo is not defined
Looks like this only works if myObject is already declared but falsey... so I guess only if I had done var myObject; or var myObject = null;
@DonnyP yes, the variable does actually have to exist first. You should, of course, always define all of your variables. The only way around that is if (typeof myObject !== "undefined" && ...), since the typeof operator can't throw the foo is not defined error.
7

You can use the optional chaining operator ?. to keep things succinct:

if (myObject?.myProperty) { ... }

which is equal to the a bit more verbose

if (myObject && myObject.myProperty) { ... }

It comes in very handy especially for deeply nested objects.

It's currently (September 2019) a ECMAScript stage 3 proposal but things are looking promising that this feature will become officially available. For the time being, you can already start using it via the respective Babel plugin: https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining

Comments

1

Try:

if(myObject && myObject.myProperty){ ... }

This code enters the body of the if block if myObject exists and also has myproperty. If myObject doesn't exist for some reason, the && short-circuits and does not evaluated myObject.myProperty.

1 Comment

Like above, if you declare with variables with var you should be good to go.
1

I've been suprised not to find this helpful function in basic Javascipt interface.

Below is a helper function I often use in my projects. It checks if the value of the final chain element is reachable without an error "can't get ... of undefined". Use it this way:

getChained(this, "this.path.to.some.object.someFunction().result");

/**
 * Deconstructs a chain, checking if every other element is undefined. 
 * You can use arrays and functions in chain and even pass parameters
 * inside them.
 *
 * The only limitation is no string values with dots are allowed.
 *
 * @param {Object} chainScope Starting object, the chain scope.
 *                            Guaranteed not to be be undefined.
 *                            Required parameter.
 * @param {String} chain A chain from code without first object 
 *                       and without first dot.
 *                       Required parameter.
 * @param {Array<Array<Object||String||Number||Boolean||undefined>>}
 *        functionsParameters Parameters for functions in chain.
 *                            Object in the array correspond the order
 *                            of functions in chain. Every object
 *                            contains parameters for its function.
 *                            Object syntax forces us to create parameter 
 *                            names even if you only have its value.
 * @returns {Object||String||Number||Boolean||undefined} Final chain element value or undefined, if any other chain element returned undefined.
 */
getChained: function (
  chainScope,
  chain,
  functionsParameters) {

  var parts;
  var part;
  var partIndex;
  var target = undefined;
  var functionIndex = 0;

  if (
    chainScope === undefined ||
    chainScope === null) {

    return target;
  }

  target = chainScope; // The starting scope of a chain.

  parts = getParts();

  // Relay chain substituting calculated parts with values
  // for function calls and arrays:
  for (
    partIndex = 0;
    partIndex < parts.length;
    partIndex++) {

    if (target === undefined) {
      // Chain element is undefined and so is the chain itself:
      return undefined;
    }

    part = parts[partIndex];

    if (
      part.indexOf("(") >
      part.indexOf("\"") &&
      part.indexOf("(") >
      part.indexOf("\'")) {

      // It's a function:

      target = getFunctionValue();
      functionIndex++;
      continue;
    }

    if (
      part.indexOf("[") >
      part.indexOf("\"") &&
      part.indexOf("]") >
      part.indexOf("\'")) {

      // It's an array's element:

      target = getArrayValue();
      continue;
    }

    if (
      typeof part === "string" &&
      target !== null &&
      target !== undefined) {

      // It's an object:

      target = target[part];
      continue;
    }
  }

  return target;

  /**
   * Splits string. Separators are dots outside the brackets.
   * No splitting for dots inside the brackets.
   */
  function getParts() {

    var SEPARATOR = ".";
    var OPEN_CHARS = [
      "(",
      "[",
      "\"",
      "\'"
    ];
    var CLOSE_CHARS = [
      ")",
      "]",
      "\"",
      "\'"
    ];
    var SUB_SEPARATOR_OPEN = "[";
    var SUB_SEPARATOR_CLOSE = "]";

    return(
      splitBySubSeparator(
        splitBySeparator(
          chain)));

    /**
     * Split by chain root separator.
     * No splitting between opening and closing characters.
     *
     * @param {String} chainString Chain to analyse characters.
     * @returns {Array<String>} Chain elements splitted.
     */
    function splitBySeparator(chainString) {
      var parts = [
      ];
      var opened = 0;
      var char1;
      var chainIndex;
      var extract;
      var cutFromIndex = 0;
      var chainArray;

      // String to array and attach the ending dot 
      // to be able to split using common rule:
      chainArray =
        (chainString + ".").
        split("");

      for (
        chainIndex = 0;
        chainIndex < chainArray.length;
        chainIndex++) {

        char1 = chainArray[chainIndex];

        if (OPEN_CHARS.indexOf(char1) > 0) {
          // It's an opening bracket:
          opened++;
          continue;
        }

        if (CLOSE_CHARS.indexOf(char1) > 0) {
          // It's a closing bracket:
          opened--;
          continue;
        }

        if (opened === 0) {
          // It's character outside the brackets:
          if (char1 === SEPARATOR) {

            // It's a dot - everything before it is an element:

            extract =
              chainArray.slice(
                cutFromIndex,
                chainIndex). // Cut an element.
              join(""); // Array to String.

            parts.push(
              extract);

            cutFromIndex = chainIndex + 1; // Shift to escape a dot.
          } else {
            // It's an ordinary character:
            continue;
          }
        }
      }

      return parts;
    }

    /**
     * Splits by root subobject or array elements calls.
     * Subcalls are searched inside the splitted chain elements.
     * (now separator is "[" instead of ".").
     * Can split several consequently called subobjects
     * without a need to deconstruct enclosures.
     * Second iteration finds array elements and object subcalls
     * inside resulting elements (now separator is "[" instead of "."):
     */
    function splitBySubSeparator(parts) {
      var newParts = [
      ];
      var opened = 0;
      var char1;
      var partIndex;
      var chainIndex;
      var chainArray;

      for (
        partIndex = 0;
        partIndex < parts.length;
        partIndex++) {

        var part = parts[partIndex];

        chainArray = part.split("");

        for (
          chainIndex = 0;
          chainIndex < chainArray.length;
          chainIndex++) {

          char1 = chainArray[chainIndex];

          if (
            opened === 0 &&
            char1 === SUB_SEPARATOR_OPEN) {

            // Start of subcall for an array element or object:
            part =
              part.substr(0, chainIndex) +
              SEPARATOR +
              part.substr(chainIndex + 1);

            opened++;
          }

          if (
            opened > 0 &&
            char1 === SUB_SEPARATOR_CLOSE) {

            // End of subcall for an array element or object:
            part =
              part.substr(0, chainIndex) +
              "" +
              part.substr(chainIndex + 1);

            opened--;
          }
        }

        // Split changed element by separators again and 
        // relay into a cumulative array:
        newParts =
          newParts.concat(
            splitBySeparator(part));
      }

      return newParts;
    }
  }

  /**
   * Creates and returns method call result. Puts required
   * parameters into method.
   *
   * @returns {Object||String||Number||Boolean||undefined} Method execution result.
   */
  function getFunctionValue() {
    var value;
    var name;

    name =
      part.
      split("(")[0];

    if (functionsParameters) {
      value =
        target[name].
        apply(
          target,
          functionsParameters[
            functionIndex
          ]);
    } else {
      value =
        target[name].
        apply(
          target);
    }

    return value;
  }

  /**
   * Returns array element.
   *
   * @returns {Object||String||Number||Boolean||undefined} Value of array element.
   */
  function getArrayValue() {
    var value;
    var arrayName;
    var itemName;

    arrayName =
      part.
      split("[")[0];

    itemName =
      (part.
        split("[")[1].
        split("]")[0]).
      split("\'").
      join("").
      split("\"").
      join("");

    if (target[arrayName]) {
      value =
        target[arrayName][itemName];
    }

    return value;
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.