When you’re writing code, there’s always something that happens over and over again, and you start looking for shortcuts. Many of these problems can be solved without even installing libraries. Here are the top 25 shortcuts and tricks I’ve collected over the years.

1. Type checking gadget

JavaScript is not a strongly typed language, and the best solution I recommend is TypeScript. But sometimes you just want a simple type check, and JavaScript allows you to use the “typeof” keyword.

The problem with “typeof” is that it works well with certain primitives and functions, but with arrays and objects, because they are both considered “objects,” it’s hard to know the difference.

const isOfType = (() = > { 
   // create a plain object with no prototype  
  const type = Object.create(null);  
  // check for null type  
  type.null = x= > x === null;  
  // check for undefined type  
  type.undefined = x= > x === undefined;  
  // check for nil type. Either null or undefined  
  type.nil = x= > type.null(x) || type.undefined(x);  
  // check for strings and string literal type. e.g: 's', "s", `str`, new String()  
  type.string = x= >! type.nil(x) && (typeof x === 'string' || x instanceof String); 
  // check for number or number literal type. LLDB: 12, 30.5, new number ()
  type.number = x= >! type.nil(x) && (// NaN & Infinity have typeof "number" and this excludes that
      (!isNaN(x) && isFinite(x)
      && typeof x === 'number'
    ) || x instanceof Number);
  // check for boolean or boolean literal type. e.g: true, false, new Boolean()
  type.boolean = x= >! type.nil(x) && (typeof x === 'boolean' || x instanceof Boolean);
  // check for array type
  type.array = x= >! type.nil(x) &&Array.isArray(x);
  // check for object or object literal type. e.g: {}, new Object(), Object.create(null)
  type.object = x= > ({}).toString.call(x) === '[object Object]';
  // check for provided type instance
  type.type = (x, X) = >! type.nil(x) && xinstanceof X;
  // check for set type
  type.set = x= > type.type(x, Set);
  // check for map type
  type.map = x= > type.type(x, Map);
  // check for date type
  type.date = x= > type.type(x, Date);
  returntype; }) ();Copy the code

2. Check whether the port is empty

Sometimes you need to know if something is empty and decide which method to use based on the result, such as checking for length, size, or whether it contains any child elements. The following tool packages these functions and allows you to check the size of strings, Objects, arrays, maps, and sets.

function isEmpty(x) {
  if(Array.isArray(x)
    || typeof x === 'string'
    || x instanceof String
   ) {
    return x.length === 0;
  }
  if(x instanceof Map || x instanceof Set) {
    return x.size === 0;
  }
  if(({}).toString.call(x) === '[object Object]') {
    return Object.keys(x).length === 0;
  }
  return false;
}
Copy the code

3. Get the last item in the list

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

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]; }}Copy the code

4. Random number generator with range

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

function randomNumber(max = 1, min = 0) {
  if(min >= max) {
    return max;
  }
  return Math.floor(Math.random() * (max - min) + min);
}
Copy the code

5. Random ID generator

Sometimes you just need some ID, right? Unless you want a more complex ID generator (such as a UUID), you don’t need to install a new library for this, and this option will suffice. You can start with the current time (in milliseconds) or specific integers and increments, or you can generate ids from letters.

// create unique id starting from current time in milliseconds
// incrementing it by 1 everytime requested
const uniqueId = (() = > {
  const id = (function* () {
    let mil = new Date().getTime();
    while (true)
      yield mil += 1; }) ();return () = >id.next().value; }) ();// create unique incrementing id starting from provided value or zero
// good for temporary things or things that id resets
const uniqueIncrementingId = ((lastId = 0) = > {
  const id = (function* () {
    let numb = lastId;
    while (true)
      yield numb += 1; }) ()return (length = 12) = > `${id.next().value}`.padStart(length, '0'); }) ();// create unique id from letters and numbers
