Benefits of JS optional chains

Posted by greatme on Mon, 26 Aug 2019 03:15:21 +0200

To ensure readability, this paper uses free translation instead of literal translation.

To read more high-quality articles, stamp the GitHub blog, and over a hundred high-quality articles are waiting for you a year!

Some of the features of JS have dramatically changed the way we code.Solutions, arrow functions, classes, and module systems that have the greatest impact on our code since ES6.

By August 2019, a new alternative chain proposal has entered the third stage, which is a good improvement.Optional links change the way attributes are accessed from deep object structures.

Let's see what this is.

This week, Daqian World has a draw with prizes: column "Hearing the Wind in the Left Ear" x3, technical book x5. Welcome to Reply: Draw Prizes

problem

Because of the dynamic nature of JS, objects can have many different layers of nested object structure.

Usually, when we deal with the following objects:

  • Get remote JSON data
  • Use Configuration Objects
  • Has optional properties

Although JS supports different hierarchies of data structures for objects, the complexity increases when accessing the properties of such objects.

bigObject can have different sets of properties at runtime

// Nested Version
const bigObject = {
  // ...
  prop1: {
    //...
    prop2: {
      // ...
      value: 'Some value'
    }
  }
};

// Simple version
const bigObject = {
  // ...
  prop1: {
    // Nothing here   
  }
};

Therefore, you must manually check for the existence of attributes

if (bigObject && 
    bigObject.prop1 != null && 
    bigObject.prop1.prop2 != null) {
  let result = bigObject.prop1.prop2.value;
}

This is too long to write, so it's best to avoid it.

Let's see how the optional chain solves this problem to reduce redundant code.

2. Easy in-depth access to properties

Design an object to hold movie information.The object contains the required title property, as well as optional director s and actors.

The movieSmall object only contains title, while movieFull contains the complete set of properties:

const movieSmall = {
  title: 'Heat'
};

const movieFull = {
  title: 'Blade Runner',
  director: { name: 'Ridley Scott' },
  actors: [{ name: 'Harrison Ford' }, { name: 'Rutger Hauer' }]
};

Write a function to get the directory.Keep in mind that directors may not exist.

function getDirector(movie) {
  if (movie.director != null) {
    return movie.director.name;
  }
}

getDirector(movieSmall); // => undefined
getDirector(movieFull);  // => 'Ridley Scott'

The if(movie.director){...} condition is used to verify that the directory property is defined.Without this precaution, when accessing the directory of the movieSmall object, the JS throws TypeError: Cannot read property'name'of undefined.

This scenario is best suited to use the functionality of the optional chain, as shown below, where the code is much simpler.

function getDirector(movie) {
  return movie.director?.name;
}

getDirector(movieSmall); // => undefined
getDirector(movieFull);  // => 'Ridley Scott'

Can be found in the movie.director?.name expression?: Optional link operator.

In movieSmall, there is no directory attribute.So, movie.director?The result of.Name is undefined.Optional chain operators prevent throwing TypeError: Cannot read property'name'of undefined.

Simply put, snippets:

let name = movie.director?.name;

Equivalent to

let name;
if (movie.director != null) {
  name = movie.director.name;
}

?. Simplify the getDirector() function by reducing two lines of code, which is why I like the optional chain.

2.1 Array Items

Optional chain functionality can do more.You can freely use multiple optional link operators in the same expression, and you can even use them to safely access array items.

The next task is to write a function that returns the name from the actors in the movie.

In a movie object, the actors array can be empty or even missing, so additional criteria must be added to make it empty.

function getLeadingActor(movie) {
  if (movie.actors && movie.actors.length > 0) {
    return movie.actors[0].name;
  }
}

getLeadingActor(movieSmall); // => undefined
getLeadingActor(movieFull);  // => 'Harrison Ford'

The if (movie.actors && movies.actors.length > 0) {...} condition mainly determines that movies contain actors and that there is at least one actor for this property.

With optional links, the code is also concise, as follows:

function getLeadingActor(movie) {
  return movie.actors?.[0]?.name;
}

getLeadingActor(movieSmall); // => undefined
getLeadingActor(movieFull);  // => 'Harrison Ford'

