0

In javascript, is there a better way to get the value of a boolean property on an object, but default to true if the property doesn't exist, than below?

 (typeof myObj.myProp !== "undefined" ? myObj.myProp : true);

I feel there must be a better way of doing it.

Test cases...

 myObj = {}; // return true
 myObj = { myProp: false; } // return false;
 myObj = { myProp: true; } // return true
freefaller
  • 19,368
  • 7
  • 57
  • 87
  • 6
    `myObj.myProp ?? true` [Is there a "null coalescing" operator in JavaScript?](https://stackoverflow.com/q/476436) – VLAZ Nov 26 '21 at 14:31
  • `const item = myObj?.myProp ?? true` see [Nullish coalescing operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator) – ciekals11 Nov 26 '21 at 14:32
  • Honestly didn't know `??` was valid operator in javascript... thought it was only in C/variants – freefaller Nov 26 '21 at 14:32
  • @freefaller It's very new - added in the latest spec. So, it's from this year. – VLAZ Nov 26 '21 at 14:33
  • @ciekals11 There is no need of `?.` in this case. `myObj.myProp ?? true` will do the work – DecPK Nov 26 '21 at 14:33
  • @VLAZ - that would explain it... and unfortunately IE doesn't support it... which unfortunately (due to really annoying clients) we DO have to still support – freefaller Nov 26 '21 at 14:33
  • @freefaller You can transpile your code, if possible. You can then *write* `a ?? true` but the transpiled code will do the full check. However, I'm aware that's not always an option. – VLAZ Nov 26 '21 at 14:35
  • ``myObj.myProp || true`` will give you the same result. You can read more about or operator at mdn reference here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_OR – em_code Nov 26 '21 at 14:36
  • Thanks @VLAZ - not really an option at the moment, but really appreciate the thought. Will stick with code I have – freefaller Nov 26 '21 at 14:37
  • @em_code - no, it won't. if `myObj.myProp == false` your code will still give `true` – freefaller Nov 26 '21 at 14:37
  • @em_code no, it's not the same because `false || true` is always `true` – VLAZ Nov 26 '21 at 14:37
  • 1
    @freefaller yes, what you have right now is probably the best, given the circumstances. – VLAZ Nov 26 '21 at 14:38
  • @VLAZ - what do you reckon... should I delete the question, update the question to point out my IE requirement, or do you want to add an answer that takes into account the requirement? Not sure of the etiquette with these situations – freefaller Nov 26 '21 at 14:43
  • @freefaller I think it's worth keeping it. I can't remember of a duplicate that directly answers that. I think can also offer you an alternative. I wouldn't say it's *better* but might be a useful approach. – VLAZ Nov 26 '21 at 14:48
  • 1
    You don't need to check the type you can just do `myObj.myProp !== undefined ? myObj.myProp : true;` - slightly shorter – James Nov 26 '21 at 14:50
  • @James undefined *could* be overwritten with a different value. It's harder nowadays as it's protected, so it might be overly defensive but I can't remember if IE11 protects `undefined` or not. You can still do it with a parameter that shadows `undefined` for example `fn = (obj, undefined) => obj.prop === undefined` and then try `fn({}, "hello")` – VLAZ Nov 26 '21 at 15:02
  • @VLAZ true, but you could say that about almost any global. `const fn = (obj, document) => document.getElementById("whatever")...` – James Nov 26 '21 at 17:09
  • @James I was just demonstrating how it's possible to do it *now*. It used to be possible to just do `undefined = "hello"` directly and change the value *everywhere*. However, `undefined` has since been made write-protected. IE certainly lagged behind on that and I'm not sure when, if ever, it was implemented there. – VLAZ Nov 26 '21 at 17:36

1 Answers1

1

ECMAScript 2020 introduced the nullish coalescing operator ??:

const test = obj =>
  obj.myProp ?? true;

console.log( test({}) );                // return true
console.log( test({ myProp: false }) ); // return false
console.log( test({ myProp: true }) );  // return true

However, before that existed there is not many options. Your current code (typeof myObj.myProp !== "undefined" ? myObj.myProp : true) is probably the best you can have for older environments.

If you do have to deal with them a lot and nullish-ness is a constant problem, you can make a simple wrapper for safely getting values that might not exist:

function Safe(val) {
  return {
    get: function(prop) {
      if (val == null)
        return Safe(null);
        
      return Safe(val[prop]);
    },
    orElse: function(fallbackValue) {
      if (val == null)
        return fallbackValue;

      return val
    }
  }
};

console.log( //true
  Safe({})
    .get("myProp")
    .orElse(true)
)
console.log( // false
  Safe({ myProp: false })
    .get("myProp")
    .orElse(true)
);
console.log( // true
  Safe({ myProp: true })
    .get("myProp")
    .orElse(true)
);

var complexObject = {
  level1: {
    level2: {
      myProp: false
    }
  }
};

console.log( // { "level2": { "myProp": false } }
  Safe(complexObject)
    .get("level1")
    .orElse(true)
);
console.log( // { "myProp": false }
  Safe(complexObject)
    .get("level1")
    .get("level2")
    .orElse(true)
);
console.log( // false
  Safe(complexObject)
    .get("level1")
    .get("level2")
    .get("myProp")
    .orElse(true)
);
console.log( // true
  Safe(complexObject)
    .get("level1")
    .get("level2")
    .get("level3")
    .get("myProp")
    .orElse(true)
);
.as-console-wrapper { max-height: 100% !important; }

The API here modelled after Java's Optional but very simplified. The point is to show that it is possible to do safer handling if that is something that often shows up.

The Optional in Java is also called Option or Maybe in other places and more formally encodes handling values that might be null. To see the more of how this can be done, see this chapter of Mostly Adequate Guide to Functional Programming on GitBooks (or the older version which uses ES5 syntax)

Another alternative instead of writing your own safe handling would be to use a library that supports it like Lodash's _.get():

console.log( //true
  _.get({}, "myProp", true)
);
console.log( // false
  _.get({ myProp: false }, "myProp", true)
);
console.log( // true
  _.get({ myProp: true }, "myProp", true)
);

var complexObject = {
  level1: {
    level2: {
      myProp: false
    }
  }
};

console.log( // { "level2": { "myProp": false } }
  _.get(complexObject, "level1", true)
);
console.log( // { "myProp": false }
  _.get(complexObject, [ "level1", "level2"], true)
);
console.log( // false
  _.get(complexObject, [ "level1", "level2", "myProp"], true)
);
console.log( // true
  _.get(complexObject, [ "level1", "level2", "level3", "myProp"], true)
);
.as-console-wrapper { max-height: 100% !important; }
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
VLAZ
  • 26,331
  • 9
  • 49
  • 67