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/
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.
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
.
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":
/**
* 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;
}
}