Серия ES2020: Почему появляется необязательная цепочка «?» и что с ней делать?

внешний интерфейс JavaScript

Необязательная цепочка "?"

дополнительная цепочка?.Безопасный способ доступа к свойствам вложенных объектов. Даже если свойство в середине не существует, ошибки не возникает.

Проблема «несуществующего имущества»

Если вы новичок в этом руководстве и изучаете JavaScript, вы, вероятно, не касались этой проблемы, но она довольно распространена.

Например, предположим, что у нас есть многоuserобъект, где хранятся наши пользовательские данные.

Адреса большинства наших пользователей хранятся вuser.address, почтовый адрес хранится вuser.address.street, но некоторые пользователи не предоставили эту информацию.

В этом случае, когда мы пытаемся получитьuser.address.street, и пользователь не предоставляет информацию об адресе, мы получаем сообщение об ошибке:

let user = {}; // 一个没有 "address" 属性的 user 对象

alert(user.address.street); // Error!

Это ожидаемый результат. Вот как работает JavaScript. потому чтоuser.addressдляundefined, попробуйте прочитатьuser.address.streetвыйдет из строя с ошибкой.

Но во многих практических сценариях мы предпочитаемundefined(имеется в виду нетstreetсвойство), а не ошибка.

...и еще один пример. В веб-разработке мы можем использовать специальные вызовы методов, такие какdocument.querySelector('.elem')) получает элемент веб-страницы как объект или возвращает, если такого объекта нетnull.

// 如果 document.querySelector('.elem') 的结果为 null,则这里不存在这个元素
let html = document.querySelector('.elem').innerHTML; // 如果 document.querySelector('.elem') 的结果为 null,则会出现错误

Аналогично, если элемент не существует, доступnullиз.innerHTMLвозникает ошибка. В некоторых случаях, когда отсутствие элемента допустимо, мы хотим избежать этой ошибки и вместо этого принятьhtml = nullкак результат.

Как мы этого добиваемся?

Вероятно, первое решение, которое приходит на ум, это использоватьifили условный оператор?Проверьте значение следующим образом:

let user = {};

alert(user.address ? user.address.street : undefined);

Это работает, и здесь нет ошибок... но недостаточно элегантно. как вы видете,"user.address"встречается в коде дважды. Для более глубоко вложенных свойств будет больше повторений этого, и это проблема.

Например, попробуем получитьuser.address.street.name.

нам нужно проверитьuser.address, опять надо проверитьuser.address.street:

let user = {}; // user 没有 address 属性

alert(user.address ? user.address.street ? user.address.street.name : null : null);

Это слишком много чепухи, и это может привести к написанию кода, который будет трудно понять другим.

Даже мы можем игнорировать эту проблему на данный момент, потому что у нас есть лучший способ сделать это, а именно использовать&&оператор:

let user = {}; // user 没有 address 属性

alert( user.address && user.address.street && user.address.street.name ); // undefined(不报错)

В свою очередь, атрибуты на всем пути оцениваются с помощью операции И, чтобы убедиться, что все узлы существуют (если нет, вычисление останавливается), но это все равно не элегантно.

Как видите, мы по-прежнему несколько раз повторяем имена свойств объекта в коде. Например, в приведенном выше кодеuser.addressЭто повторялось трижды.

Вот почему необязательная цепочка?.был добавлен в язык программирования JavaScript. То есть полностью решить все вышеперечисленные проблемы!

дополнительная цепочка

если необязательная цепочка?.Предыдущая частьundefinedилиnull, он останавливает вычисления и возвращается к этому разделу.

Для краткости в оставшейся части этой статьи мы будем говорить, что если свойство не является ниnullни одинundefined, то он "существует".

Другими словами, напримерvalue?.prop:

  • еслиvalueсуществует, результат тот же, что иvalue.propтакой же,
  • иначе (когдаvalueдляundefined/nullвремя) затем вернутьсяundefined.

Ниже приведено использование?.безопасный доступuser.address.streetПуть:

let user = {}; // user 没有 address 属性

alert( user?.address?.street ); // undefined(不报错)

Код лаконичен и понятен, нет необходимости несколько раз повторять название свойства.

даже объектuserне существует, используйтеuser?.addressНе проблема прочитать адрес:

let user = null;

alert( user?.address ); // undefined
alert( user?.address.street ); // undefined

осторожность:?.Синтаксис делает значение, предшествующее ему, необязательным, но не действует на значение, следующее за ним.

