我想检查一个对象是否存在,并且有一个属性。目前我得到一个" myObject未定义"停止检查的错误。
即使myObject可能不存在,如何使以下内容仍能正常工作?
if (myObject.myProperty) {
...
} else {
...
}
我试图甚至检查对象/变量是否存在但是收到错误:
if (foo) { console.log('hello'); }
给出错误Uncaught ReferenceError:foo未定义。这是一个jsfiddle http://jsfiddle.net/cfUss/
答案 0 :(得分:7)
您可以使用“短路”&&
运算符:
if (myObject && myObject.myProperty) {
...
}
如果myObject
为“falsey”(例如未定义),&&
运算符将不会尝试评估右手表达式,从而避免尝试引用不存在的属性对象
变量myObject
必须已经声明,上面的测试是针对是否已为分配了一个定义的值。
答案 1 :(得分:1)
我很惊讶在基本的Javascipt界面中找不到这个有用的功能。
以下是我经常在我的项目中使用的帮助函数。它检查最终链元素的值是否可达而没有错误"无法获得...未定义" 。以这种方式使用它:
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;
}
}
答案 2 :(得分:0)
尝试:
if(myObject && myObject.myProperty){ ... }
如果if
存在,此代码会进入myObject
块的正文,并且还会myproperty
。如果由于某种原因myObject
不存在,&&
短路且未评估myObject.myProperty
。
答案 3 :(得分:0)
您可以使用可选链接运算符?.
保持简洁:
if (myObject?.myProperty) { ... }
相当于更冗长
if (myObject && myObject.myProperty) { ... }
它非常方便,特别是对于深度嵌套的对象。
它目前(2019年9月)是一个 ECMAScript第三阶段提案,但看起来该功能将正式可用是有希望的。目前,您已经可以通过相应的Babel插件开始使用它了:https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining