23 super practical JS skills you should know

Keywords: Javascript html5

The purpose of this paper is to help you more skillfully use JavaScript language for development.

if statement with multiple conditions

Put multiple values in an array, and then call the array.   includes   method.

// bad 👴
if (x === "abc" || x === "def" || x === "ghi" || x === "jkl") {
  //logic
}

// better 👶
if (["abc", "def", "ghi", "jkl"].includes(x)) {
  //logic
}

Simplify using conditional expressions   if true...else

// bad 👴
let test: boolean;
if (x > 100) {
  test = true;
} else {
  test = false;
}

// better 👶
let test = x > 10 ? true : false;
//Or so
let test = x > 10;

console.log(test);

False value (undefined, null, 0, false, NaN, empty string) check

When we create a new variable, we sometimes want to check whether the referenced variable is null   or   undefined or empty string   Equal false value. JavaScript does have a good shortcut to implement this check - logic or operator (|)

||Returns the right operand when the left operand is false

Only if the left side is:

  • Empty string:  '' Or``

  • NaN

  • 0

  • null

  • undefined

  • false

Logical or operator (|)   The value with the right side will be returned

// bad 👴
if (test1 !== null || test1 !== undefined || test1 !== "") {
  let test2 = test1;
}

// better 👶
let test2 = test1 || "";

// bad 👴
if (test1 === true) or if (test1 !== "") or if (test1 !== null)

// better 👶
if (test1){
  // do some
}else{
  // do other
}

Note: if   test1   If there is a value, it will be executed   if   After the logic, this operator is mainly used for   Null, undefined, empty string   Check.

Use the null merge operator -??

Only if the left side is

  • null

  • undefined

Null merge operator (?)   The value on the right is returned

const baz = 0 ?? 42;
console.log(baz);
// expected output: 0

Note: unlike the logical or operator (|), |) returns the right operand when the left operand is false

Only if the left side is:

  • Empty string:  '' Or``

  • NaN

  • 0

  • null

  • undefined

Logical or operator (|)   The value with the right side will be returned

var a = "" || 1;
//  output   one
console.log(a);

null   Check and default assignment

let test1 = null;
let test2 = test1 ?? "";

console.log("null check", test2); //  Output empty string   ""

undefined   Check and default assignment

const test = undefined ?? "default";

console.log(test);
// expected output: "default"

Return after comparison

// bad 👴
let test;
function checkReturn() {
  if (!(test === undefined)) {
    return test;
  } else {
    return callMe("test");
  }
}

// better 👶
function checkReturn() {
  return test ?? callMe("test");
}

Use the optional chain operator -

?.   Also called chain judgment operator. It allows developers to read property values deeply nested in the object chain without having to validate each reference. When the reference is empty, the expression stops evaluating and returns   undefined

const travelPlans = {
  destination: "DC",
  monday: {
    location: "National Mall",
    budget: 200,
  },
};

// bad 👴
const res =
  travelPlans &&
  travelPlans.tuesday &&
  travelPlans.tuesday.location &&
  travelPlans.tuesday.location.href;

// better 👶
//  output   undefined
const res1 = travelPlans?.tuesday?.location?.href;

& & operator for multiple conditional judgments

If the function is called only when the variable is true, you can use  && Operator.

// bad 👴
if (test1) {
  callMethod();
}

// better 👶
test1 && callMethod();

When you want to conditionally render a component in React, this is more useful than (& &) short circuit. For example:

<div> {this.state.isLoading && <Loading />} </div>

switch simplification

We can save the conditions in the key value object and call them according to the conditions.

// bad 👴
switch (data) {
  case 1:
    test1();
    break;
  case 2:
    test2();
    break;
  case 3:
    test();
    break;
  // And so on...
}

// better 👶
var data = {
  1: test1,
  2: test2,
  3: test,
};

//  If type   stay   data exists,   Then execute the corresponding function
data[type] && data[type]();

Default parameter value

// bad 👴
function add(test1, test2) {
  if (test1 === undefined) test1 = 1;
  if (test2 === undefined) test2 = 2;
  return test1 + test2;
}

// better 👶
add = (test1 = 1, test2 = 2) => test1 + test2;
add(); //output: 3

Condition finding simplification

If we want to call different methods based on different types, we can use multiple else if statements or switches, but is there a better simplification technique than this? In fact, the previous switch is simplified in the same way!

// bad 👴
if (type === "test1") {
  test1();
} else if (type === "test2") {
  test2();
} else if (type === "test3") {
  test3();
} else if (type === "test4") {
  test4();
} else {
  throw new Error("Invalid value " + type);
}

// better 👶
var types = {
  test1,
  test2,
  test3,
  test4,
};
types[type] && types[type]();

