Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”

In our daily development process, we will see the Cannot Read Property of undefined error in the console when the data returned by the interface does not meet the expectations when the code is not carefully selected

Error code:

const obj = {
  name: 'nordon'.info: {
    age: ' '}};if(obj.msg.age === 18) { // Uncaught TypeError: Cannot read properties of undefined (reading 'age')
  console.log('Age 18')}Copy the code

Because obj. MSG is undefined, the age attribute does not exist. Therefore, in the development process, we need to ensure that the result of each value needs to be verified during the value process, and only the result of each value meets the expectation can we perform the value operation

Common handling methods:

The && short-circuit operator performs accessibility sniffing:

if(obj.msg && obj.msg.age === 18) {}
Copy the code

| | unit to set the default guaranteed value:

if((obj.msg || {}).age === 18) {}
Copy the code

Try catch:

try {
    if(obj.msg.age === 18) {}}catch {
    // todo ...
}
Copy the code

Two ways above && and | | for simple data structure, relatively simple and intuitive, second try catch the way to the code of invasive high, not too frequent use, and our value is a very high frequency operation, could not every value to add try catch for fault tolerance

If there is deep nested structure:

const obj = {
    user: {
        info: {
            hobbys: {
                sports: [{value: "basketball".label: "Basketball"}, {value: "football".label: "Football",},],},},},},};Copy the code

At this time if use && and | | way code robustness processing:

if(
  obj &&
  obj.user &&
  obj.user.info &&
  obj.user.info.hobbys &&
  obj.user.info.hobbys.sports &&
  obj.user.info.hobbys.sports[1] &&
  obj.user.info.hobbys.sports[1].value === 'basketball'
) {
   // todo...
}
Copy the code

Look at the above of judgment, is the mood was not good, so && and | | way will make the code becomes swollen, is not very appropriate, you can manually wrap a gain value according to the incoming data

Manual wrapping function:

/** * keys: array, according to the hierarchy * source: data source */
const getValue = (keys, source) = > {
    return keys.reduce((nextObj, key) = > {
        return nextObj && nextObj[key] ? nextObj[key] : null;
    }, source);
};
Copy the code

Usage:

getValue(["user"."info"."hobbys"."sports"[1]], obj); // {value: 'football', label: 'football'}
getValue(["user"."info"."hobbys"[1]], obj); // null
Copy the code

Optional chaining operator:

The optional chain operator (? .) allows you to read the value of a property located deep in the chain of connected objects without explicitly validating that each reference in the chain is valid. ? The. Operator functions like the. Chain operator, except that it does not cause errors when references are nullish (null or undefined), and the short-circuit returns undefined. When used with a function call, returns undefined if the given function does not exist.

Use grammar:

const obj = {
  foo: {
    bar: {
      baz: 42,}}};constbaz = obj? .foo? .bar? .baz;/ / 42
constsafe = obj? .qux? .baz;// undefined
Copy the code

Used in Babel:

Download:

npm install --save-dev @babel/plugin-proposal-optional-chaining
Copy the code

Configure in a configuration file, such as babel.config.js

{
  "plugins": ["@babel/plugin-proposal-optional-chaining"]}Copy the code

Then you can happily use it in your project