Javascript 如何避免';无法读取未定义的';错误?
在我的代码中,我处理一个数组,该数组中有一些条目,其中许多对象嵌套在另一个条目中,而有些条目则没有。它看起来如下所示:Javascript 如何避免';无法读取未定义的';错误?,javascript,monetjs,Javascript,Monetjs,在我的代码中,我处理一个数组,该数组中有一些条目,其中许多对象嵌套在另一个条目中,而有些条目则没有。它看起来如下所示: // where this array is hundreds of entries long, with a mix // of the two examples given var test = [{'a':{'b':{'c':"foo"}}}, {'a': "bar"}]; 这给我带来了问题,因为我有时需要遍历数组,而不一致性给我带来了如下错误: for (i=0; i
// where this array is hundreds of entries long, with a mix
// of the two examples given
var test = [{'a':{'b':{'c':"foo"}}}, {'a': "bar"}];
这给我带来了问题,因为我有时需要遍历数组,而不一致性给我带来了如下错误:
for (i=0; i<test.length; i++) {
// ok on i==0, but 'cannot read property of undefined' on i==1
console.log(a.b.c);
}
for(i=0;i您所做的会引发异常(这是理所当然的)
你总能做到
try{
window.a.b.c
}catch(e){
console.log("YO",e)
}
但我不会去想你的用例
为什么要访问您不熟悉的6层嵌套数据?什么用例证明了这一点
通常,您希望实际验证正在处理的对象的类型
另外,在旁注中,您不应该使用类似于if(a.b)
的语句,因为如果a.b为0,甚至是“0”,它将返回false。相反,请检查a.b!==未定义的如果我正确理解您的问题,您需要最安全的方法来确定对象是否包含属性
最简单的方法是使用
当然,你可以把它埋得越深越好
if ("a" in window.b.c) { }
不确定这是否有帮助。如果您正在使用,您可以使用它们的“has”功能。它类似于本机的“in”,但允许路径
var testObject = {a: {b: {c: 'walrus'}}};
if(_.has(testObject, 'a.b.c')) {
//Safely access your walrus here
}
我很虔诚地使用它。它测试对象的每一个级别,直到它得到您要求的值,或者返回“undefined”。但决不会出错。这是处理深度或复杂json对象时的常见问题,因此我尽量避免尝试/捕获或嵌入多个检查,这会使代码无法读取,我通常在所有过程中都使用这段代码来完成这项工作
/*ex:getProperty(myObj,'aze.xyz',0)//安全返回myObj.aze.xyz
*接受属性名称的数组:
*getProperty(myObj,['aze','xyz'],{value:null})
*/
函数getProperty(对象、道具、默认值){
var res,isvoid=function(x){return typeof x==“undefined”| | x==null;}
如果(!isvoid(obj)){
如果(isvoid(props))props=[];
如果(typeof props==“string”)props=props.trim().split(“.”);
if(props.constructor==数组){
res=props.length>1?getProperty(obj[props.shift()],props,defaultValue):obj[props[0]];
}
}
返回typeof res==“未定义”?默认值:res;
}
更新:
- 如果根据ECMAScript 2020或更高版本使用JavaScript,请参阅
- TypeScript在版本中增加了对可选链接的支持
//像这样使用它
大量的财产
ECMASCript 2020之前的JavaScript解决方案或版本3.7之前的TypeScript解决方案:
一种快速解决方法是在ES6中使用try/catch助手函数:
函数getSafe(fn,defaultVal){
试一试{
返回fn();
}捕获(e){
返回defaultVal;
}
}
//像这样使用它
log(getSafe(()=>obj.a.lot.of.properties));
//或添加可选的默认值
console.log(getSafe(()=>obj.a.lot.of.properties,'nothing');
试试这个。如果a.b
未定义,它将毫无例外地保留If
语句
if (a.b && a.b.c) {
console.log(a.b.c);
}
在str的回答中,如果属性未定义,将返回值“undefined”,而不是设置的默认值。这有时会导致错误。以下内容将确保在属性或对象未定义时始终返回defaultVal
const temp = {};
console.log(getSafe(()=>temp.prop, '0'));
function getSafe(fn, defaultVal) {
try {
if (fn() === undefined || fn() === null) {
return defaultVal
} else {
return fn();
}
} catch (e) {
return defaultVal;
}
}
我以前回答过这个问题,今天碰巧做了一个类似的检查。检查嵌套虚线属性是否存在的简化方法。您可以修改它以返回值,或者使用一些默认值来实现您的目标
function containsProperty(instance, propertyName) {
// make an array of properties to walk through because propertyName can be nested
// ex "test.test2.test.test"
let walkArr = propertyName.indexOf('.') > 0 ? propertyName.split('.') : [propertyName];
// walk the tree - if any property does not exist then return false
for (let treeDepth = 0, maxDepth = walkArr.length; treeDepth < maxDepth; treeDepth++) {
// property does not exist
if (!Object.prototype.hasOwnProperty.call(instance, walkArr[treeDepth])) {
return false;
}
// does it exist - reassign the leaf
instance = instance[walkArr[treeDepth]];
}
// default
return true;
}
我通常这样使用:
var x = object.any ? object.any.a : 'def';
我喜欢曹寿光的回答,但我不喜欢每次调用时都将函数作为参数传递给getSafe函数。我修改了getSafe函数,以接受简单的参数和纯ES5
/**
* Safely get object properties.
* @param {*} prop The property of the object to retrieve
* @param {*} defaultVal The value returned if the property value does not exist
* @returns If property of object exists it is returned,
* else the default value is returned.
* @example
* var myObj = {a : {b : 'c'} };
* var value;
*
* value = getSafe(myObj.a.b,'No Value'); //returns c
* value = getSafe(myObj.a.x,'No Value'); //returns 'No Value'
*
* if (getSafe(myObj.a.x, false)){
* console.log('Found')
* } else {
* console.log('Not Found')
* }; //logs 'Not Found'
*
* if(value = getSafe(myObj.a.b, false)){
* console.log('New Value is', value); //logs 'New Value is c'
* }
*/
function getSafe(prop, defaultVal) {
return function(fn, defaultVal) {
try {
if (fn() === undefined) {
return defaultVal;
} else {
return fn();
}
} catch (e) {
return defaultVal;
}
}(function() {return prop}, defaultVal);
}
Lodash有一种方法,允许将默认值作为可选的第三个参数,如下所示:
const myObject={
有:"一些",,
缺失:{
瓦尔斯:是的
}
}
常量路径='missing.const.value';
const myValue=551;.get(myObject,path,'default');
console.log(myValue)//打印出上面指定的默认值
如果您使用Babel,您已经可以使用可选的链接语法。这将允许您替换此语法:
console.log(a && a.b && a.b.c);
为此:
console.log(a?.b?.c);
如果有,可以使用它的.get
方法
获取(a,'b.c.d.e')
或者给它一个默认值
\获取(a'b.c.d.e',默认值)
想象一下,我们想对x
应用一系列函数,当且仅当x
为非空时:
if (x !== null) x = a(x);
if (x !== null) x = b(x);
if (x !== null) x = c(x);
现在让我们假设我们需要对y
执行相同的操作:
if (y !== null) y = a(y);
if (y !== null) y = b(y);
if (y !== null) y = c(y);
与z
相同:
if (z !== null) z = a(z);
if (z !== null) z = b(z);
if (z !== null) z = c(z);
正如你所看到的,如果没有一个适当的抽象,我们将一次又一次地重复代码。这样的抽象已经存在了:可能是单子
Maybe monad包含一个值和一个计算上下文:
monad保持值的安全性并对其应用函数
计算上下文是应用函数之前的空检查
简单的实现如下所示:
var x = object.any ? object.any.a : 'def';
⚠️ 这个实现只是为了说明目的!这不是应该怎么做的,在很多层面上都是错误的。不过,这会让你更好地理解我所说的
正如你所看到的,没有任何东西可以打破:
我们将一系列函数应用于我们的值
如果在任何时候,值变为null(或未定义),我们就不再应用任何函数
const abc=obj=>
大概
.of(obj)
.map(o=>o.a)
.map(o=>o.b)
.map(o=>o.c)
价值
常量值=[
{},
{a:{}},
{a:{b:{}},
{a:{b:{c:42}}
];
console.log(
价值地图(abc)
);
函数(x){
this.value=x;//->我们价值的容器
if (z !== null) z = a(z);
if (z !== null) z = b(z);
if (z !== null) z = c(z);