foreword
Please tell me the data type in JavaScript
?
In the front-end interview, it is estimated that everyone has been asked this way.
Answer: The data types in Javascript
include primitive types and reference types. null
、 undefined
、 boolean
、 string
、 symbol
、 bigInt
, number
. The reference type refers to Object
.
Yes, I answered the same way, but this is usually the first question, and many, many questions can be raised from this question, such as
- What is the difference between
Null
andUndefined
? What should be paid attention to in the front-end empty judgment? -
typeof null
Whyobject
? - Why
ES6
to proposeSymbol
? -
BigInt
What problem was solved? - Why
0.1 + 0.2 !== 0.3?
how do you fix this? - How to tell if a value is an array?
- ...
weakly typed language
Because JavaScript
is a weakly typed language or a dynamic language. This means that you do not need to declare the type of the variable in advance, the type will be automatically determined during the running of the program, which means that you can use the same variable to store values of different types
var foo = 42; // foo is a Number now
foo = "bar"; // foo is a String now
foo = true; // foo is a Boolean now
While this feature brings us convenience, it also brings us a lot of type errors. Just imagine, if JS
is said to be a strongly typed language, then there is no way to convert between types, and there will be a barrier or a layer of protection. Will it be easier to maintain? ——This may be the reason why TypeScript
was born.
Mastering the data type of JavaScript
is the most basic knowledge point of a front-end
null or undefined
definition
undefined
represents an undefined variable. null
value represents a null object pointer.
追本溯源: 一开始的时候,JavaScript
Brendan Eich
其实null
,null
Java
as in, is treated as an object. But becauseJavaScript
there are two data types: primitive and reference.Brendan Eich
I think the value that means "nothing" is best not an object.
Therefore, the design of Javascript
is that null is an object representing "nothing", which is 0 when converted to a value; undefined is a primitive value representing "nothing", which is NaN when converted to a value.
Number(null)
// 0
5 + null
// 5
Number(undefined)
// NaN
5 + undefined
// NaN
The difference and application of Null and Undefined
null means "no object", i.e. there should be no value there. , the typical usage is as follows
- As an argument to a function, it means that the argument to the function is not an object.
- as the end of the object prototype chain.
Object.getPrototypeOf(Object.prototype)
// null
undefined means "missing value", i.e. there should be a value here, but it hasn't been defined . Typical usage is:
- When the variable is declared, but not assigned a value, it is equal to
undefined
. - When calling the function, the parameter that should be provided is not provided, the parameter is equal to
undefined
. - The object has no assigned property, the value of this property is
undefined
. - When the function has no return value, the default return
undefined
.
var i;
i // undefined
function f(x){console.log(x)}
f() // undefined
var o = new Object();
o.p // undefined
var x = f();
x // undefined
What should I pay attention to when judging empty?
javaScript
Five kinds of null and false values, respectively undefined, null, false, "", 0, NAN
This can sometimes easily lead to some problems, such as
let a = 0;
console.log(a || '/'); // 本意是只要 a 为 null 或者 Undefined 的时候,输出 '/',但实际上只要是我们以上的五种之一就输出 '/'
Of course we can write
let a = 0;
if (a === null || a === undefined) {
console.log('/');
} else {
console.log(a);
}
It's not always very elegant, so the ES specification proposes the null coalescing operator (??)
The null coalescing operator (??) is a logical operator. When the left operand is null or undefined, it returns its right operand, otherwise it returns the left operand.
The above example can be written as:
let a = 0;
console.log(a??'/'); // 0
typeof null - JS mistakes
typeof null // "object"
The value in JavaScript
is represented by a label representing the type and the actual data value. The first version JavaScript
used 32 bits to store the value, and the type was identified by the lower 1 or 3 bits of the value, and the type tag of the object was 000. as follows
- 1: Integer (int)
- 000: Reference type (object)
- 010: Double-precision floating-point type (double)
- 100: string (string)
- 110: Boolean (boolean)
But there are two special values:
- undefined, use the integer −2^30 (negative 2 to the 30th power, not in the range of integers)
- null, machine code null pointer (C/C++ macro definition), the lower three digits are also 000
null
代表的是空指针(低000
),因此,null
的类型标签是000
, typeof null
also returns "object" as a result.
This is a design error of JavaScript
, but it cannot be modified. After all, if you modify it, it will affect the existing code.
Number——0.1+0.2 !== 0.3
Phenomenon
In JavaScript
there will be a phenomenon similar to the following
0.1 + 0.2
0.30000000000000004
reason
In the process of operating on floating point numbers, we need to convert decimal to binary. The rules for converting decimal to binary are as follows:
Multiply the number after the decimal point by 2, take the integer part of the result (either 1 or 0), then multiply the fractional part by 2, and then take the integer part of the result... and so on until the fractional part is 0 or a bit The number is enough and it is OK. Then arrange the integer parts taken in order
According to the above rules, the final representation of 0.1 is as follows:
0.000110011001100110011(0011无限循环)……
So, the loss of precision is not a language problem, but an inherent flaw in the storage of floating-point numbers.
JavaScript
64
位双精度Number
类型值, IEEE754
,0.1 的二进制数只保留52 significant digits, i.e.
1.100110011001100110011001100110011001100110011001101 * 2^(-4)
Similarly, the binary number of 0.2 is
1.100110011001100110011001100110011001100110011001101 * 2^(-3)
In this way, precision has been lost in the conversion between bases. The operation is as follows
0.00011001100110011001100110011001100110011001100110011010
+0.00110011001100110011001100110011001100110011001100110100
------------------------------------------------------------
=0.01001100110011001100110011001100110011001100110011001110
So it leads to 0.1 + 0.2 !== 0.3 in the final calculation result
How to solve
- Convert numbers to integers
function add(num1, num2) {
const num1Digits = (num1.toString().split('.')[1] || '').length;
const num2Digits = (num2.toString().split('.')[1] || '').length;
const baseNum = Math.pow(10, Math.max(num1Digits, num2Digits));
return (num1 * baseNum + num2 * baseNum) / baseNum;
}
- class library
NPM
上有许多支持JavaScript
Node.js
的数学库,math.js
,decimal.js
,D.js
etc - ES6
ES6
Added a tiny constant on theNumber
objectNumber.EPSILON
Number.EPSILON
// 2.220446049250313e-16
Number.EPSILON.toFixed(20)
// "0.00000000000000022204"
The purpose of introducing such a small amount is to set an error range for floating-point calculations. If the error can be less than Number.EPSILON
, we can consider the result to be reliable.
function withinErrorMargin (left, right) {
return Math.abs(left - right) < Number.EPSILON
}
withinErrorMargin(0.1+0.2, 0.3)
Future Solutions - TC39 Decimal proposal
Proposal currently in Stage 1
. The later mentioned BigInt
is extended to the positive number boundary of JS
, which exceeds the 2^53 safe integer problem. Decimal
is to solve the decimal problem of JS -2^53. This proposal introduces a new primitive type in JS: decimal
(suffix m), which declares that the number is a decimal operation.
let zero_point_three = 0.1m + 0.2m;
assert(zero_point_three === 0.3m);
// 提案中的例子
function calculateBill(items, tax) {
let total = 0m;
for (let {price, count} of items) {
total += price * BigDecimal(count);
}
return BigDecimal.round(total * (1m + tax), {maximumFractionDigits: 2, round: "up"});
}
let items = [{price: 1.25m, count: 5}, {price: 5m, count: 1}];
let tax = .0735m;
console.log(calculateBill(items, tax));
Extension - storage of floating point numbers in memory
So what does the final floating point number look like in memory? EEE754
gives a definition for floating point representation
(-1)^S M 2^E
The meaning of each symbol is as follows: S, is the sign bit, which determines whether it is positive or negative. When it is 0, it is a positive number, and when it is 1, it is a negative number. M, refers to the effective number of digits, greater than 1 and less than 2. E, is the exponent bit.
Javascript is a 64-bit double-precision floating-point number, the highest 1 bit is the sign bit S, the next 11 bits are the exponent E, and the remaining 52 bits are the significand M.
Use this visualizer to see the binary representation of floating point numbers in memory)
BigInt - Breaking the Biggest Limits
JavaScript
The Number
type is a double-precision IEEE 754 64-bit floating point type.
The maximum value in JavaScript is 2^53
.
BigInt
Arbitrary precision numeric type, which has entered the stage3 specification. BigInt
can represent arbitrarily large integers. To create a BigInt
, we just need to add an n suffix to any integer literal. For example, write 123 as 123n. This global BigInt(number) can be used to convert a Number to a BigInt, the implication being that BigInt(123) === 123n. Now let me use these two points to solve the problem we mentioned earlier:
Symbol - I am the most beautiful boy
definition
ES6 introduces a new primitive data type Symbol
, representing a unique value
let s = Symbol();
typeof s
// "symbol"
Application scenarios
- Define a set of constants to ensure that the set of constants are not equal. Eliminate magic strings
Objects are guaranteed to have different property names
let mySymbol = Symbol(); // 第一种写法 let a = {}; a[mySymbol] = 'Hello!'; // 第二种写法 let a = { [mySymbol]: 'Hello!' }; // 第三种写法 let a = {}; Object.defineProperty(a, mySymbol, { value: 'Hello!' }); // 以上写法都得到同样结果 a[mySymbol] // "Hello!"
-
Vue
provide
andinject
.provide
andinject
allow an ancestor component to inject a dependency into all its descendants, no matter how deep the component hierarchy is, and it will always take effect when the upstream-downstream relationship is established. But this intrusiveness is also very strong. UsingSymbols
askey
can avoid the interference with the component code, and there will be no problems such as the same naming
Array - a special existence in an object
Please tell me how to judge Array?
Why ask this question?
Because the array is a special existence, it is one of the data structures we usually come into contact with the most. It is a special object, and its index is the key
value of the "ordinary object". But it also has some methods that "normal objects" do not have, such as map
etc.
typeof
Yes javascript
provided operator to determine the data type, which returns a string representing the data type of the parameter. But we can't judge whether it is an array by typeof
. Because typeof
arrays and normal objects and null
all return "object"
const a = null;
const b = {};
const c= [];
console.log(typeof(a)); //Object
console.log(typeof(b)); //Object
console.log(typeof(c)); //Object
How to judge an array
-
Object.prototype.toString.call()
.
Every object that inheritsObject
hastoString
method, iftoString
method is not overridden, it will return[Object type]
type
is the type of the object
const a = ['Hello','Howard'];
const b = {0:'Hello',1:'Howard'};
const c = 'Hello Howard';
Object.prototype.toString.call(a);//"[object Array]"
Object.prototype.toString.call(b);//"[object Object]"
Object.prototype.toString.call(c);//"[object String]"
Array.isArray()
const a = []; const b = {}; Array.isArray(a);//true Array.isArray(b);//false
Array.isArray()
YesES5
Added method, when there is noArray.isArray()
, you can useObject.prototype.toString.call()
if (!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
-
instanceof
.instanceof
operator can be used to determine whether the object pointed to by theprototype
attribute of a constructor exists on the prototype chain of another object to be tested. Because the constructor of the array isArray
, the following judgment can be made. Note: Because arrays are also objects, soa instanceof Object
is alsotrue
const a = [];
const b = {};
console.log(a instanceof Array);//true
console.log(a instanceof Object);//true,在数组的原型链上也能找到Object构造函数
console.log(b instanceof Array);//false
-
constructor
. Instances instantiated through the constructor have aconstructor
attribute.
function B() {};
let b = new B();
console.log(b.constructor === B) // true
And the array is instantiated by a function called Array
. so you can
let c = [];
console.log(c.constructor === Array) // true
Note: the constructor is subject to change. Therefore, it is not recommended to judge
let c = [];
c.constructor = Object;
console.log(c.constructor === Array); // false
in conclusion
According to the above description, the judgment method of personal recommendation has the following priorities
isArray
> Object.prototype.toString.call()
> instanceof
> constructor
Summarize
This article discusses and analyzes some common data type problems in JavaScript
. I hope it can be helpful for everyone in interviews or work at ordinary times. In addition, things that may not be mentioned, such as type conversion, have the opportunity to discuss again.
Finally, welcome everyone to pay attention to my official account - front-end grocery store, discuss more technical issues~
refer to
- Difference between undefined and null
- The history of “type of null”
- 0.1 + 0.2 does not equal 0.3? Why does JavaScript have such a "saucy" operation?
- Deep understanding of precision loss in JavaScript
- JavaScript famous interview question: 0.1 + 0.2 !== 0.3, will soon be a thing of the past
- [[Translation]BigInt: Arbitrary Precision Integer in JavaScript]( https://juejin.cn/post/6844903601601511431 )
- Getting Started with ECMAScript 6
- In JavaScript, how to tell if an array is an array?
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。