Numerical expansion

Binary and octal notation

ES6 provides a new way of writing binary and octal values, which are represented by prefixes 0b (or 0B) and 0o (or 0O) respectively.

0b111110111 === 503; // true
0o767 === 503; // true

Starting from ES5, in strict mode, the prefix 0 is no longer allowed in octal system. ES6 further clarifies that the prefix 0o should be used.

// Non-strict mode
(function () {
  console.log(0o11 === 011);
})()(
  // true

  // strict mode
  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 ​​prefixed with 0b and 0o to decimal, use the Number method.

Number("0b111"); // 7
Number("0o10"); // 8

Number.isFinite(), Number.isNaN()

ES6 provides two new methods, Number.isFinite() and Number.isNaN(), on the Number object.

Number.isFinite() is used to check whether a value is finite, that is, it is not Infinity.

Number.isFinite(15); // true
Number.isFinite(0.8); // true
Number.isFinite(NaN); // false
Number.isFinite(Infinity); // false
Number.isFinite(-Infinity); // false
Number.isFinite("foo"); // false
Number.isFinite("15"); // false
Number.isFinite(true); // false

Note that if the parameter type is not numeric, Number.isFinite always returns false.

Number.isNaN() is used to check whether a value is NaN.

Number.isNaN(NaN); // true
Number.isNaN(15); // false
Number.isNaN("15"); // false
Number.isNaN(true); // false
Number.isNaN(9 / NaN); // true
Number.isNaN("true" / 0); // true
Number.isNaN("true" / "true"); // true

If the parameter type is not NaN, Number.isNaN always returns false.

The difference between them and the traditional global methods isFinite() and isNaN() is that the traditional method first calls Number() to convert a non-numeric value to a numeric value, and then judges, and these two new methods only Valid for numeric values, Number.isFinite() always returns false for non-numeric values, Number.isNaN() returns true only for NaN, and always returns false for non-NaN.

isFinite(25); // true
isFinite("25"); // true
Number.isFinite(25); // true
Number.isFinite("25"); // false

isNaN(NaN); // true
isNaN("NaN"); // true
Number.isNaN(NaN); // true
Number.isNaN("NaN"); // false
Number.isNaN(1); // false

Number.parseInt(), Number.parseFloat()

ES6 transplants the global methods parseInt() and parseFloat() to the Number object, and the behavior remains completely unchanged.

// How to write ES5
parseInt("12.34"); // 12
parseFloat("123.45#"); // 123.45

// How to write ES6
Number.parseInt("12.34"); // 12
Number.parseFloat("123.45#"); // 123.45

The purpose of this is to gradually reduce the overall approach and make the language gradually modular.

Number.parseInt === parseInt; // true
Number.parseFloat === parseFloat; // true

Number.isInteger()

Number.isInteger() is used to determine whether a number is an integer.

Number.isInteger(25); // true
Number.isInteger(25.1); // false

In JavaScript, integers and floating-point numbers use the same storage method, so 25 and 25.0 are considered the same value.

Number.isInteger(25); // true
Number.isInteger(25.0); // true

If the parameter is not a number, Number.isInteger returns false.

Number.isInteger(); // false
Number.isInteger(null); // false
Number.isInteger("15"); // false
Number.isInteger(true); // false

Note that since JavaScript adopts the IEEE 754 standard, the value is stored in a 64-bit double-precision format, and the numerical precision can reach up to 53 binary digits (1 hidden bit and 52 effective digits). If the precision of the value exceeds this limit, the 54th and subsequent bits will be discarded. In this case, Number.isInteger may be misjudged.

Number.isInteger(3.0000000000000002); // true

In the above code, the parameter of Number.isInteger is obviously not an integer, but it will return true. The reason is that the precision of this decimal has reached 16 decimal digits after the decimal point, and the conversion into binary digits exceeds 53 binary digits, resulting in the last 2 being discarded.

In a similar situation, if the absolute value of a number is less than Number.MIN_VALUE (5E-324), that is, less than the minimum value that JavaScript can distinguish, it will be automatically converted to 0. At this time, Number.isInteger will also misjudge.

Number.isInteger(5e-324); // false
Number.isInteger(5e-325); // true

In the above code, 5E-325 will be automatically converted to 0 because the value is too small, so it returns true.

In short, if the data accuracy requirements are high, it is not recommended to use Number.isInteger() to determine whether a value is an integer.

Number.EPSILON

ES6 adds a tiny constant Number.EPSILON to the Number object. According to the specification, it represents the difference between 1 and the smallest floating-point number greater than 1.

For 64-bit floating-point numbers, the smallest floating-point number greater than 1 is equivalent to the binary 1.00..001, with 51 consecutive zeros after the decimal point. After subtracting 1 from this value, it is equal to 2 to the -52th power.

Number.EPSILON === Math.pow(2, -52);
// true
Number.EPSILON;
// 2.220446049250313e-16
Number.EPSILON.toFixed(20);
// "0.00000000000000022204"

Number.EPSILON is actually the smallest precision that JavaScript can represent. If the error is less than this value, it can be considered as meaningless, that is, there is no error.

The purpose of introducing such a small amount is to set an error range for floating-point calculations. We know that floating-point calculations are imprecise.

0.1 + 0.2;
// 0.30000000000000004

0.1 + 0.2 - 0.3;
// 5.551115123125783e-17

(5.551115123125783e-17).toFixed(20);
// '0.00000000000000005551'

The above code explains why the result of comparing 0.1 + 0.2 with 0.3 is false.

0.1 + 0.2 === 0.3; // false

Number.EPSILON can be used to set the "acceptable error range". For example, the error range is set to the power of 2-50 (ie Number.EPSILON * Math.pow(2, 2)), that is, if the difference between two floating-point numbers is less than this value, we consider these two floating-point numbers equal.

5.551115123125783e-17 < Number.EPSILON * Math.pow(2, 2);
// true

Therefore, the essence of Number.EPSILON is an acceptable minimum error range.

function withinErrorMargin(left, right) {
  return Math.abs(left - right) < Number.EPSILON * Math.pow(2, 2);
}

0.1 + 0.2 === 0.3; // false
withinErrorMargin(0.1 + 0.2, 0.3); // true

1.1 + 1.3 === 2.4; // false
withinErrorMargin(1.1 + 1.3, 2.4); // true

The above code is floating-point arithmetic, and an error checking function is deployed.

Safe Integer and Number.isSafeInteger()

The integer range that JavaScript can accurately represent is between -2^53 and 2^53 (excluding the two endpoints). If this range is exceeded, this value cannot be accurately represented.

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 2 to the 53rd power, a number becomes inaccurate.

ES6 introduced the two constants Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER to indicate 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 above code, you can see the limit that JavaScript can accurately represent.

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, just compare it with the two boundary values ​​of a 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 actually using this function, you need to pay attention. Verify that the result of the operation falls within the range of a safe integer. Do not only verify the result of the operation, but also verify each value involved in 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 will return the result, showing that the calculation result is safe. This is because this number is beyond the accuracy range, and it is stored inside the computer in the form of 9007199254740992.

9007199254740993 === 9007199254740992;
// true

Therefore, if you only verify whether the result of the operation is a safe integer, you may get an incorrect result. The following function can simultaneously verify two operands and the result of the operation.

function trusty(left, right, result) {
  if (
    Number.isSafeInteger(left) &&
    Number.isSafeInteger(right) &&
    Number.isSafeInteger(result)
  ) {
    return result;
  }
  throw new RangeError("Operation cannot be trusted!");
}

trusty(9007199254740993, 990, 9007199254740993 - 990);
// RangeError: Operation cannot be trusted!

trusty(1, 2, 3);
// 3

Math object extension

ES6 adds 17 new math-related methods on the Math object. All these methods are static methods and can only be called on the Math object.

Math.trunc()

The 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-numerical values, Math.trunc internally uses the Number method to convert it to a numeric value first.

Math.trunc("123.456"); // 123
Math.trunc(true); //1
Math.trunc(false); // 0
Math.trunc(null); // 0

For null values ​​and integer values ​​that cannot be intercepted, NaN is returned.

Math.trunc(NaN); // NaN
Math.trunc("foo"); // NaN
Math.trunc(); // NaN
Math.trunc(undefined); // NaN

For environments where this method is not deployed, the following code can be used to simulate.

Math.trunc =
  Math.trunc ||
  function (x) {
    return x < 0 ? Math.ceil(x) : Math.floor(x);
  };

Math.sign()

The Math.sign method is used to determine whether a number is positive, negative, or zero. For non-numeric values, it will first be converted to numeric values.

It will return five values.

-If the parameter is a positive number, return +1; -If the parameter is negative, return -1; -The parameter is 0, return 0; -The parameter is -0, return -0; -For other values, NaN is returned.

Math.sign(-5); // -1
Math.sign(5); // +1
Math.sign(0); // +0
Math.sign(-0); // -0
Math.sign(NaN); // NaN

If the parameter is non-numeric, it will be automatically converted to a numeric value. For those values ​​that cannot be converted to numeric values, NaN will be returned.

Math.sign(""); // 0
Math.sign(true); // +1
Math.sign(false); // 0
Math.sign(null); // 0
Math.sign("9"); // +1
Math.sign("foo"); // NaN
Math.sign(); // NaN
Math.sign(undefined); // NaN

For environments where this method is not deployed, the following code can be used to simulate.

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()

The Math.cbrt() method is used to calculate the cube root of a number.

Math.cbrt(-1); // -1
Math.cbrt(0); // 0
Math.cbrt(1); // 1
Math.cbrt(2); // 1.2599210498948732

For non-numerical values, the Math.cbrt() method internally also uses the Number() method to convert it to a number.

Math.cbrt("8"); // 2
Math.cbrt("hello"); // NaN

For environments where this method is not deployed, the following code can be used to simulate.

Math.cbrt =
  Math.cbrt ||
  function (x) {
    var y = Math.pow(Math.abs(x), 1 / 3);
    return x < 0 ? -y : y;
  };

Math.clz32()

The Math.clz32() method converts the parameter to the form of a 32-bit unsigned integer, and then returns how many leading zeros are in the 32-bit value.

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 0s, so there are 32 leading 0s; the binary form of 1 is 0b1, which only occupies 1 bit, so there are 31 leading 0s in 32 bits; the binary form of 1000 is 0b1111101000, there are 10 bits in total, so there are 22 leading 0s in the 32 bits.

The name of the function clz32 comes from the abbreviation of "count leading zero bits in 32-bit binary representation of a number".

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 decimals, the Math.clz32 method only considers the integer part.

Math.clz32(3.2); // 30
Math.clz32(3.9); // 30

For null values ​​or other types of values, the Math.clz32 method will first convert them to numeric values, and then calculate 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 a 32-bit signed integer, and it 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, in most cases, the results of Math.imul(a, b) and a * b are the same, that is, the method is equivalent to the effect of (a * b)|0 (Partial overflow exceeding 32 bits). The reason why this method needs to be deployed is because JavaScript has a precision limit, and values ​​exceeding 2 to the 53 power cannot be accurately represented. This means that for the multiplication of large numbers, the low-order values ​​are often inaccurate, and the Math.imul method can return the correct low-order values.

(0x7fffffff * 0x7fffffff) | 0; // 0

The above multiplication formula returns a result of 0. But since the lowest bit of these two binary numbers are both 1, this result is definitely incorrect, because according to binary multiplication, the lowest binary bit of the calculation result should also be 1. This error is because their product exceeds 2 to the 53rd power. JavaScript can't save the extra precision, so the low-order value becomes 0. The Math.imul method can return the correct value 1.

Math.imul(0x7fffffff, 0x7fffffff); // 1

Math.fround()

The Math.fround method returns a 32-bit single-precision floating-point number form of a number.

For the 32-bit single-precision format, the numerical precision is 24 binary digits (1 hidden bit and 23 significant digits), so for -224 to 224 The integer between (excluding the two endpoints), the returned result is consistent with the parameter itself.

Math.fround(0); // 0
Math.fround(1); // 1
Math.fround(2 ** 24 - 1); // 16777215

If the absolute value of the parameter is greater than 224, the returned result will start to lose precision.

Math.fround(2 ** 24); // 16777216
Math.fround(2 ** 24 + 1); // 16777216

The main function of the Math.fround method is to convert a 64-bit double-precision floating-point number to a 32-bit single-precision floating-point number. If the precision of the decimal exceeds 24 binary digits, the return value will be different from the original value, otherwise the return value will not change (that is, the same as the 64-bit double precision value).

// Effective accuracy is not lost
Math.fround(1.125); // 1.125
Math.fround(7.25); // 7.25

// Lost precision
Math.fround(0.3); // 0.30000001192092896
Math.fround(0.7); // 0.699999988079071
Math.fround(1.0000000123); // 1

For NaN and Infinity, this method returns the original value. For other types of non-numeric values, the Math.fround method will first convert them to numeric values, and then return single-precision floating-point numbers.

Math.fround(NaN); // NaN
Math.fround(Infinity); // Infinity

Math.fround("5"); // 5
Math.fround(true); // 1
Math.fround(null); // 0
Math.fround([]); // 0
Math.fround({}); // NaN

For environments where this method is not deployed, the following code can be used to simulate.

Math.fround =
  Math.fround ||
  function (x) {
    return new Float32Array([x])[0];
  };

Math.hypot()

The 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 above code, the square of 3 plus the square of 4 is equal to the square of 5.

If the parameter is not a numeric value, the Math.hypot method will convert it to a numeric value. As long as there is a parameter that cannot be converted to a value, NaN will be returned.

Logarithmic method

ES6 adds 4 logarithmic correlation methods.

(1) Math.expm1()

Math.expm1(x) returns ex-1, which 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, the following code can be used to simulate.

Math.expm1 =
  Math.expm1 ||
  function (x) {
    return Math.exp(x) - 1;
  };

(2)Math.log1p()

The Math.log1p(x) method returns the natural logarithm of 1 + x, which 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, the following code can be used to simulate.

Math.log1p =
  Math.log1p ||
  function (x) {
    return Math.log(1 + x);
  };

(3)Math.log10()

Math.log10(x) returns the base 10 logarithm of x. If x is less than 0, NaN is returned.

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, the following code can be used to simulate.

Math.log10 =
  Math.log10 ||
  function (x) {
    return Math.log(x) / Math.LN10;
  };

(4)Math.log2()

Math.log2(x) returns the base 2 logarithm of x. If x is less than 0, NaN is returned.

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, the following code can be used to simulate.

Math.log2 =
  Math.log2 ||
  function (x) {
    return Math.log(x) / Math.LN2;
  };

Hyperbolic function method

ES6 added 6 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

Exponential operator

ES2016 added a new exponent operator (**).

2 ** 2; // 4
2 ** 3; // 8

A feature of this operator is right associativity, rather than the common left associativity. When multiple exponent operators are used together, the calculation starts from the rightmost.

// equivalent to 2 ** (3 ** 2)
2 ** (3 ** 2);
// 512

In the above code, the second exponential operator is calculated first, not the first.

The exponent operator can be combined with the 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;

BigInt data type

Introduction

All numbers in JavaScript are saved as 64-bit floating point numbers, which brings two major limitations to the representation of values. One is that the precision of a value can only reach 53 binary digits (equivalent to 16 decimal digits). Integers larger than this range cannot be accurately represented by JavaScript, which makes JavaScript unsuitable for accurate scientific and financial calculations. The second is a value greater than or equal to 2 to the power of 1024, which JavaScript cannot represent and will return Infinity.

// The value exceeds 53 binary digits, and the precision cannot be maintained
Math.pow(2, 53) === Math.pow(2, 53) + 1; // true

// A value exceeding 2 to the power of 1024, cannot be represented
Math.pow(2, 1024); // Infinity

ES2020 introduced a new data type BigInt (big integer) to solve this problem, which is the eighth data type of ECMAScript. BigInt is only used to represent integers, there is no limit on the number of digits, and integers of any number of digits can be accurately represented.

const a = 2172141653n;
const b = 15346349309n;

// BigInt can maintain accuracy
a * b; // 33334444555566667777n

// Ordinary integers cannot maintain precision
Number(a) * Number(b); // 33334444555566670000

In order to distinguish from the Number type, the data of the BigInt type must be suffixed with n.

1234; // ordinary integer
1234n; // BigInt

// Operation of BigInt
1n + 2n; // 3n

BigInt can also be expressed in various bases, all with the suffix n.

0b1101n; // Binary
0o777n; // octal
0xffn; // Hexadecimal

BigInt and ordinary integer are two kinds of values, and they are not equal.

42n === 42; // false

The typeof operator returns bigint for data of type BigInt.

typeof 123n; //'bigint'

BigInt can use negative sign (-), but cannot use positive sign (+) because it will conflict with asm.js.

-42n + // correct
  42n; // report an error

JavaScript could not calculate the factorial of 70 (that is, 70!) because it exceeded the precision that can be expressed.

let p = 1;
for (let i = 1; i <= 70; i++) {
  p *= i;
}
console.log(p); // 1.197857166996989e+100

Now that large integers are supported, it's fine. Run the following code in the browser's developer tool, and it will be OK.

let p = 1n;
for (let i = 1n; i <= 70n; i++) {
  p *= i;
}
console.log(p); // 11978571...00000000n

BigInt Object

JavaScript natively provides the BigInt object, which can be used as a constructor to generate BigInt type values. The conversion rules are basically the same as Number(), and other types of values ​​are converted to BigInt.

BigInt(123); // 123n
BigInt("123"); // 123n
BigInt(false); // 0n
BigInt(true); // 1n

The BigInt() constructor must have parameters, and the parameters must be converted to values ​​normally. The following usages will report errors.

new BigInt(); // TypeError
BigInt(undefined); //TypeError
BigInt(null); // TypeError
BigInt("123n"); // SyntaxError
BigInt("abc"); // SyntaxError

In the above code, it is especially worth noting that the string 123n cannot be parsed into Number type, so an error will be reported.

If the parameter is a decimal, an error will be reported.

BigInt(1.5); // RangeError
BigInt("1.5"); // SyntaxError

The BigInt object inherits two instance methods of the Object object.

-BigInt.prototype.toString() -BigInt.prototype.valueOf()

It also inherits an instance method of the Number object.

-BigInt.prototype.toLocaleString()

In addition, three static methods are provided.

-BigInt.asUintN(width, BigInt): The given BigInt is converted to the corresponding value between 0 and 2width-1. -BigInt.asIntN(width, BigInt): The given BigInt is converted to the corresponding value from -2width-1 to 2width-1-1. -BigInt.parseInt(string[, radix]): Approximately Number.parseInt(), which converts a string into a BigInt in the specified base.

const max = 2n ** (64n - 1n) - 1n;

BigInt.asIntN(64, max);
// 9223372036854775807n
BigInt.asIntN(64, max + 1n);
// -9223372036854775808n
BigInt.asUintN(64, max + 1n);
// 9223372036854775808n

In the above code, max is the maximum value that a 64-bit signed BigInt can represent. If you add 1n to this value, BigInt.asIntN() will return a negative value, because the new bit will be interpreted as a sign bit. The BigInt.asUintN() method can return the result correctly because there is no sign bit.

If the number of digits specified by BigInt.asIntN() and BigInt.asUintN() is less than the number of digits, then the head bit will be discarded.

const max = 2n ** (64n - 1n) - 1n;

BigInt.asIntN(32, max); // -1n
BigInt.asUintN(32, max); // 4294967295n

In the above code, max is a 64-bit BigInt. If it is converted to 32 bits, the previous 32 bits will be discarded.

The following is an example of BigInt.parseInt().

// Comparison of Number.parseInt() and BigInt.parseInt()
Number.parseInt("9007199254740993", 10);
// 9007199254740992
BigInt.parseInt("9007199254740993", 10);
// 9007199254740993n

In the above code, because the effective number exceeds the maximum limit, the result returned by the Number.parseInt method is inaccurate, and the BigInt.parseInt method correctly returns the corresponding BigInt.

For binary arrays, BigInt adds two new types BigUint64Array and BigInt64Array, both of which return 64-bit BigInt. The instance methods DataView.prototype.getBigInt64() and DataView.prototype.getBigUint64() of the DataView object also return BigInt.

Conversion rules

You can use the three methods Boolean(), Number() and String() to convert BigInt to Boolean, numeric and string types.

Boolean(0n); // false
Boolean(1n); // true
Number(1n); // 1
String(1n); // "1"

In the above code, pay attention to the last example, the suffix n will disappear when converted to a string.

In addition, the negation operator (!) can also convert BigInt to a Boolean value.

!0n; // true
!1n; // false

computation

In terms of mathematical operations, the four binary operators +, -, *, and ** of the BigInt type have the same behavior as the Number type. The division operation / will round off the decimal part and return an integer.

9n / 5n;
// 1n

Almost all numerical operators can be used in BigInt, but there are two exceptions.

-Unsigned right shift operator >>> -Unary positive operator +

The above two operators will report errors when used in BigInt. The former is because the >>> operator is unsigned, but BigInt is always signed, which makes the operation meaningless and is completely equivalent to the right shift operator >>. The latter is because the unary operator + always returns the Number type in asm.js. In order not to damage asm.js, it is stipulated that +1n will report an error.

BigInt cannot be mixed with ordinary values.

1n + 1.3; // error

The above code reports an error because whether it returns BigInt or Number, it will cause the loss of precision information. For example, if the expression (2n**53n + 1n) + 0.5 returns the BigInt type, the fractional part of 0.5 will be lost; if it returns the Number type, the effective precision can only maintain 53 digits, resulting in a decrease in precision.

For the same reason, if the parameter of a standard library function is expected to be of type Number, but the result is a BigInt, an error will be reported.

// wrong way
Math.sqrt(4n); // error

// correct writing
Math.sqrt(Number(4n)); // 2

In the above code, the parameter of Math.sqrt is expected to be of Number type. If it is BigInt, an error will be reported. You must first use the Number method to transfer the type before calculation.

In asm.js, |0 following a value will return a 32-bit integer. According to the rule that the operation cannot be mixed with the Number type, BigInt will report an error if it is operated with |0.

1n | 0; // error

Other operations

The Boolean value corresponding to BigInt is consistent with the Number type, that is, 0n will be converted to false, and other values ​​will be converted to true.

if (0n) {
  console.log("if");
} else {
  console.log("else");
}
// else

In the above code, 0n corresponds to false, so it will enter the else clause.

Comparison operators (such as >) and equality operators (==) allow BigInt to be mixed with other types of values, because they do not lose precision.

0n < 1; // true
0n < true; // true
0n == 0; // true
0n == false; // true
0n === 0; // false

When BigInt is mixed with a string, it will be converted to a string first, and then the operation will be performed.

"" + 123n; // "123"