Необязательная цепочка ES2020: в чем разница между a?. (). B и a () ?. b и a?. () ?. b - PullRequest
1 голос
/ 19 июня 2020

Предположим, у нас есть этот объект:

let obj = {};

Что именно делает каждое из этих выражений?

  • obj.a?.().b
  • obj.a()?.b
  • obj.a?.()?.b

Ответы [ 4 ]

4 голосов
/ 19 июня 2020

obj.a?.().b - Если obj.a равно null или undefined, тогда выражение равно undefined, иначе выражение оценивается как obj.a().b.

obj.a()?.b - Если obj.a() равно null или undefined, тогда выражение будет undefined, иначе выражение оценивается как obj.a().b

obj.a?.()?.b, если obj.a или obj.a() равно null или undefined, тогда выражение равно undefined в противном случае выражение оценивается как obj.a().b.

Подробнее о необязательной цепочке здесь .

3 голосов
/ 19 июня 2020

obj.a?.().b

  1. Разыменование obj напрямую.

  2. Разыменование obj.a нулевым способом - он остановится на этом месте, если свойства там нет, это undefined или null. Если это произойдет, результатом вычисления выражения будет undefined.

  3. Выполнить это значение напрямую.

  4. Получить возврат результат и продолжить.

  5. Получить свойство b напрямую из результата.

Flowchart for the above process

const tryIt = obj => {
  console.log("------start------");

  console.log("trying with", obj );

  try {
    console.log( "result", obj.a?.().b );
  } catch (e) {
    console.error("problem", e.message);
  }

  console.log("-------end-------");
}

tryIt( null );                 // ERROR
tryIt( {} );                   // undefined
tryIt( { a: undefined } );     // undefined
tryIt( { a: null } );          // undefined
tryIt( { a: false } );         // ERROR
tryIt( { a: "hello" } );       // ERROR
tryIt( { a: function() {} } ); // ERROR
tryIt( {                       // ERROR
  a: function() {
    return null; 
  }
});
tryIt( {                       // 42
  a: function() {
    return { b: 42 };
  }
});

obj.a()?.b

  1. Разыменование obj напрямую.

  2. Разыменование obj.a напрямую.

  3. Выполнение этого значения напрямую.

  4. Обработка значения нулевым безопасным способом - остановится на эта точка, если возвращаемое значение null или undefined. Если это произойдет, результатом вычисления выражения будет undefined.

  5. Получить свойство b напрямую из результата.

Flowchart for the above process

const tryIt = obj => {
  console.log("------start------");

  console.log("trying with", obj );

  try {
    console.log( "result", obj.a()?.b );
  } catch (e) {
    console.error("problem", e.message);
  }

  console.log("-------end-------");
}


tryIt( null );                 // ERROR
tryIt( {} );                   // ERROR
tryIt( { a: undefined } );     // ERROR
tryIt( { a: null } );          // ERROR
tryIt( { a: false } );         // ERROR
tryIt( { a: "hello" } );       // ERROR
tryIt( { a: function() {} } ); // undefined
tryIt( {                       // undefined
  a: function() {
    return null; 
  }
});
tryIt( {                       // 42
  a: function() {
    return { b: 42 };
  }
});

obj.a?.()?.b

  1. Разыменование obj напрямую.

  2. Разыменование obj.a безопасным для нуля способом - он остановится на этом этапе, если свойство отсутствует, это undefined или null. Если это произойдет, результатом вычисления выражения будет undefined.

  3. Выполнение этого значения напрямую.

  4. Обработка значения безопасным для нуля способом - он остановится на этом этапе, если возвращаемое значение null или undefined. Если это произойдет, результатом вычисления выражения будет undefined.

  5. Получить свойство b напрямую из результата.

enter image description here

const tryIt = obj => {
  console.log("------start------");

  console.log("trying with", obj );

  try {
    console.log( "result", obj.a?.()?.b );
  } catch (e) {
    console.error("problem", e.message);
  }

  console.log("-------end-------");
}


tryIt( null );                 // ERROR
tryIt( {} );                   // undefined
tryIt( { a: undefined } );     // undefined
tryIt( { a: null } );          // undefined
tryIt( { a: false } );         // ERROR
tryIt( { a: "hello" } );       // ERROR
tryIt( { a: function() {} } ); // undefined
tryIt( {                       // undefined
  a: function() {
    return null; 
  }
});
tryIt( {                       // 42
  a: function() {
    return { b: 42 };
  }
});
2 голосов
/ 20 июня 2020