Object attribute assignment

let test1 = "a";
let test2 = "b";

// bad 👴
let obj = { test1: test1, test2: test2 };

// better 👶
let obj = { test1, test2 };

Destructuring assignment

// bad 👴
const test1 = this.data.test1;
const test2 = this.data.test2;
const test2 = this.data.test3;

// better 👶
const { test1, test2, test3 } = this.data;

Template string

If you're tired of using + to connect multiple variables into a string, this simplification technique will stop you from having a headache.

// bad 👴
const welcome = "Hi " + test1 + " " + test2 + ".";
// better 👶
const welcome = `Hi ${test1} ${test2}`;

Cross line string

// bad 👴
const data =
  "abc abc abc abc abc abc\n\t" + "test test,test test test test\n\t";
// better 👶
const data = `abc abc abc abc abc abc
         test test,test test test test`;

Simplified bitwise operation of indexOf

When looking up a value of an array, we can use   indexOf()   method. But there is a better way. Let's take a look at this example.

// bad 👴
if (arr.indexOf(item) > -1) {
  // item found
}
if (arr.indexOf(item) === -1) {
  // item not found
}
// better 👶
if (~arr.indexOf(item)) {
  // item found
}
if (!~arr.indexOf(item)) {
  // item not found
}

The bitwise (~) operator returns   true (- 1 excluded), reverse operation only needs! ~. Alternatively, you can use   includes()   Function.

if (arr.includes(item)) {
  // true if the item found
}

Convert string to number

There are built-in methods, such as parseInt and parseFloat, that can be used to convert strings to numbers. We can also simply provide a unary operator (+) before the string to achieve this.

// bad 👴
let total = parseInt("453");
let average = parseFloat("42.6");

// better 👶
let total = +"453";
let average = +"42.6";

Execute promise sequentially

What if you have a bunch of asynchronous or ordinary functions that return promise and ask you to execute one by one?

async function getData() {
  const promises = [fetch("url1"), fetch("url2"), fetch("url3"), fetch("url4")];
  for (const item of promises) {
    //  Print promise
    console.log(item);
  }

  // better 👶
  for await (const item of promises) {
    //  Print out the result of the request
    console.log(item);
  }
}

Wait for all promise s to complete

The Promise.allSettled() method accepts a set of Promise instances as parameters and wraps them into a new Promise instance. Only wait until all these parameter instances return results, whether or not   fulfilled   still   The wrapper instance will not end until it is rejected

Sometimes, we don't care about the result of asynchronous requests, only whether all requests have ended. At this point, the Promise.allSettled() method is useful

const promises = [fetch("index.html"), fetch("https://does-not-exist/")];

const results = await Promise.allSettled(promises);

// Filter out successful requests
const successfulPromises = results.filter((p) => p.status === "fulfilled");

// Filter out the failed requests and output the reason
const errors = results
  .filter((p) => p.status === "rejected")
  .map((p) => p.reason);

Swap positions of array elements

// bad 👴
const swapWay = (arr, i, j) => {
  const newArr = [...arr];

  let temp = newArr[i];

  newArr[i] = list[j];
  newArr[j] = temp;

  return newArr;
};

Starting with ES6, it became much easier to exchange values from different locations in the array

// better 👶
const swapWay = (arr, i, j) => {
  const newArr = [...arr];

 const [newArr[j],newArr[i]] = [newArr[i],newArr[j]];

  return newArr;
};

Use variables as object keys

Use it when you have a string variable and want to use it as a key in an object to set a value

let property = "a";

const obj = {
  b: "b",
};

property = "name";

obj[property] = "This is A";

//  {b:   "b",   name:   "This is A"}
console.log(obj);

Random number generator with range

Sometimes you need to generate random numbers, but if you want these numbers to be within a certain range, you can use this tool.

function randomNumber(max = 1, min = 0) {
  if (min >= max) {
    return max;
  }

  return Math.floor(Math.random() * (max - min) + min);
}

Generate random colors

function getRandomColor() {
  const colorAngle = Math.floor(Math.random() * 360);
  return `hsla(${colorAngle},100%,50%,1)`;
}

Get the last item in the list

In other languages, this function is made into a method or function that can be called in an array, but in JavaScript, you have to do some work yourself.

let array = [0, 1, 2, 3, 4, 5, 6, 7];
console.log(array.slice(-1)) >>> [7];

console.log(array.slice(-2)) >>> [6, 7];

console.log(array.slice(-3)) >>> [5, 6, 7];

function lastItem(list) {
  if (Array.isArray(list)) {
    return list.slice(-1)[0];
  }

  if (list instanceof Set) {
    return Array.from(list).slice(-1)[0];
  }

  if (list instanceof Map) {
    return Array.from(list.values()).slice(-1)[0];
  }
}