Например, вuser?.address.street.nameсередина,?.разрешатьuserдляnull/undefined, но не более того. Доступ к более глубоким свойствам осуществляется обычным способом. Если мы хотим, чтобы некоторые из них также были необязательными, нам нужно использовать больше?.заменить..

Не злоупотребляйте необязательными цепочками:

мы должны только?.Используется там, где что-то не может существовать.

Например, если согласно логике нашего кода,userобъект должен существовать, ноaddressявляется необязательным, то мы должны написатьuser.address?.street, вместо этогоuser?.address?.street.

Так что еслиuserТак уж получилось, что поскольку ошибка становится неопределенной, мы видим ошибку программирования и исправляем ее. В противном случае ошибки в коде устраняются в неподходящих местах, что затрудняет отладку.

дополнительная цепочка?.Предыдущая переменная должна быть объявлена

Если переменная не объявленаuser,Такuser?.anythingвызовет ошибку:

// ReferenceError: user is not defined
user?.address;

?.Предыдущая переменная должна быть объявлена ​​(например,let/const/var userили как параметр функции). Необязательная цепочка работает только для объявленных переменных.

эффект короткого замыкания

Как было сказано ранее, если?.Если левая часть не существует, работа немедленно останавливается («эффект короткого замыкания»).

Таким образом, если последуют какие-либо вызовы функций или побочные эффекты, ни один из них не будет выполнен.

Например:

let user = null;
let x = 0;

user?.sayHi(x++); // 没有 "sayHi",因此代码执行没有触达 x++

alert(x); // 0,值没有增加

Другие варианты: ?.(), ?.[]

дополнительная цепочка?.Не оператор, а специальная синтаксическая конструкция. Он также работает с функциями и квадратными скобками.

Например, будет?.()Используется для вызова функции, которая может не существовать.

В приведенном ниже коде у некоторых пользователейadminметод, а некоторые нет:

let userAdmin = {
  admin() {
    alert("I am admin");
  }
};

let userGuest = {};

userAdmin.admin?.(); // I am admin

userGuest.admin?.(); // 啥都没有(没有这样的方法)

В этих двух строках кода мы сначала используем запись через точку (user1.admin) получитьadminсвойство, так как пользовательский объект должен существовать, читать его безопасно.

потом?.()проверит часть слева от него: еслиadminфункция существует, затем вызовите ее для запуска (дляuser1). иначе (дляuser2) работа останавливается без ошибок.

Если мы хотим использовать квадратные скобки[]вместо записи через точку.для доступа к свойствам, синтаксису?.[]также можно использовать. Как и в предыдущем примере, он позволяет безопасно читать свойства возможно несуществующего объекта.

let user1 = {
  firstName: "John"
};

let user2 = null; // 假设,我们不能授权此用户

let key = "firstName";

alert( user1?.[key] ); // John
alert( user2?.[key] ); // undefined

alert( user1?.[key]?.something?.not?.existing); // undefined

Кроме того, мы также можем?.а такжеdeleteиспользовать вместе:

delete user?.name; // 如果 user 存在,则删除 user.name

мы можем использовать?.безопасно читать или удалять, но не писать:

дополнительная цепочка?.Не может использоваться в левой части оператора присваивания.

Например:

let user = null;

user?.name = "John"; // Error,不起作用
// 因为它在计算的是 undefined = "John"

Это еще не так умно.

Суммировать

дополнительная цепочка?.Есть три формы грамматики:

  1. obj?.prop-- еслиobjвернуть, если существуетobj.prop, иначе возвратundefined.
  2. obj?.[prop]-- еслиobjвернуть, если существуетobj[prop], иначе возвратundefined.
  3. obj.method?.()-- еслиobj.methodзвоните если естьobj.method(), иначе возвратundefined.

Как мы видели, эти синтаксические формы просты в использовании.?.Проверьте, является ли левая частьnull/undefined, если нет, продолжайте операцию.

?.Цепочки позволяют нам безопасно получать доступ к вложенным свойствам.

Тем не менее, мы должны соблюдать осторожность?., его целесообразно использовать только тогда, когда нет проблем с отсутствием левой части. Для того, чтобы в коде были программные ошибки, от нас их не скроют.


Учебники по современному JavaScript: учебные пособия по современному JavaScript с открытым исходным кодом, от начального до продвинутого.Рекомендовано официальной документацией React, учебным пособием по JavaScript вместе с MDN..

Читайте онлайн бесплатно:zh.javascript.info


Найдите общедоступный аккаунт WeChat «Technology Talk», подпишитесь на более интересный контент.