引言
你知道JS有几种数据类型吗? 7种?8种?这是面试中经常提到的问题。了解数据类型及其特性对于编写高效、可靠的JS代码至关重要。本文将详细介绍 JavaScript 的数据类型及其分类。
JavaScript 数据类型分类
JS把数据类型分为两大类:简单数据类型和复杂数据类型。
- 简单的数据类型(Primitive Types)
- Numeric: 数值
- Number: JavaScript 数值类型不再细分整型、浮点型等,js 的所有数值都属于浮点型,但有范围(2^53 - 1)。
- BigInt:表示任意大小的整数,可以超出Number类型的范围,一般来表示大数字。
- String: 字符串,最抽象的数据类型,信息传播的载体,字符串必须包含在单引号、双引号或反引号之中。
- Boolean: 布尔值(true,false),逻辑运算的载体。
- Null:表示一个空值或不存在的对象。
- Undefined:未定义或不存在的值。
- Symbol:es6引入的新类型,表示独一无二的值
- Numeric: 数值
- 复杂的对象类型(Complex Types)
- Object:对象,是一种无序的数据集合。(数组、函数、日期等都属于Object)
内存分配机制
对于JS来说,依据变量内存的分配机制,简单数据类型和复杂数据类型的内存分配机制并不相同。 简单数据类型存储在栈内存,拷贝赋值,复杂数据类型存储在堆内存,引用赋值。
下面给出一个例子:
let obj1 = {
job: '前端开发工程师',
company: '字节',
}
obj.hometown = "南昌";
let a = 10;
// 拷贝
let b = a; //将a赋值给b
b = 20;
// 引用式赋值
let obj2 = obj1;
obj2.name = "李四";
console.log(a, b); // 10 20 a没有因为b的改变而改变,是b拷贝了a的值
console.log(obj1, obj2);
// { job: '前端开发工程师', company: '字节', hometown: '南昌', name: '李四' } { job: '前端开发工程师', company: '字节', hometown: '南昌', name: '李四' }
// obj1因为obj2的改变而改变了,obj2添加了name属性,obj1和obj2的引用地址都指向堆内存中同一个obj
数据类型的不同细节
下面将使用一些例子来分别介绍每种数据类型的一些小细节
Null
null
表示一个空值或不存在的对象,是一个可以赋值给变量的特殊值。null
可以来帮助垃圾回收器回收内存。
下面来简单介绍一下垃圾回收机制
在JavaScript中,垃圾回收(Garbage Collection,简称GC)是内存管理的一个重要组成部分。它允许开发者不需要手动分配和释放内存,因为垃圾回收机制可以自动处理内存的分配和释放。这大大减轻了开发者的负担,并降低了内存泄漏的风险。
将一个变量设置为 null
可以显式地解除对该变量所引用对象的引用。这样做可以帮助垃圾回收器更快地识别和回收不再使用的对象。
let a = null; // 栈内存(简单数据类型)(速度快快)
console.log(a);
// 堆内存(复杂数据类型)
let largeObject = {
data: new Array(100000000).fill('a')
}
// 释放内存 垃圾回收
// 不存在的对象
largeObject = null
Undefined
未定义
let a;
console.log(a); // 输出: undefined
Number
在 JS 中,由于数字的存储和计算方式,直接对浮点数进行计算可能会导致精度问题。这是因为 JS 使用的是 IEEE 754 标准来表示浮点数,该标准在存储和计算浮点数时可能会引入微小的误差。
// 数值类型 Number 不擅长计算
// 强大表现力,前端
// 0.1 js 以二进制存储 没有高精度
let a = 0.1;
let b = 0.2;
console.log(a + b); //0.30000000000000004
//0.1和0.2在二进制表示中是无限循环的小数,而计算机只能存储有限的位数,因此会导致舍入误差。
BigInt
// 能表示的数字范围有限
// let num1 = 99999999999999999999999999;
// let num2 = 14646513312312132135664564;
// console.log(num1 + num2);
// 1.1464651331231214e+26 明显精确度不够,不准确
// bigint
let num1 = 99999999999999999999999999n;
let num2 = 14646513312312132135664564n;
console.log(num1 + num2);
// 114646513312312132135664563n 这回正确了
Symbol
Symbol
是唯一值,以函数的形式创建,简单值。哪怕标签一样,值绝对不一样。
// Symbol es6 的新数据类型 独一无二 标签
// 函数一样的外观,但是是简单数据类型
console.log(Symbol('张三') === Symbol('张三')); //false
一切皆对象
你写的代码复杂数据类型都是对象,而简单数据类型中的 string、number、boolean、symbol、bigInt 又和基本包装类型有了调用原型方法后删除实例的关系。简单来说,它们既享受了基本类型的轻量占内存小,又获得了调用内置构造函数的各种原型方法 基本类型中,除了 null、undefined,其余的都与对象有关,而引用类型就是指对象,所以可以说 JS 中的一切都是对象。
// js 是一切皆对象 面向对象的很存粹
// 可以看到,无论是复杂数据类型,还是简单数据类型,都有内置的方法
"123".length
let arr = [1, 2, 3, 4, 5]
arr.customProperty = "This is a custom property"
arr.push(6)
arr.forEach(function (item) {
console.log(item);
})
console.log(arr);
确定变量的数据类型
typeof操作符
使用typeof
可以得到表示操作数的类型,但有缺陷,null
类型将会给出object
的结果,因为在JS引擎中,类型信息通常以二进制形式存储。每个值都带有一个类型标签(Type Tag)(前三位),用于标识该值的类型。但null
的前三位与object
的前三位相同,都是000。
let a = 1;
// typeof js 类型 运算符
// console.log(typeof a, typeof (a)); number number
console.log(typeof a, +'1'); //number
console.log(typeof "hello"); //string
console.log(typeof true); //boolean
console.log(typeof 12n); //bigint
console.log(typeof Symbol()); //symbol
console.log(typeof undefined); //undefined
console.log(typeof null); // object
//这是 JS 语言设计中的一个历史遗留问题。在 JS 的早期版本中,null被设计为表示一个空的对象指针,因此 typeof null 返回 object。尽管这在逻辑上并不正确,因为null实际上并不是一个对象,但为了保持向后兼容性,这个特性一直被保留至今。
console.log(typeof function () { }); //function
其他准确的检测方法
Object.prototype.toString.call
console.log(Object.prototype.toString.call(null)); // "[object Null]"
通过调用 Object.prototype.toString
方法并传入要检测的值,返回一个表示该值类型的字符串。可以准确判断所有数据类型,包括null
。
结论
理解 JavaScript 中的数据类型是编写高效、可靠和易于维护代码的基础。总之,通过对数据类型和内存管理的深入理解,结合不断的学习和实践,你将能够编写出更高效、更可靠的 JavaScript 代码,成为一名更加出色的开发者。希望你在编程的道路上不断进步,享受编程带来的乐趣和成就感。