Javascript 从节点应用程序中的对象安全获取属性
首先是一点上下文(如果您喜欢关注代码,可以跳过这一部分) 我加入了一个新项目,该项目将集成到一个nodeJS平台中。我们的团队确实拥有使用JEE企业Web应用程序的经验。这就是我们的背景。这个新项目将使用RESTAPI,聚合一些数据,实现一些业务逻辑,并将这些数据传递给前端消费者。一种轻量级的微服务架构 一些同事开始着手这个项目,我发现在源代码中有很多代码片段,比如Javascript 从节点应用程序中的对象安全获取属性,javascript,node.js,null,undefined,lodash,Javascript,Node.js,Null,Undefined,Lodash,首先是一点上下文(如果您喜欢关注代码,可以跳过这一部分) 我加入了一个新项目,该项目将集成到一个nodeJS平台中。我们的团队确实拥有使用JEE企业Web应用程序的经验。这就是我们的背景。这个新项目将使用RESTAPI,聚合一些数据,实现一些业务逻辑,并将这些数据传递给前端消费者。一种轻量级的微服务架构 一些同事开始着手这个项目,我发现在源代码中有很多代码片段,比如if(foo!=null&&foo.property!=null){return foo.property.value;} Foo应
if(foo!=null&&foo.property!=null){return foo.property.value;}
Foo应该是作为参数传递给函数的对象,函数将实现这种测试
一个片段示例将说明更多内容
让我们假设这是我正在使用的API的响应。我想写一个小函数,它将返回statusValue
,如果对象确实存在,如果它不为null或未定义,不为空,并且属性确实存在,例如不为空或为空
var response = {
"services":[],
"metadata": {
"status": "statusValue"
}
};
目前情况就是这样:
function getStatusValue(response) {
if (response != null && response.metadata != null) {
return response.metadata.status;
}
};
实现这一点的最佳JS实践是什么(我们也在使用lodash,因此使用lodash内部构件可能是更好的选择)。我只是担心我们正在改变Java的习惯
基本上,我想知道如何安全地检查
null、undefined、empty、blank
(如果有意义的话)。2016年,对于lodash和stuff之类的库,JS的最佳实践是什么。使用lodash,您可以使用\uuuu.isNil(response)
函数
通常,我会检查如下变量:
if (typeof x !== 'undefined' && x !== null) {
// x has some value
}
您不应该检查x===undefined
,因为如果x
未定义,您将得到一个解引用错误。这里有一种(更简洁的)方法,可以仅使用JS执行此操作:
var obj = ...;
var val = obj && obj.prop && obj.prop.val;
val
如果obj
或obj.prop
为空,则val
将是未定义的/null
;否则它将是对象属性值
这是因为对&&
进行了短路评估。它的文字行为是这样的:如果第一个操作数为false,它将计算为第一个操作数。否则,它将计算为第二个。这与预期的布尔值一样有效,但正如您所看到的,它对对象非常有用
|
具有类似的行为。例如,您可以使用它来获取一个值,如果该值为false(例如,null
),则可以使用它获取一个默认值:
请注意,如果val
有任何错误,包括0
或“
”
,,我将使用以下函数实现此功能,则这将计算为“未找到”
:
var响应={
“服务”:[],
“元数据”:{
“状态”:“状态值”
}
};
函数getStatusValue(res){
if(res&&res.metadata)
返回res.metadata.status | |“未找到”;
其他的
返回“未找到”;
}
console.log(getStatusValue(response))代码>检查对象属性时,仅检查是否与null
不相等是不够的
松散相等(=
)在JavaScript中使用类型暗示,它尝试将成员转换为公共类型,然后可用于确定它们是否相等。
因此,JavaScript的最佳实践要求始终使用严格相等(=
),以避免在检查值或类型时出现边缘情况或未知行为。
您可以在此处找到有关松散与严格平等的更多信息:
虽然这不是您函数中必须具备的功能,但作为一种习惯来遵循和培养它是一种很好的做法,这样在以后的代码中就可以避免松散相等(=
)的影响(例如,当需要数字或字符串类型时,避免'3'==3
)
尽管有些人认为使用null
是该语言的一个缺点,但在意图上与检查未定义的类似,但实际上是为了在代码中表示编码者希望提供对象(或缺少),而不是原语类型(number
,string
,boolean
,function
)。这不同于Java或任何其他类型化语言,其中null
用于对象
类型定义的变量;但在JavaScript中,没有将变量约束为给定类型
您可以在MDN上找到有关null
的更多详细信息:
在实践中,尤其是在处理单元之外的值时(这是任何API的情况),实际检查类型是否为对象
,以确保其具有属性,被认为是最佳做法
虽然您的代码没有错误,但它确实表明您对最佳实践没有太多的关注,这最终会导致编写错误代码
我对您的代码的建议是,遵循最佳实践并独立于任何库:
function getStatusValue(response) {
// must be of type `object`, to have properties.
if (typeof response === 'object' &&
// any variable of type `object` might be `null`, so exclude that.
response !== null &&
// `metadata` property must be of type `object`, to have properties.
typeof response.metadata !== 'object' &&
// `metadata` is of type `object`, check for not being `null`.
response.metadata !== null) {
// `status` property is expected to be a string, given by the API spec
if (typeof response.metadata.status === 'string' &&
// on strings, we can access the `length` property to check if empty string (0 chars).
response.metadata.status.length > 0) {
// all good, return `status` property.
return response.metadata.status;
} else {
// `status` property is either not a string, or an empty string ('').
}
} else {
// invalid `response` object.
}
}
此外,从您集成的任何库中创建或使用一个用于检查有效对象的函数可能更容易;类似这样的功能:
function isObject(o) {
return (typeof o === 'object' && o !== null);
}
您可以稍后在上面的截图中使用,如下所示:
function getStatusValue(response) {
if (isObject(response) && isObject(response.metadata)) {
if (typeof response.metadata.status === 'string' &&
response.metadata.status.length > 0) {
return response.metadata.status;
} else {
// `status` property is either not a string, or an empty string ('').
}
} else {
// invalid `response` object.
}
}
最后一个想法是,很明显,遵循最佳实践确实会增加代码的大小,但好处是生成的代码更安全,抛出异常的可能性更小(许多应用程序崩溃的根源)一方面,你可以省去!=null
,因为null
/未定义的是错误的。如果(obj&&obj.prop)
,我们使用如果(obj&&obj.prop)
。为了防止未定义的对象,你可以使用严格模式
function getStatusValue(response) {
if (isObject(response) && isObject(response.metadata)) {
if (typeof response.metadata.status === 'string' &&
response.metadata.status.length > 0) {
return response.metadata.status;
} else {
// `status` property is either not a string, or an empty string ('').
}
} else {
// invalid `response` object.
}
}