TL; TR

Выражение проверяется на наличие non-undefined, not-null значений с помощью ? и в любой момент, если обнаруживается одно из этих значений, цепочка просто разрывается и возвращает undefined.

Очень важно отметить, что она защищает только от значений undefined и null, а не от ложности значения, т.е. он все равно будет передавать другие ложные значения, такие как NaN или "".

Длинное объяснение

Начнем с цитирования MDN

Необязательный оператор цепочки предоставляет способ упростить доступ к значениям через подключенные объекты, когда возможно, что ссылка или функция могут быть неопределенными или нулевыми.

Рассмотрим такой объект:

 var obj = {
       a: {
           b: 1
       },
     }

Теперь для проверки obj, obj peroperty a, а затем свойства a b как undefined и null, вам может потребоваться сделайте что-нибудь вроде этого:

 obj && obj.a && obj.a.b

Дополнительное связывание предоставляет вам альтернативу этому. Вы можете просто сделать это так:

obj?.a?.b

Теперь предположим, что a оказывается функцией, которая возвращает объект со свойством b, которое содержит значение 1. Примерно так:

 var obj = {
           a: function{
               return {b:1}
            },
       }

Итак, как вы теперь проверяете obj и его поля для глубоко вложенных b? Что ж, вы можете сделать что-то вроде этого:

obj && obj.a && typeof obj.a === 'function' && obj.a() && obj.a().b

Или вы можете просто сделать

obj?.a()?.b

Это просто означает проверку obj на наличие неопределенных и ненулевых значений (если это), затем проверьте obj?.a() на то же самое, (если это так) выполните метод a() obj. Если после выполнения метод возвращает значение (которое не является undefined или null), тогда получите из него значение свойства b.

В любой момент во время этой проверки , если будет найдено значение undefined или null, просто разорвите цепочку и верните undefined

Однако это не удастся, если a не является функцией, которая было проверено с помощью typeof obj.a === 'function' в предыдущем выражении. Также обратите внимание, что на этом этапе, если obj.a() вернет, скажем, «baz», он будет выполнен как "baz".b, что даст вам undefined.

С этими знаниями мы можем расшифровать это выражение легко:

   obj.a?.().b

Оно проверяет, соответствует ли obj.a non-undefined, not-null. Если это так, выполните obj.a () (обратите внимание, что он выдаст ошибку, если obj.a не является функцией, но возвращает, скажем, число 5)

Если obj.a() происходит, выполните успешно, тогда .b перенастроенного значения будет проверено.

Теперь это осталось

obj.a?.()?.b

Ну, это также выполняется так же, как и наши предыдущие исполнения:

проверка obj.a, если это not-null и non-undefined. Если это так, выполните obj.a. Если это также non-null и non-undefined, выполните obj.a() и т. Д.

Если в любой момент во время проверки будет обнаружено значение null или undefined, цепочка просто разорвется .

Очень важно отметить, что наш оператор ? защищает только от undefined и null, а не от других ложных значений.

Учитывайте это

var a = undefined
var myVal = a?.details.b;
alert(a) //will return undefined

var a = ""
var myVal = a?.details.b;
alert(a) //Our guard fails us here and simply throws an error
2 голосов
/ 19 июня 2020

Оператор необязательного связывания может использоваться в трех местах:

  1. Вместо оператора точки для доступа к собственности (obj?.a)
  2. Немедленно перед синтаксисом скобок для доступа к свойству (obj?.['a'])
  3. Непосредственно перед вызовом функции (obj.a?.())

В позиции доступа к свойству , если значение свойства равно nulli sh (ie. null или undefined), затем оно немедленно замыкает все выражение и возвращает undefined.

в функции позиция вызова , если функция имеет значение nulli sh, то она немедленно замыкает все выражение и возвращает undefined (тем самым избегая исключения «undefined is not a function»).

Итак:

  • obj.a?.().b вернет undefined, если obj.a равно нулю sh.

  • obj.a()?.b вернет undefined, если результат obj.a().b равен нулю sh.

  • obj.a?.()?.b вернет undefined, если a равно нулю sh, или если результат obj.a() равен нулю sh.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...