Actors?.Make sure the actors attribute exists, [0]?.Make sure the first actor exists in the list.

3.nullish coalescing

A name is nullish coalescing operator New proposal?Handle undefined or null and default them to specific values.

Expression variable?? If the variable undefined or null, the default value is the specified value.

const noValue = undefined;
const value = 'Hello';

noValue ?? 'Nothing'; // => 'Nothing'
value   ?? 'Nothing'; // => 'Hello'

Next, use?? to optimize the getLeading() function to return "Unknown actor" when there is no actor in the movie object

function getLeadingActor(movie) {
  return movie.actors?.[0]?.name ?? 'Unknown actor';
}

getLeadingActor(movieSmall); // => 'Unknown actor'
getLeadingActor(movieFull);  // => 'Harrison Ford'

4. Three forms of optional chains

We can use the following three types of optional chains.

First, object?.property is used to access static properties:

const object = null;
object?.property; // => undefined

Second, object?.[expression] is used to access dynamic properties or array items:

// firstly
const object = null;
const name = 'property';
object?.[name]; // => undefined
// second
const array = null;
array?.[0]; // => undefined

Third: object?.([arg1, [arg2,...]) Executes an object method

const object = null;
object?.method('Some value'); // => undefined

Combine the three to create an optional chain:

const value = object.maybeUndefinedProp?.maybeNull()?.[propName];

5. Short circuit: encountered null/undefined stop

The interesting thing about the optional link operator is that as long as it's on the left leftHandSide?When.rightHandSide encounters an invalid value, right-hand access stops, which is called short-circuit.

Take an example:

const nothing = null;
let index = 0;

nothing?.[index++]; // => undefined
index;              // => 0

6. When to use optional chains

Do not rush to use the optional chain operator to access any type of property: this can lead to incorrect use.

6.1 Accessing potentially invalid properties

?.Typically used for attributes that may be empty: maybeNullish?.prop.Use the property accessor:.Property or [propExpression] when you are certain that the property is not empty.

// good
function logMovie(movie) {
  console.log(movie.director?.name);
  console.log(movie.title);
}

// not good
function logMovie(movie) {
  // director needs optional chaining
  console.log(movie.director.name);

  // movie doesn't need optional chaining
  console.log(movie?.title);
}

6.2 There are usually better choices

The following function hasPadding() receives a style object for an optional padding attribute.Padding has left, top, right, bottom optional attributes.

Try using the optional chain operator:

function hasPadding({ padding }) {
  const top = padding?.top ?? 0;
  const right = padding?.right ?? 0;
  const bottom = padding?.bottom ?? 0;
  const left = padding?.left ?? 0;
  return left + top + right + bottom !== 0;
}

hasPadding({ color: 'black' });        // => false
hasPadding({ padding: { left: 0 } });  // => false
hasPadding({ padding: { right: 10 }}); // => true

Although the function correctly determines whether an element has a padding, using an optional chain for each attribute is a little too cumbersome.

A better way is to default the padding object to zero using the object extension operator

function hasPadding({ padding }) {
  const p = {
    top: 0,
    right: 0,
    bottom: 0,
    left: 0,
    ...padding
  };
  return p.top + p.left + p.right + p.bottom !== 0;
}

hasPadding({ color: 'black' });        // => false
hasPadding({ padding: { left: 0 } });  // => false
hasPadding({ padding: { right: 10 }}); // => true

This is simpler than the optional chain.

BUGs that may exist after code deployment are not known in real time. In order to solve these BUGs afterwards, a lot of time has been spent debugging the log. By the way, a useful BUG monitoring tool is recommended. Fundebug.

Communication

The dry goods series articles are summarized below, feel good to order Star, welcome to join the group to learn from each other.

https://github.com/qq44924588...

I am Xiao Zhi, the author of the public number "Move the World", a fan of keeping learning about front-end technology.I often share what I've learned and what I've seen. On the way to the next level, I'll reluctantly!

Focus on the public number and reply to the benefits in the background. You can see the benefits, you know.

Topics: Javascript Attribute github JSON