const uniqueAlphaNumericId = (() = > {
  const heyStack = '0123456789abcdefghijklmnopqrstuvwxyz';
  const randomInt = () = > Math.floor(Math.random() * Math.floor(heyStack.length))
  return (length = 24) = > Array.from({length}, () = > heyStack[randomInt()]).join(' '); }) ();Copy the code

6. Create a range of numbers

One of my favorite Python features, which I often have to write myself in JavaScript, is the range function. Here is a simple implementation, perfect for… Of loops and situations where numbers in a particular range are required.

function range(maxOrStart, end = null, step = null) {
  if(! end) {return Array.from({length: maxOrStart}, (_, i) = > i)
  }
  if(end <= maxOrStart) {
    return [];
  }
  if(step ! = =null) {
    return Array.from(
      {length: Math.ceil(((end - maxOrStart) / step))},
      (_, i) = > (i * step) + maxOrStart    );
  }
  return Array.from(
    {length: Math.ceil((end - maxOrStart))},
    (_, i) = > i + maxOrStart  );
}
Copy the code

7. Format a JSON string and stringify anything

I often use this method when logging objects to the console using NodeJs. The json.stringify method requires a third argument, which must be indented with multiple Spaces. The second argument can be null, but you can use it to handle things like function, Set, Map, Symbol, etc. Json.stringify methods cannot handle or ignore completely.

const stringify = (() = > {
  const replacer = (key, val) = > {
    if(typeof val === 'symbol') {
      return val.toString();
    }
    if(val instanceof Set) {
      return Array.from(val);
    }
    if(val instanceof Map) {
      return Array.from(val.entries());
    }
    if(typeof val === 'function') {
      return val.toString();
    }
    return val;
  }
  return (obj, spaces = 0) = > JSON.stringify(obj, replacer, spaces)
})();
Copy the code

8. Implement promises sequentially

This tool can be useful if you have a bunch of asynchronous or ordinary functions that all return promises and require you to execute them one by one. It takes a list of functions or promises and parses them in order using the array Reduce method.

const asyncSequentializer = (() = > {
  const toPromise = (x) = > {
    if(x instanceof Promise) { // if promise just return it
      return x;
    }
    if(typeof x === 'function') {
      // if function is not async this will turn its result into a promise
      // if it is async this will await for the result
      return (async() = >await x())();
    }
    return Promise.resolve(x)
  }
  return (list) = > {
    const results = [];
    return list
      .reduce((lastPromise, currentPromise) = > {
        return lastPromise.then(res= > {
          results.push(res); // collect the results
          return toPromise(currentPromise);
        });
      }, toPromise(list.shift()))
      // collect the final result and return the array of results as resolved promise
      .then(res= > Promise.resolve([...results, res]));
  }
})();
Copy the code

9. Poll data

If you need to constantly check for data updates and there is no WebSocket on your system, you can use this tool to do so. It’s great for uploading files and you want to constantly check if the file has been processed, or if you’re using a third-party API (such as Dropbox or Uber) and you want to constantly check if the process is complete or the rider has arrived at his destination.

async function poll(fn, validate, interval = 2500) {
  const resolver = async (resolve, reject) => {
    try { // catch any error thrown by the "fn" function
      const result = await fn(); // fn does not need to be asynchronous or return promise
      // call validator to see if the data is at the state to stop the polling
      const valid = validate(result);
      if (valid === true) {
        resolve(result);
      } else if (valid === false) {
        setTimeout(resolver, interval, resolve, reject);
      } // if validator returns anything other than "true" or "false" it stops polling
    } catch(e) { reject(e); }};return new Promise(resolver);
}
Copy the code

10. Wait for all promises to be fulfilled

This isn’t so much a code solution as an enhancement to the Promise API. The API is evolving. I used to code “allSettled”, “Race” and “any”, but now I just use the API.

11. Swap the positions of array values

Starting with ES6, swapping values from different locations in the array is much easier. It’s not hard to do, but it’s good to know,

12. Conditional object keys

This tip is my favorite, and I use it a lot when updating status with React. You can conditionally insert a key into a spread object by wrapping conditions in parentheses.

