JS `Optional Chaining (?.)` (ES2020):安全访问嵌套属性与方法

嘿,大家好!我是你们今天的代码导游,准备好一起探索 JavaScript 中这个让代码更安全、更优雅的小技巧了吗?今天咱们要聊的是 ES2020 引入的 Optional Chaining,也就是我们常说的“可选链式调用”。 听起来很高大上?别怕,其实它简单到让你觉得“早该有了!”。

第一幕: 痛点 – 深渊般的属性访问

在没有 Optional Chaining 的日子里,我们常常面对这样的场景:

const user = {
  profile: {
    address: {
      street: 'Main Street',
      city: 'Anytown'
    }
  }
};

// 获取用户的城市
let city;
if (user && user.profile && user.profile.address) {
  city = user.profile.address.city;
} else {
  city = undefined; // 或者其他默认值
}

console.log(city); // Anytown

这段代码虽然能工作,但读起来像在走钢丝,每一步都要检查是否存在,稍有不慎就会掉入 TypeError: Cannot read property '...' of undefined 的深渊。特别是当对象层级更深,条件判断就会像俄罗斯套娃一样嵌套,代码瞬间变得难以维护。

如果你胆子大,可能会尝试这样写:

let city = user.profile.address.city; // 可能会报错!

一旦 user.profileuser.profile.address 不存在,程序就直接崩溃了。这种写法就像在没有安全措施的情况下攀岩,刺激是刺激,但风险太高。

第二幕:救星登场 – Optional Chaining (?.)

现在,让我们欢迎今天的明星 – Optional Chaining! 它的语法很简单: ?.。 它的作用是:如果 ?. 前面的值为 null 或者 undefined,那么整个表达式会立即停止运算,并返回 undefined。 否则,就像普通的属性访问一样继续执行。

Optional Chaining 重写上面的例子:

const user = {
  profile: {
    address: {
      street: 'Main Street',
      city: 'Anytown'
    }
  }
};

let city = user?.profile?.address?.city;

console.log(city); // Anytown

const user2 = {}; // 空对象

let city2 = user2?.profile?.address?.city;

console.log(city2); // undefined  不会报错!

看到了吗?代码瞬间变得简洁明了,不再需要繁琐的条件判断。如果 userprofileaddress 中任何一个不存在,city 的值都会是 undefined,而不会抛出错误。 这就像给我们的代码穿上了一件安全气囊,即使遇到 nullundefined,也能平稳落地。

第三幕:花式用法 – 方法调用、数组访问

Optional Chaining 不仅仅可以用于属性访问,还可以用于方法调用和数组访问。

  • 方法调用:
const obj = {
  myMethod: function() {
    return 'Hello!';
  }
};

let result = obj.myMethod?.(); // 'Hello!'

const obj2 = {};

let result2 = obj2.myMethod?.(); // undefined  不会报错!

如果 myMethod 存在且是一个函数,那么它会被正常调用。 如果 myMethod 不存在,整个表达式会返回 undefined,避免了调用 undefined 的错误。

  • 数组访问:
const arr = [1, 2, 3];

let value = arr?.[1]; // 2

const arr2 = null;

let value2 = arr2?.[1]; // undefined  不会报错!

如果 arr 存在且是一个数组,那么我们可以像往常一样访问它的元素。 如果 arrnullundefined,那么整个表达式会返回 undefined

第四幕: 与 Nullish Coalescing Operator (??) 配合使用

Optional Chaining 经常与 Nullish Coalescing Operator (??) 配合使用,提供默认值。 ?? 的意思是:如果左边的值为 nullundefined,则返回右边的值。

const user = {};

let city = user?.profile?.address?.city ?? 'Unknown City';

console.log(city); // Unknown City

在这个例子中,如果 user.profile.address.city 的值为 nullundefined,那么 city 的值就会是 'Unknown City'。 这样我们就能优雅地处理缺失值,避免了在代码中到处写 if 语句。

第五幕: 注意事项和最佳实践