Lazy loading of pictures

In the implementation of lazy loading, there are two key values: one is the height of the current visual area, and the other is the height of the element from the top of the visual area.

The height of the current viewing area can be obtained with the window.innerHeight attribute in modern browsers and browsers above IE9. In the standard mode of low version ie, you can use document.documentElement.clientHeight to obtain it. Here we are compatible with two cases:

const viewHeight = window.innerHeight || document.documentElement.clientHeight;

For the height of the element from the top of the visual area, we use the getBoundingClientRect() method to obtain the size of the returned element and its position relative to the viewport. MDN gives a very clear explanation for this:

The return value of this method is a DOMRect object, which is a collection of rectangles returned by the getClientRects() method of the element, that is, a collection of CSS borders related to the element.

The DOMRect object contains a set of read-only properties -- left, top, right, and bottom -- that describe the border in pixels. All attributes except width and height are relative to the upper left corner of the viewport.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Lazy-Load</title>
    <style>
      .img {
        width: 200px;
        height: 200px;
        background-color: gray;
      }
      .pic {
        //  Required img styles
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="img">
        //  Note that we did not introduce real src for it
        <img class="pic" alt="Loading" data-src="./images/1.png" />
      </div>
      <div class="img">
        <img class="pic" alt="Loading" data-src="./images/2.png" />
      </div>
      <div class="img">
        <img class="pic" alt="Loading" data-src="./images/3.png" />
      </div>
      <div class="img">
        <img class="pic" alt="Loading" data-src="./images/4.png" />
      </div>
      <div class="img">
        <img class="pic" alt="Loading" data-src="./images/5.png" />
      </div>
      <div class="img">
        <img class="pic" alt="Loading" data-src="./images/6.png" />
      </div>
      <div class="img">
        <img class="pic" alt="Loading" data-src="./images/7.png" />
      </div>
      <div class="img">
        <img class="pic" alt="Loading" data-src="./images/8.png" />
      </div>
      <div class="img">
        <img class="pic" alt="Loading" data-src="./images/9.png" />
      </div>
      <div class="img">
        <img class="pic" alt="Loading" data-src="./images/10.png" />
      </div>
    </div>
  </body>
</html>

<script>
    //  Get all picture labels
    const imgs = document.getElementsByTagName('img')
    //  Gets the height of the visible area
    const viewHeight = window.innerHeight || document.documentElement.clientHeight
    //  num is used to count which picture is currently displayed to avoid checking whether it is exposed from the first picture every time
    let num = 0
    function lazyload(){
        for(let i=num; i<imgs.length; i++) {
            //  Subtract the height of the top of the element from the top of the visible area by the height of the visible area
            let distance = viewHeight - imgs[i].getBoundingClientRect().top
            //  If the height of the visible area is greater than or equal to the height from the top of the element to the top of the visible area, the element is exposed
            if(distance >= 0 ){
                //  Write real src to the element and show the image
                imgs[i].src = imgs[i].getAttribute('data-src')
                //  The first i pictures have been loaded. Next time, check whether they are exposed from i+1
                num = i + 1
            }
        }
    }
    //  Listen for Scroll events
    window.addEventListener('scroll', lazyload, false);
</script>


Picture preload

class PreLoadImage {
  constructor(imgNode) {
    //  Get the real DOM node
    this.imgNode = imgNode;
  }

  //  src attribute of operation img node
  setSrc(imgUrl) {
    this.imgNode.src = imgUrl;
  }
}

class ProxyImage {
  //  url address of bitmap
  static LOADING_URL = "xxxxxx";

  constructor(targetImage) {
    //  The target Image is the PreLoadImage instance
    this.targetImage = targetImage;
  }

  //  This method mainly operates the virtual Image to complete the loading
  setSrc(targetUrl) {
    //  When the real img node is initialized, a bitmap is displayed
    this.targetImage.setSrc(ProxyImage.LOADING_URL);
    //  Create a virtual Image instance to help us load pictures
    const virtualImage = new Image();
    //  Listen to the loading of the target image, and set the src attribute of the real img node on the DOM as the url of the target image when it is completed
    virtualImage.onload = () => {
      this.targetImage.setSrc(targetUrl);
    };
    //  Set the src property and the virtual Image instance starts loading pictures
    virtualImage.src = targetUrl;
  }
}

ProxyImage helps us schedule the work related to preloading. Through ProxyImage, we can achieve indirect access to real img nodes and get the desired effect.

Posted by jeremywesselman on Sat, 02 Oct 2021 17:30:05 -0700