13. Use variables as object keys

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

14. Check the keys in the object

This is a good technique to help you check the object keys.

15. Delete array duplicates

Arrays often have duplicate values, which you can eliminate using the Set data structure. It works with many data types, and sets have a variety of ways to check for equality, which is handy. In the case of different instances or objects, you can still use sets to track specific things and filter out duplicate objects.

16. Execute ‘break’ and ‘continue’ in ArrayforEach

I really like using the array “.foreach “method, but sometimes I need to exit early or continue through the next loop rather than using for… Loop. You can copy the “continue” statement behavior to return earlier, but to copy the “break” behavior, you need to use the array “.some “method.

17. Use alias and default values to destroy

Destructuring is one of JavaScript’s most useful features, and you can use “colon” to set aliases and “equal” to set property defaults.

18. Optional chain and null value merge

When you drill down into object properties and deal with null and undefined values, you can use several very handy JavaScript features to solve common problems.

19. Extend classes with functions

I often tell people that JavaScript classes are just constructors and low-level prototypes, not real concepts like they are in Java. One proof is that you can extend a class with just one constructor. This works fine in private content, looks weird in classes, and compiles less code when used with Babel or WebPack.

Extend constructors

One problem with classes is that you can only extend one other class. With constructors, you can use multiple constructors to form a function, which is much more flexible. You can do this using the.apply or.call methods of the function prototype. You can even extend only part of a function as long as it is an object.

Sometimes, you need to loop through any iterable content (Set, Map, Object, Array, String, etc.). The very simple forEach function tool does just that. If the callback returns true, it exits the loop.

function forEach(list, callback) {
  const entries = Object.entries(list);
  let i = 0;
  const len = entries.length;
  for(; i < len; i++) {const res = callback(entries[i][1], entries[i][0], list);
    if(res === true) break; }}Copy the code

22. Make the function argument required

This is a great way to ensure that the function calls what it needs to do its job. You can call a function with the property of the default argument value, and an error will be thrown. If the function is called with a value it needs, the value replaces the function and nothing happens. Using undefined has the same effect.

function required(argName = 'param') {
  throw new Error(`"${argName}" is required`)}function iHaveRequiredOptions(arg1 = required('arg1'), arg2 = 10) {
  console.log(arg1, arg2)
}
iHaveRequiredOptions(); // throws "arg1" is required
iHaveRequiredOptions(12); // prints 12, 10
iHaveRequiredOptions(12.24); // prints 12, 24
iHaveRequiredOptions(undefined.24); // throws "arg1" is required
Copy the code

23. Create a module or singleton

A lot of times, you need to initialize something at load time, set up all sorts of things it needs, and then you can use it all over the application without any additional work. You can do this using the IIFE function, which is so handy. This modular pattern is great for isolating things, exposing only the things that need to be interacted with.

Deep clone object developers usually install libraries like “LoDash” to do this, but it’s really easy to do it in pure JavaScript. This is a simple recursive function: as long as it is an object, it is re-initialized as a clone using the function’s constructor, and the process is repeated for all properties.

const deepClone = obj= > {
  let clone = obj;
  if (obj && typeof obj === "object") {
    clone = new obj.constructor();
    Object.getOwnPropertyNames(obj).forEach(
      prop= > (clone[prop] = deepClone(obj[prop]))
    );
  }
  return clone;
};
Copy the code

25. Deep freeze objects

If you like immutability, this is a tool you should always have.

const deepClone = obj= > {
  let clone = obj;
  if (obj && typeof obj === "object") {
    clone = new obj.constructor();
    Object.getOwnPropertyNames(obj).forEach(
      prop= > (clone[prop] = deepClone(obj[prop]))
    );
  }
  return clone;
};
Copy the code

Read beforesemicolon.medium.com/25-javascri…

Before Semicolon, wang Qiang, Li Junchen, 25 JS tips you should know Commercial reprint please contact the author for authorization, non-commercial reprint please indicate the source.