Длинные цепочки вызовов в JavaScript могут быть подвержены ошибкам, потому что может произойти любой шаг.null
илиundefined
(также известное как «недопустимое» значение). Проверка существования свойств на каждом шаге может легко стать глубоко вложенной.if
Объявите или скопируйте длинные цепочки доступа к свойствамif
условие:
// 容易出错的版本,可能抛出错误
const nameLength = db.user.name.length;
// 不容易出错,但是难以阅读
let nameLength;
if (db && db.user && db.user.name)
nameLength = db.user.name.length;
Вышеприведенное также может использовать троичное выражение, но его так же трудно читать:
const nameLength =
(db
? (db.user
? (db.user.name
? db.user.name.length
: undefined)
: undefined)
: undefined);
Представляем необязательные цепочки вызовов
Мы не хотим писать такой код, поэтому желательны некоторые альтернативы. Некоторые языки (например, swift, подробнее см. https://www.jianshu.com/p/5599b422afb0) предоставляют элегантное решение этой проблемы — необязательное связывание вызовов.
согласно снедавняя норма, "Необязательная цепочка вызовов — это цепочка из одного или нескольких обращений к свойствам и вызовов функций, начинающаяся с?.
начало".
Используя новую дополнительную цепочку вызовов, мы можем переписать демо выше:
// 依然检查错误,但是可读性更高
const nameLength = db?.user?.name?.length;
С дополнительной цепочкой вызовов, когдаdb
,user
,илиname
даundefined
илиnull
когда,nameLength
Быть инициализированнымundefined
Бросить ошибку раньше, но не вроде.
**Примечание.** Дополнительная цепочка вызовов более эффективна, чем наша собственная.if(db && db.user && db.user.name)
Проверка более надежна, например, еслиname
является пустой строкой, необязательные строки будутname?.length
изменить наname.length
Затем получите правильную длину0
, но если мы сделаем то же самое, что и раньше, мы не получим правильное значение, потому что в операторе if нулевой символ иfalse
ведет себя так же. Необязательная цепочка вызовов исправляет эту распространенную ошибку.
Другие формы синтаксиса: вызовы и динамические свойства
Также есть оператор для вызова необязательных методов:
// 使用可选方法扩展接口,仅适用于管理员用户
const adminOption = db?.user?.validateAdminAndGetPrefs?.().option;
Этот синтаксис может быть немного неожиданным, так как операторы здесь?.()
, что относится к предыдущему выражению.
Существует третье использование необязательной цепочки вызовов, необязательный динамический доступ к свойствам.?.[]
. Если в объекте есть значение, соответствующее ключу, вернуть значение, иначе вернутьundefined
. Демонстрация выглядит следующим образом:
// 使用动态属性名访问属性对应的值
const optionName = 'optional setting';
const optionLength = db?.user?.preferences?.[optionName].length;
То же самое относится и к необязательным индексированным массивам, например:
// 如果`userArray`是`null`或`undefined`,则`userName`被优雅的赋值为`undefined`
const userIndex = 42;
const userName = usersArray?.[userIndex].name;
Необязательную цепочку вызовов можно комбинировать снулевой объединяющий оператор ??используется в комбинации, возвращаетundefined
Значение по умолчанию. Доступ к этому можно получить, используя указанную безопасность по умолчанию, и решает проблему, которую пользователь может решить, например, с помощью библиотеки JavaScript._.получить Лодаш:
const object = { id: 123, names: { first: 'Alice', last: 'Smith' }};
{ // With lodash:
const firstName = _.get(object, 'names.first');
// → 'Alice'
const middleName = _.get(object, 'names.middle', '(no middle name)');
// → '(no middle name)'
}
{ // With optional chaining and nullish coalescing:
const firstName = object?.names?.first ?? '(no first name)';
// → 'Alice'
const middleName = object?.names?.middle ?? '(no middle name)';
// → '(no middle name)'
}
Необязательные свойства цепочки вызовов
Необязательные цепочки вызовов обладают некоторыми интересными свойствами:короткое замыкание,укладкаа такженеобязательное удаление. Давайте используем пример, чтобы понять эти свойства.
* Короткое замыкание * I.e. Остальная часть выражения не оценивается, если дополнительная цепь вызовов возвращает рано:
// 只有在`db`和`user`不是`undefined`的情况下`age`才会+1
db?.user?.grow(++age);
// 一个可选链可以跟随另一个可选链
const firstNameLength = db.users?.[42]?.names.first.length;
Однако рассмотрите возможность использования нескольких необязательных операторов вызова в цепочке. Если значение гарантировано допустимо, его использование не рекомендуется.?.
для доступа к свойствам. Как и в предыдущем примере,db
должны быть определены, ноdb.users
а такжеdb.users[42]
Может быть неопределенным. Если такой пользователь есть в базе, тоname.first.length
также всегда определен.
*необязательное удаление* естьdelete
Операторы можно использовать с необязательным связыванием:
// 当且仅当`db`是定义过的时候删除`db.user`
delete db?.user;
Доступ к более подробной информации можно получитьСмысловая часть предложения.
Оригинальная ссылка:V8.dev/features/op...