从节点应用程序中的对象安全地获取 属性

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 如果 objobj.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));

如果 resres.metadataundefinedif 语句将 return false 并且如果它们都存在,它将 return res.metadata.status 只有定义了或者0,否则会return 'not found'.

检查对象的属性时,检查与 null 的松散相等性是不够的。

松散相等 (==) 在 JavaScript 中使用类型提示,它尝试将成员转换为通用类型,然后可用于确定它们是否相等。 因此,JavaScript 的最佳实践规定始终使用严格相等 (===),以避免在检查值或类型时出现边缘情况或未知行为。 您可以在此处找到有关松散与严格相等的更多信息:

虽然这在您的函数中不是必须的,但将其养成习惯是一种很好的做法,这样在以后的代码中就可以避免松散相等 (==) 的影响(例如,避免 '3' == 3,当需要数字或字符串类型时)。

虽然有些人认为这种语言有缺点,但使用 null 的意图与检查 undefined 相似,但实际上是为了在代码中表达编码人员期望 object(或缺少),而不是原始类型(numberstringbooleanfunction)。这不同于 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。