虽然 Optional Chaining 很好用,但也要注意以下几点:

  1. 只在必要时使用: 不要滥用 Optional Chaining。 只有当你知道某个属性或方法可能不存在时才使用它。 过度使用 Optional Chaining 可能会掩盖代码中的潜在问题。
  2. 明确你的意图: 在使用 Optional Chaining 时,要清楚地知道你希望在属性不存在时做什么。 是返回 undefined,还是提供一个默认值? 使用 Nullish Coalescing Operator (??) 可以明确你的意图。
  3. 避免过深的链式调用: 如果你的代码中出现了很长的 Optional Chaining 链,例如 a?.b?.c?.d?.e,那么可能需要重新考虑你的数据结构或代码设计。 过深的链式调用通常意味着代码的耦合度过高,难以维护。 可以考虑使用中间变量或者重构代码来简化逻辑。
  4. 不要用于赋值操作的左侧: Optional Chaining 不能用于赋值操作的左侧。 例如, user?.profile?.name = 'John' 是无效的语法。 因为 user?.profile?.name 可能会返回 undefined,而我们不能给 undefined 赋值。

第六幕: 示例代码 – 更复杂的场景

让我们来看一些更复杂的例子,展示 Optional Chaining 的威力。

  • 处理 API 返回的数据:
async function fetchData() {
  try {
    const response = await fetch('/api/data');
    const data = await response.json();

    // 使用 Optional Chaining 安全地访问数据
    const userName = data?.user?.name ?? 'Guest';
    const userAddress = data?.user?.address?.city ?? 'Unknown';

    console.log(`User Name: ${userName}, City: ${userAddress}`);

  } catch (error) {
    console.error('Error fetching data:', error);
  }
}

fetchData();

在这个例子中,我们从 API 获取数据,并使用 Optional Chaining 安全地访问 user.nameuser.address.city。 如果 API 返回的数据结构不完整,我们的代码也不会崩溃,而是会使用默认值。

  • 处理用户输入:
function processUserInput(input) {
  const trimmedInput = input?.trim?.(); // 安全地调用 trim() 方法
  if (trimmedInput) {
    console.log('Processed input:', trimmedInput);
  } else {
    console.log('No input provided.');
  }
}

processUserInput('  Hello  '); // Processed input: Hello
processUserInput(null); // No input provided.
processUserInput(undefined); // No input provided.

在这个例子中,我们使用 Optional Chaining 安全地调用字符串的 trim() 方法。 如果 inputnullundefinedtrim() 方法不会被调用,避免了错误。

第七幕:总结 – 告别 NullPointerException 的噩梦

Optional Chaining 是一个非常实用的 JavaScript 特性,它可以让我们编写更安全、更简洁的代码。 它通过优雅地处理 nullundefined 值,避免了 TypeError 错误,提高了代码的可读性和可维护性。

以下表格总结了 Optional Chaining 的主要用法:

语法 描述 示例
obj?.prop 如果 objnullundefined,则返回 undefined。否则,返回 obj.prop const name = user?.profile?.name;
obj?.[expr] 如果 objnullundefined,则返回 undefined。否则,返回 obj[expr] const firstElement = arr?.[0];
func?.(args) 如果 funcnullundefined,则返回 undefined。否则,调用 func(args) const result = obj.myMethod?.(arg1, arg2);
obj?.prop ?? defaultValue 如果 obj?.propnullundefined,则返回 defaultValue。否则,返回 obj.prop。 这与 Optional ChainingNullish Coalescing Operator (??) 结合使用,提供默认值。 const city = user?.profile?.address?.city ?? 'Unknown City';

总而言之,Optional Chaining 就像一把瑞士军刀,可以帮助我们轻松应对 JavaScript 中常见的 nullundefined 问题。 熟练掌握 Optional Chaining,可以让我们编写出更健壮、更优雅的代码,告别 NullPointerException 的噩梦!

希望今天的讲座对大家有所帮助! 下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注