JavaScript 可选链运算符

摘要: 在本教程中,您将了解可选链运算符 (?.),它简化了通过连接对象访问值的方式。

JavaScript 可选链运算符简介

可选链运算符 (?.) 就像一个访问对象系列中嵌套属性的快捷方式。 您无需检查链中每个步骤是否为空 (nullundefined),而是可以使用运算符 ?. 直接访问所需的属性。

如果链的任何部分为空,可选链运算符 (?.) 将立即停止并返回 undefined 作为结果。 它可以避免您为链中每个步骤编写额外的检查。

假设您有一个返回 user 对象的函数

function getUser(id) {

    if(id <= 0) {
        return null;
    }

    // get the user from database
    // and return null if id does not exist
    // ...
    
    // if user was found, return the user
    return {
        id: id,
        username: 'admin',
        profile: {
            avatar: '/avatar.png',
            language: 'English'
        }
    }
}Code language: JavaScript (javascript)

以下示例使用 getUser() 函数访问用户资料

let user = getUser(1);
let profile = user.profile;Code language: JavaScript (javascript)

但是,如果您传递的 id 小于或等于零,或者 id 在数据库中不存在,getUser() 函数将返回 null

因此,在访问 avatar 属性之前,您需要使用 逻辑运算符 AND 检查 user 是否不为 null

let user = getUser(2);
let profile = user && user.profile;Code language: JavaScript (javascript)

在此示例中,我们确认 user 不为 nullundefined,然后才访问 user.profile 属性的值。 它可以防止在未首先检查用户的情况下直接访问 user.profile 时出现的错误。

ES2020 引入了可选链运算符,它由问号后跟一个点表示

?.Code language: JavaScript (javascript)

要使用可选链运算符访问对象的属性,请使用以下方法之一

objectName ?. propertyName
objectName ?. [expression]Code language: JavaScript (javascript)

可选链运算符隐式地检查 user 是否不为 nullundefined,然后才尝试访问 user.profile

let user = getUser(2);
let profile = user ?. profile;Code language: JavaScript (javascript)

在此示例中,如果 usernullundefined,可选链运算符 (?.) 将立即返回 undefined

从技术上讲,它等效于以下内容

let user = getUser(2);
let profile = (user !== null || user !== undefined)
            ? user.profile
            : undefined;
Code language: JavaScript (javascript)

堆叠可选链运算符

如果 getUser() 返回的 user 对象没有 profile 属性,则在没有先检查 user.profile 的情况下尝试访问 avatar 将导致错误。

为了避免错误,您可以多次使用可选链运算符,如下所示

let user = getUser(-1);
let avatar = user ?. profile ?. avatar;Code language: JavaScript (javascript)

在这种情况下,avatarundefined

与空值合并运算符结合使用

如果您想为 user 指定默认资料,可以将可选链运算符 (?.) 与空值合并运算符 (??) 结合使用,如下所示

let defaultProfile =  { default: '/default.png', language: 'English'};

let user = getUser(2);
let profile = user ?. profile ?? defaultProfile;Code language: JavaScript (javascript)

在此示例中,如果 user.profilenullundefined,由于空值合并运算符的存在,资料将采用 defaultProfile

将可选链运算符与函数调用结合使用

假设您有一个文件 API,如下所示

let file = {
    read() {
        return 'file content';
    },
    write(content) {
        console.log(`Writing ${content} to file...`);
        return true;
    }
};Code language: JavaScript (javascript)

此示例调用 file 对象的 read() 方法

let data = file.read();
console.log(data);Code language: JavaScript (javascript)

如果您调用 file 对象中不存在的方法,您将收到 TypeError

let compressedData = file.compress();Code language: JavaScript (javascript)

错误

Uncaught TypeError: file.compress is not a functionCode language: JavaScript (javascript)

但是,如果您将可选链运算符与方法调用一起使用,表达式将返回 undefined 而不是抛出错误

let compressedData = file.compress?.();Code language: JavaScript (javascript)

现在 compressedDataundefined

这在您使用 API 时很有用,在该 API 中,方法可能由于某种原因不可用,例如特定浏览器或设备。

以下示例说明了将可选链运算符与函数或方法调用一起使用的语法

functionName ?. (args)Code language: JavaScript (javascript)

可选链运算符 (?.) 在您有一个带可选 回调 的函数时也很有用

function getUser(id, callback) {
    // get user
    // ...

    let user = {
        id: id,
        username: 'admin'
    };

    // test if the callback exists
    if ( callback ) {
        callback(user);
    }

    return user;
}Code language: JavaScript (javascript)

通过使用可选链运算符,您可以跳过回调是否存在时的测试

function getUser(id, callback) {
    // get user
    // ...

    let user = {
        id: id,
        username: 'admin'
    };

    // test if the callback exists
    callback ?. (user);


    return user;
}Code language: JavaScript (javascript)

总结

  • 可选链运算符 (?.) 在您尝试访问 nullundefined 对象的属性时返回 undefined,而不是抛出错误:obj ?. property
  • 将可选链运算符 (?.) 与空值合并运算符 (??) 结合使用,以指定默认值。
  • 使用 functionName ?. (args) 避免在调用 functionName 之前显式检查它是否不为 undefinednull
本教程是否有帮助?