12 JavaScript tricks that most tutorials don't cover
When I started learning JavaScript, the first thing I did was make a list of tricks that helped me save time. I spied them on other programmers, on different sites and in manuals.
In this article, I'll show you 12 great ways to improve and speed up your JavaScript code. In most cases, they are universal.
We remind you:for all readers of "Habr" - a discount of 10 rubles when enrolling in any Skillbox course using the "Habr" promotional code.
In a normal situation, much more code is needed to perform the same operation.
This trick works for arrays containing primitive types: undefined, null, boolean, string, and number. If you're working with an array containing objects, functions, or additional arrays, you'll need a different approach.
Cache array length in cycles
CYCLES
When you learn for for loops, you follow the standard procedure:
for (let i = 0; i < array.length; i++){
console.log(i);
}
However, with this syntax, the for loop rechecks the length of the array on each iteration.
This can sometimes be useful, but in most cases it's more efficient to cache the length of the array, which will require one access to it. We can do this by defining a variable length where to set the i variable like so:
for (let i = 0, length = array.length; i < length; i++){
console.log(i);
}
In principle, almost the same as above, but with an increase in the size of the loop, we will get significant time savings.
Short Circuit Rating (McCarthy Rating)
CONDITIONAL OPERATORS
The ternary operator is a fast and efficient way to write simple (and sometimes not so simple) conditional statements:
x > 100? "more than 100": "less than 100";
x > 100? (x > 200? "greater than 200": "between 100-200"): "less than 100";
But sometimes even the ternary operator is more complicated than required. Instead, we can use 'and' && and 'or' || logical operators to evaluate some expressions in an even more concise way. It is often referred to as "short circuit" or "short circuit evaluation".
How it works
Let's say we only want to return one of two or more conditions.
Using && will return the first false value. If each operand evaluates to true, then the last expression evaluated will be returned.
let one = 1, two = 2, three = 3;
console.log(one && two && three); // Result: 3
console.log(0 && null); // Result: 0
Using || will return the first true value. If each operand evaluates to false, then the last computed value will be returned.
let one = 1, two = 2, three = 3;
console.log(one || two || three); // Result: 1
console.log(0 || null); // Result: null
Example 1
Let's say we want to return the length of a variable, but we don't know its type.
In this case, you can use if/else to check that foo is the right type, but this method can be too long. Therefore, it is better to take our "short circuit".
return (foo || []).length;
If the variable foo has a suitable length, then it will be returned. Otherwise, we will get 0.
Example 2
Have you had problems accessing a nested object? You may not know if an object or one of its subproperties exists, and this can lead to problems.
For example, we wanted to access the data property in this.state, but data is not defined until our program returns a fetch request.
Depending on where we use it, calling this.state.data may prevent the application from starting. To solve the problem, we could wrap this in a conditional statement:
A better option would be to use the "or" operator.
return (this.state.data || 'Fetching Data');
We cannot change the code above to use &&. The 'Fetching Data' operator && this.state.data will return this.state.data whether it is undefined or not.
Optional chain
One might suggest using optional chaining when trying to return a property deep into the tree structure. So, the question mark symbol? can be used to retrieve a property only if it is non-null.
For example, we could refactor the example above to get this.state.data?..(). That is, data is returned only if the value is not null.
Or, if it matters whether state is defined or not, we could return this.state?.data.
Convert to Boolean
TYPE CONVERSION
Besides the normal boolean true and false functions, JavaScript also treats all other values as truthy or false.
Unless otherwise noted, all values in JavaScript are truthy, except for 0, "", null, undefined, NaN, and of course false. The latter are false.
We can easily switch between the two using the ! operator, which also converts the type to boolean.
There may be situations where + will be interpreted as a concatenation operator rather than an addition operator. To avoid this, use tildes: ~~. This operator is equivalent to the -n-1 expression. For example, ~15 is equal to -16.
Using two tildes in a row nullifies the operation, because - (- - n - 1) - 1 = n + 1 - 1 = n. In other words, ~-16 is equal to 15.
Since ES7, you can use the exponentiation operator ** as a shorthand for exponents. This is much faster than using Math.pow(2, 3). It seems simple, but this moment is included in the list of tricks, since it is far from being mentioned everywhere.
console.log(2 ** 3); // Result: 8
Do not confuse it with the ^ symbol, which is commonly used for exponentiation. But in JavaScript it's the XOR operator.
Prior to ES7, the abbreviation ** could only be applied to base-2 exponents using the bitwise left shift operator <<:
Math.pow(2, n);
2 << (n - 1);
2**n;
For example, 2 << 3 = 16 is equivalent to 2 ** 4 = 16.
Float to integer
OPERATIONS / TYPE CONVERSION
If you need to convert a float to an integer, you can use Math.floor(), Math.ceil(), or Math.round(). But there is a faster way, for this we use |, that is, the OR operator.
Behavior | largely depends on whether you are dealing with positive or negative numbers, so this method is only suitable if you are sure of what you are doing.
n | 0 removes everything after the decimal separator, truncating the float to an integer.
You can get the same rounding effect using ~~. After a forced conversion to an integer, the value remains unchanged.
Removing trailing numbers
The OR operator can be used to remove any number of digits from a number. This means we don't need to typecast like this:
let str = "1553";
Number(str.substring(0, str.length - 1));
ES6 arrow notation can be used in class methods and binding is implied. Thanks to this, you can say goodbye to repetitive expressions like this.myMethod = this.myMethod.bind (this)!