从节点应用程序中的对象安全地获取 属性
get property safely from an object in a node application
首先是一点上下文(如果你更喜欢关注代码,可以跳过这部分)。
我加入了一个新项目,该项目将集成到 nodeJS 的平台中。我们的团队确实有 JEE 企业 Web 应用程序 的经验。这就建立了我们的背景。这个新项目将使用 REST APIs,聚合一些数据,实现一些业务逻辑并将这些数据传递给前端消费者。某种轻量级微服务架构。
一些同事开始从事该项目,我发现在源代码中我们确实有很多代码片段,例如 if (foo != null && foo.property != null) {return foo.property.value;}
Foo 应该是一个对象,作为参数传递给将实现这种测试的函数。
一个片段示例会讲得更多。
让我们假设这是我正在消费的 API 的反应。我想写一个小函数,如果对象确实存在,它会 return 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 等库的 JS 最佳实践是什么。
使用 Lodash,您可以使用 _.isNil(response)
记录的函数 here。
一般来说,我会这样检查变量:
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
将是 undefined
/null
如果 obj
或 obj.prop
是;否则它将是 obj.prop.val
.
这是因为 &&
的短路评估。它的字面行为是这样的:如果第一个操作数是假的,它计算第一个操作数。否则,它评估为第二个。这对于布尔值可以正常工作,但如您所见,它对对象很有用。
||
有类似的行为。例如,您可以使用它来获取一个值,如果该值是假的(例如 null
),则可以使用它来获取默认值:
var val2 = val || "not found";
请注意,如果 val
是 任何错误的东西 ,包括 0
或 ""
,这将评估为 "not found"
。
我将使用以下函数实现它:
var response = {
"services":[],
"metadata": {
"status": "statusValue"
}
};
function getStatusValue(res) {
if (res && res.metadata)
return res.metadata.status || 'not found';
else
return 'not found';
}
console.log(getStatusValue(response));
如果 res
或 res.metadata
是 undefined
,if
语句将 return false
并且如果它们都存在,它将 return res.metadata.status
只有定义了或者0
,否则会return 'not found'
.
检查对象的属性时,检查与 null
的松散相等性是不够的。
松散相等 (==
) 在 JavaScript 中使用类型提示,它尝试将成员转换为通用类型,然后可用于确定它们是否相等。
因此,JavaScript 的最佳实践规定始终使用严格相等 (===
),以避免在检查值或类型时出现边缘情况或未知行为。
您可以在此处找到有关松散与严格相等的更多信息:
- https://developer.mozilla.org/en/docs/Web/JavaScript/Equality_comparisons_and_sameness
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators
虽然这在您的函数中不是必须的,但将其养成习惯是一种很好的做法,这样在以后的代码中就可以避免松散相等 (==
) 的影响(例如,避免 '3' == 3
,当需要数字或字符串类型时)。
虽然有些人认为这种语言有缺点,但使用 null
的意图与检查 undefined
相似,但实际上是为了在代码中表达编码人员期望 object
(或缺少),而不是原始类型(number
、string
、boolean
、function
)。这不同于 Java 或任何其他类型化语言,其中 null
用于 Object
类型定义的变量; 但在 JavaScript 中没有将变量限制为给定类型。
您可以在 MDN 上找到有关 null
的更多详细信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null
在实践中,尤其是在处理来自单位之外的值时 - 这是任何 API 的情况 - 被认为是实际检查类型为 [=20= 的最佳实践],以确保它 具有 属性。
虽然您的代码并没有错,但它确实表明没有太多关注最佳实践,这最终会导致编写有错误的代码。
我对您的代码的建议是:遵循最佳实践并独立于任何库:
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.
}
}
此外,从您集成的任何库中创建或使用检查有效对象的函数可能会更容易;像 _.isObject 或这样的东西:
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.
}
}
作为最后的想法,很明显,遵循最佳实践确实会增加代码的大小,但好处是生成的代码更安全,抛出异常的可能性更小 (许多应用程序崩溃的根源),更容易协作,更容易构建 tests/coverage。
首先是一点上下文(如果你更喜欢关注代码,可以跳过这部分)。
我加入了一个新项目,该项目将集成到 nodeJS 的平台中。我们的团队确实有 JEE 企业 Web 应用程序 的经验。这就建立了我们的背景。这个新项目将使用 REST APIs,聚合一些数据,实现一些业务逻辑并将这些数据传递给前端消费者。某种轻量级微服务架构。
一些同事开始从事该项目,我发现在源代码中我们确实有很多代码片段,例如 if (foo != null && foo.property != null) {return foo.property.value;}
Foo 应该是一个对象,作为参数传递给将实现这种测试的函数。
一个片段示例会讲得更多。
让我们假设这是我正在消费的 API 的反应。我想写一个小函数,如果对象确实存在,它会 return 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 等库的 JS 最佳实践是什么。
使用 Lodash,您可以使用 _.isNil(response)
记录的函数 here。
一般来说,我会这样检查变量:
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
将是 undefined
/null
如果 obj
或 obj.prop
是;否则它将是 obj.prop.val
.
这是因为 &&
的短路评估。它的字面行为是这样的:如果第一个操作数是假的,它计算第一个操作数。否则,它评估为第二个。这对于布尔值可以正常工作,但如您所见,它对对象很有用。
||
有类似的行为。例如,您可以使用它来获取一个值,如果该值是假的(例如 null
),则可以使用它来获取默认值:
var val2 = val || "not found";
请注意,如果 val
是 任何错误的东西 ,包括 0
或 ""
,这将评估为 "not found"
。
我将使用以下函数实现它:
var response = {
"services":[],
"metadata": {
"status": "statusValue"
}
};
function getStatusValue(res) {
if (res && res.metadata)
return res.metadata.status || 'not found';
else
return 'not found';
}
console.log(getStatusValue(response));
如果 res
或 res.metadata
是 undefined
,if
语句将 return false
并且如果它们都存在,它将 return res.metadata.status
只有定义了或者0
,否则会return 'not found'
.
检查对象的属性时,检查与 null
的松散相等性是不够的。
松散相等 (==
) 在 JavaScript 中使用类型提示,它尝试将成员转换为通用类型,然后可用于确定它们是否相等。
因此,JavaScript 的最佳实践规定始终使用严格相等 (===
),以避免在检查值或类型时出现边缘情况或未知行为。
您可以在此处找到有关松散与严格相等的更多信息:
- https://developer.mozilla.org/en/docs/Web/JavaScript/Equality_comparisons_and_sameness
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators
虽然这在您的函数中不是必须的,但将其养成习惯是一种很好的做法,这样在以后的代码中就可以避免松散相等 (==
) 的影响(例如,避免 '3' == 3
,当需要数字或字符串类型时)。
虽然有些人认为这种语言有缺点,但使用 null
的意图与检查 undefined
相似,但实际上是为了在代码中表达编码人员期望 object
(或缺少),而不是原始类型(number
、string
、boolean
、function
)。这不同于 Java 或任何其他类型化语言,其中 null
用于 Object
类型定义的变量; 但在 JavaScript 中没有将变量限制为给定类型。
您可以在 MDN 上找到有关 null
的更多详细信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null
在实践中,尤其是在处理来自单位之外的值时 - 这是任何 API 的情况 - 被认为是实际检查类型为 [=20= 的最佳实践],以确保它 具有 属性。
虽然您的代码并没有错,但它确实表明没有太多关注最佳实践,这最终会导致编写有错误的代码。
我对您的代码的建议是:遵循最佳实践并独立于任何库:
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.
}
}
此外,从您集成的任何库中创建或使用检查有效对象的函数可能会更容易;像 _.isObject 或这样的东西:
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.
}
}
作为最后的想法,很明显,遵循最佳实践确实会增加代码的大小,但好处是生成的代码更安全,抛出异常的可能性更小 (许多应用程序崩溃的根源),更容易协作,更容易构建 tests/coverage。