Previous remarks
This article will introduce ES6 digital extension in detail.
Exponential operator
The only JS grammatical change introduced by ES2016 is the power operator, which is a mathematical operation that applies exponential to cardinality. The existing Math.pow() method of JS can perform power calculation, but it is also one of the few methods that need to be used instead of formal operators to do power calculation.
The power operator is the base of two asterisks (**) left operand and the right operand is the exponent.
let result = 5 ** 2; console.log(result) // 25 console.log(result === Math.pow(5,2) ) // true
An exponential operator can be combined with an equal sign to form a new assignment operator (**=)
let a = 1.5;
a **= 2;
// Equivalent to a = a * a;
let b = 4;
b **= 3;
// Equivalent to b = b * b * b;
[Note] In V8 engines, exponential operators differ from Math.pow implementations, and there are subtle differences between them for very large operations.
Math.pow(99, 99) // 3.697296376497263e+197 99 ** 99 // 3.697296376497268e+197
[Operational order]
The power operator has the priority of all binary operators in JS (the priority of unary operators is higher than **), which means that it is first applied to all composite operations.
let result = 2 * 5 ** 2 console.log(result) // 50
Calculate 52 first, then multiply the value by 2, and the final result is 50.
[Operational Limitation]
The power operator does have some unusual limitations that other operators do not have. The unary expression on its left side can only use + + or -
//Syntax error let result =-5 ** 2
In this example, -5 is written in a grammatical error because the order of operations is not clear. - Does it apply only to 5, or to the result of expression 5** 2? Disabling the binary expression on the left side of the power operator eliminates ambiguity. To specify the intention, brackets are needed to wrap - 5 or 5** 2.
//Can wrap 5**2 let result1 =-(5 ** 2) //-25 //It can also be wrapped.-5 let result2 = (-5) ** 2 // Equivalent to 25
If parentheses are placed at both ends of an expression, then - will apply to the entire expression; if parentheses are placed at both ends of - 5, it indicates that the second curtain of - 5 is to be calculated.
On the left side of the curtain operator, you can use + + and -, without parentheses, because both operators clearly define the behavior that acts on the operand. The prefix + + or -- changes the operands before all other operations occur, and the suffix version does not change until the entire expression has been computed. Both of these usages are safe on the left side of the operation.
let num1 = 2, num2 = 2; console.log(++num1 ** 2) // 9 console.log(num1) // 3 console.log(num2--** 2) // 4 console.log(num2) // 1
In this example, num1 adds 1 before applying the power operator, so num1 becomes 3 and the result is 9, while num2 keeps the value of the power operator 2 and then subtracts 1.
Different binary systems
ES6 provides a new way to write binary and octal values, expressed by prefixes 0b (or 0B) and 0o (or 0O), respectively.
0b111110111 === 503 // true 0o767 === 503 // true
Starting with ES5, in strict mode, octal system is no longer allowed to be represented by prefix 0. ES6 makes it clear that prefix 0o should be used to represent octal system.
// Non-strict model (function(){ console.log(0o11 === 011); })() // true // Strict model (function(){ 'use strict'; console.log(0o11 === 011); })() // Uncaught SyntaxError: Octal literals are not allowed in strict mode.
If you want to convert the string values of 0b and 0o prefixes to decimal values, use Number method
Number('0b111') // 7 Number('0o10') // 8
Number method
ES6 provides two new methods on Number object, Number.isFinite() and Number.isNaN().
[Number.isFinite()]
Number.isFinite() is used to check whether a value is finite.
console.log( Number.isFinite(15)); // true console.log( Number.isFinite(0.8)); // true console.log( Number.isFinite(NaN)); // false console.log( Number.isFinite(Infinity)); // false console.log( Number.isFinite(-Infinity)); // false console.log( Number.isFinite('foo')); // false console.log( Number.isFinite('15')); // false console.log( Number.isFinite(true)); // false
The difference from the original isFinite() method is that the Number.isFinite() method has no implicit Number() type conversion and returns false for all non-numeric values.
console.log(isFinite(15)); // true console.log(isFinite(0.8)); // true console.log(isFinite(NaN)); // false console.log(isFinite(Infinity)); // false console.log(isFinite(-Infinity)); // false console.log(isFinite('foo')); // false console.log(isFinite('15')); // true console.log(isFinite(true)); // true
ES5 can deploy the Number.isFinite method through the following code
(function (global) { var global_isFinite = global.isFinite; Object.defineProperty(Number, 'isFinite', { value: function isFinite(value) { return typeof value === 'number' && global_isFinite(value); }, configurable: true, enumerable: false, writable: true }); })(this);
[Number.isNaN()]
Number.isNaN() is used to check whether a value is NaN
console.log(Number.isNaN('true')); //false console.log(Number.isNaN('hello')); //false console.log(Number.isNaN(NaN)); // true console.log(Number.isNaN(15)); // false console.log(Number.isNaN('15')); // false console.log(Number.isNaN(true)); // false console.log(Number.isNaN('true'/0)); // true
Unlike the original isNaN() method, there is no implicit Number() type conversion and non-NaN returns false.
console.log(isNaN('true')); //true console.log(isNaN('hello')); //true console.log(isNaN(NaN)); // true console.log(isNaN(15)); // false console.log(isNaN('15')); // false console.log(isNaN(true)); // false console.log(isNaN('true'/0)); // true
ES6 ports the global methods parseInt() and parseFloat() onto Number objects, and the behavior remains unchanged.
[parseInt()]
// ES5 Writing of parseInt('12.34') // 12 parseFloat('123.45#') // 123.45 // ES6 Writing of Number.parseInt('12.34') // 12 Number.parseFloat('123.45#') // 123.45
The goal is to gradually reduce the global approach and make the language modular.
Number.parseInt === parseInt // true Number.parseFloat === parseFloat // true
[Number.isInteger()]
Number.isInteger() is used to determine whether a value is an integer. It should be noted that within JS, integers and floating-point numbers are stored in the same way, so 3 and 3.0 are considered to be the same value.
Number.isInteger(25) // true Number.isInteger(25.0) // true Number.isInteger(25.1) // false Number.isInteger("15") // false Number.isInteger(true) // false
ES5 can deploy Number.isInteger() through the following code
(function (global) { var floor = Math.floor, isFinite = global.isFinite; Object.defineProperty(Number, 'isInteger', { value: function isInteger(value) { return typeof value === 'number' && isFinite(value) && floor(value) === value; }, configurable: true, enumerable: false, writable: true }); })(this);
Number constant
[Number.EPSILON]
ES6 adds a minimal constant Number.EPSILON to the Number object
Number.EPSILON// 2.220446049250313e-16 Number.EPSILON.toFixed(20)// '0.00000000000000022204'
The purpose of introducing such a small amount is to set a range of errors for floating-point calculations.
0.1 + 0.2// 0.30000000000000004 0.1 + 0.2 - 0.3// 5.551115123125783e-17 5.551115123125783e-17.toFixed(20)// '0.00000000000000005551'
But if the error is less than Number.EPSILON, we can assume that the correct result is obtained.
5.551115123125783e-17 < Number.EPSILON // true
Therefore, Number.EPSILON is essentially an acceptable error range.
function withinErrorMargin (left, right) { return Math.abs(left - right) < Number.EPSILON; } withinErrorMargin(0.1 + 0.2, 0.3)// true withinErrorMargin(0.2 + 0.2, 0.3)// false
The above code is a floating-point operation and deploys an error checking function.
[Safe Integer]
JS can accurately represent integers ranging from - 2 ^ 53 to 2 ^ 53 (excluding two endpoints), beyond which it cannot accurately represent this value.
Math.pow(2, 53) // 9007199254740992 9007199254740992 // 9007199254740992 9007199254740993 // 9007199254740992 Math.pow(2, 53) === Math.pow(2, 53) + 1 // true
In the above code, after exceeding the 53 power of 2, a number is not accurate.
[Number.MAX_SAFE_INTEGER,Number.MIN_SAFE_INTEGER]
ES6 introduces two constants Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER to represent the upper and lower limits of this range.
Number.MAX_SAFE_INTEGER === Math.pow(2, 53) - 1 // true Number.MAX_SAFE_INTEGER === 9007199254740991 // true Number.MIN_SAFE_INTEGER === -Number.MAX_SAFE_INTEGER // true Number.MIN_SAFE_INTEGER === -9007199254740991 // true
In the code above, you can see the limits that JS can accurately represent.
[Number.isSafeInteger()]
Number.isSafeInteger() is used to determine whether an integer falls within this range.
Number.isSafeInteger('a') // false Number.isSafeInteger(null) // false Number.isSafeInteger(NaN) // false Number.isSafeInteger(Infinity) // false Number.isSafeInteger(-Infinity) // false Number.isSafeInteger(3) // true Number.isSafeInteger(1.2) // false Number.isSafeInteger(9007199254740990) // true Number.isSafeInteger(9007199254740992) // false Number.isSafeInteger(Number.MIN_SAFE_INTEGER - 1) // false Number.isSafeInteger(Number.MIN_SAFE_INTEGER) // true Number.isSafeInteger(Number.MAX_SAFE_INTEGER) // true Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1) // false
The implementation of this function is very simple, that is, to compare it with the two boundary values of the safe integer.
Number.isSafeInteger = function (n) { return (typeof n === 'number' && Math.round(n) === n && Number.MIN_SAFE_INTEGER <= n && n <= Number.MAX_SAFE_INTEGER); }
When using this function in practice, we should pay attention to verifying whether the result of operation falls within the scope of safe integers, not only verifying the result of operation, but also verifying each value of the operation.
Number.isSafeInteger(9007199254740993) // false Number.isSafeInteger(990) // true Number.isSafeInteger(9007199254740993 - 990) // true 9007199254740993 - 990 // Return result 9007199254740002 // The correct answer should be 9007199254740003
In the above code, 9007199254740993 is not a safe integer, but Number.isSafeInteger returns the result, showing that the result is safe. This is because this number is beyond the accuracy range, resulting in the computer internal, in the form of 9007199254740992 storage.
9007199254740993 === 9007199254740992 // true
Therefore, if you only verify that the result of the operation is a safe integer, you will probably get the wrong result. The following functions can verify both arithmetic numbers and results at the same time
function trusty (left, right, result) { if ( Number.isSafeInteger(left) && Number.isSafeInteger(right) && Number.isSafeInteger(result) ) { return result; } throw new RangeError('Operation cannot be trusted!'); } // RangeError: Operation cannot be trusted! trusty(9007199254740993, 990, 9007199254740993 - 990) trusty(1, 2, 3)// 3
Math object
ES6 adds 17 math-related methods to Math objects. All of these methods are static methods that can only be invoked on Math objects
[Math.trunc]
Math.trunc method is used to remove the decimal part of a number and return the integer part.
Math.trunc(4.1) // 4 Math.trunc(4.9) // 4 Math.trunc(-4.1) // -4 Math.trunc(-4.9) // -4 Math.trunc(-0.1234) // -0
For non-numeric values, Math.trunc uses Number method internally to convert them to numeric values first
Math.trunc('123.456')// 123
Returns NaN for null values and values that cannot intercept integers
Math.trunc(NaN); // NaN Math.trunc('foo'); // NaN Math.trunc(); // NaN
For environments where this method is not deployed, you can simulate it with the following code
Math.trunc = Math.trunc || function(x) { return x < 0 ? Math.ceil(x) : Math.floor(x); };
[Math.sign]
Math.sign method is used to determine whether a number is positive, negative or zero. For non-numeric values, they are first converted to numeric values
It returns the following five values
The parameter is positive and returns + 1. The parameter is negative and returns - 1. Parameter 0, return 0; Parameter is - 0, return - 0; Other values, return NaN.
Math.sign(-5) // -1 Math.sign(5) // +1 Math.sign(0) // +0 Math.sign(-0) // -0 Math.sign(NaN) // NaN Math.sign('9'); // +1 Math.sign('foo'); // NaN Math.sign(); // NaN
For environments where this method is not deployed, you can simulate it with the following code
Math.sign = Math.sign || function(x) { x = +x; // convert to a number if (x === 0 || isNaN(x)) { return x; } return x > 0 ? 1 : -1; };
[Math.cbrt]
Math.cbrt Method for Calculating Cubic Roots of a Number
Math.cbrt(-1) // -1 Math.cbrt(0) // 0 Math.cbrt(1) // 1 Math.cbrt(2) // 1.2599210498948734
For non-numerical values, the Number method is also used internally to convert the Math.cbrt method to numerical values.
Math.cbrt('8') // 2 Math.cbrt('hello') // NaN
For environments where this method is not deployed, you can simulate it with the following code
Math.cbrt = Math.cbrt || function(x) { var y = Math.pow(Math.abs(x), 1/3); return x < 0 ? -y : y; };
[Math.clz32]
JS integers are represented in 32-bit binary form. Math.clz32 method returns 32-bit unsigned integers of a number. How many leading zeros are there?
Math.clz32(0) // 32 Math.clz32(1) // 31 Math.clz32(1000) // 22 Math.clz32(0b01000000000000000000000000000000) // 1 Math.clz32(0b00100000000000000000000000000000) // 2
In the above code, the binary form of 0 is all 0, so there are 32 leading zeros; the binary form of 1 is 0b1, which only occupies one bit, so there are 31 leading zeros in 32 bits; the binary form of 1000 is 0b1111101000, which has a total of 10 bits, so there are 22 leading zeros in 32 bits.
The left shift operator (<<) is directly related to the Math.clz32 method
Math.clz32(0) // 32 Math.clz32(1) // 31 Math.clz32(1 << 1) // 30 Math.clz32(1 << 2) // 29 Math.clz32(1 << 29) // 2
For decimal numbers, Math.clz32 only considers integer parts.
Math.clz32(3.2) // 30 Math.clz32(3.9) // 30
For null values or other types of values, the Math.clz32 method converts them to values before calculating them.
Math.clz32() // 32 Math.clz32(NaN) // 32 Math.clz32(Infinity) // 32 Math.clz32(null) // 32 Math.clz32('foo') // 32 Math.clz32([]) // 32 Math.clz32({}) // 32 Math.clz32(true) // 31
[Math.imul]
The Math.imul method returns the result of multiplying two numbers in the form of 32-bit signed integers. It also returns a 32-bit signed integer.
Math.imul(2, 4) // 8 Math.imul(-1, 8) // -8 Math.imul(-2, -2) // 4
If only the last 32 bits are considered, Math.imul(a, b) and a * B have the same results in most cases, that is, the method is equivalent to (a * b)|0 (partial overflow over 32 bits). The reason why this method needs to be deployed is that JS has precision limitations, and the values of the 53th power over 2 can not be accurately expressed. That is to say, for multiplication of large numbers, low-order values are often inaccurate, and Math.imul method can return the correct low-order values.
(0x7fffffff * 0x7fffffff)|0 // 0
The multiplication formula above returns 0. However, since the lowest bit of both binary numbers is 1, this result must be incorrect, because according to the binary multiplication, the lowest bit of the calculation result should also be 1. This error is because their product exceeds the 53th power of 2, JS can not save additional precision, so the low value is changed to 0. Math.imul method can return the correct value 1
Math.imul(0x7fffffff, 0x7fffffff) // 1
[Math.fround]
Math.front method returns a single-precision floating-point form of a number
Math.fround(0) // 0 Math.fround(1) // 1 Math.fround(1.337) // 1.3370000123977661 Math.fround(1.5) // 1.5 Math.fround(NaN) // NaN
For integers, the Math.front method returns no different results, except for decimal numbers that cannot be accurately represented by 64 binary bits. At this point, the Math. front method returns the single-precision floating-point number closest to the decimal.
For environments where this method is not deployed, you can simulate it with the following code
Math.fround = Math.fround || function(x) { return new Float32Array([x])[0]; };
[Math.hypot]
Math.hypot method returns the square root of the sum of squares of all parameters
Math.hypot(3, 4); // 5 Math.hypot(3, 4, 5); // 7.0710678118654755 Math.hypot(); // 0 Math.hypot(NaN); // NaN Math.hypot(3, 4, 'foo'); // NaN Math.hypot(3, 4, '5'); // 7.0710678118654755 Math.hypot(-3); // 3
In the code above, the square of three plus the square of four equals the square of five.
If the parameter is not a numerical value, the Math.hypot method converts it to a numerical value. As long as one parameter cannot be converted to a value, it returns NaN
ES6 adds four logarithmic correlation methods
[Math.expm1]
Math.expm1(x) returns ex-1, that is, Math.exp(x) -1
Math.expm1(-1) // -0.6321205588285577 Math.expm1(0) // 0 Math.expm1(1) // 1.718281828459045
For environments where this method is not deployed, you can simulate it with the following code
Math.expm1 = Math.expm1 || function(x) { return Math.exp(x) - 1; };
[Math.log1p(x)]
The Math.log1p(x) method returns the natural logarithm of 1+x, that is, Math.log(1+x). If x is less than - 1, return NaN
Math.log1p(1) // 0.6931471805599453 Math.log1p(0) // 0 Math.log1p(-1) // -Infinity Math.log1p(-2) // NaN
For environments where this method is not deployed, you can simulate it with the following code
Math.log1p = Math.log1p || function(x) { return Math.log(1 + x); };
[Math.log10(x)]
Math.log10(x) returns the logarithm of x based on 10. If x is less than 0, return NaN
Math.log10(2) // 0.3010299956639812 Math.log10(1) // 0 Math.log10(0) // -Infinity Math.log10(-2) // NaN Math.log10(100000) // 5
For environments where this method is not deployed, you can simulate it with the following code
Math.log10 = Math.log10 || function(x) { return Math.log(x) / Math.LN10; };
[Math.log2(x)]
Math.log2(x) returns the logarithm of X at the bottom of 2. If x is less than 0, return NaN
Math.log2(3) // 1.584962500721156 Math.log2(2) // 1 Math.log2(1) // 0 Math.log2(0) // -Infinity Math.log2(-2) // NaN Math.log2(1024) // 10 Math.log2(1 << 29) // 29
For environments where this method is not deployed, you can simulate it with the following code
Math.log2 = Math.log2 || function(x) { return Math.log(x) / Math.LN2; };
ES6 adds six hyperbolic function methods
Math.sinh(x) returns the hyperbolic sine of X Math.cosh(x) returns the hyperbolic cosine of X Math.tanh(x) returns the hyperbolic tangent of X Math.asinh(x) returns the inverse hyperbolic sine of X Math.acosh(x) returns the inverse hyperbolic cosine of X Math.atanh(x) returns the inverse hyperbolic tangent of X