还在被JavaScript数据类型搞糊涂?一篇文章帮你彻底搞懂!

掌握数据类型,写出更健壮可靠的代码

如果你是初学者,可能会对 nullundefined 的区别感到困惑;如果你已经有经验,或许曾在类型判断和引用赋值上踩过坑。不用担心,这篇文章将带你从入门到精通,彻底搞懂 JavaScript 数据类型的所有细节。

一、JavaScript 的两大数据类型家族

JavaScript 的数据类型主要分为两大类:基本数据类型 (原始类型)和引用数据类型(对象类型)。

截至 ES2023,JavaScript 共有 8 种数据类型。

基本数据类型包括:

  1. Undefined :表示变量已声明但未赋值,只有一个值 undefined
  2. Null :表示空值或不存在的对象,只有一个值 null
  3. Boolean :表示逻辑值,只有 truefalse 两个值
  4. Number :表示整数或浮点数,还包括特殊值 NaN(Not a Number)和 Infinity
  5. String:表示文本数据,可以用单引号、双引号或反引号包裹
  6. Symbol:ES6 新增,表示唯一的、不可变的值
  7. BigInt:ES2020 新增,表示任意精度的整数

引用数据类型 主要是 Object,还包括其派生类型:

  • Object:键值对的集合
  • Array:有序的元素集合
  • Function:可执行的对象
  • 其他内置对象:如 Date、RegExp、Map、Set 等

二、基本数据类型 vs 引用数据类型:核心区别

为什么要把数据类型分成这两大类呢?因为它们在使用上有根本性的区别。

存储位置不同 基本数据类型存储在栈内存 中,直接存储值本身。引用数据类型存储在堆内存中,变量在栈内存中存储的是指向堆内存的地址引用。

赋值方式不同 基本数据类型赋值是复制值,赋值后两个变量互不影响。

javascript 复制代码
let a = 10;
let b = a; // 值拷贝
b = 20;
console.log(a); // 10(互不影响)

引用数据类型赋值是复制引用,赋值后两个变量指向同一个对象。

javascript 复制代码
let obj1 = { name: 'John' };
let obj2 = obj1; // 指针拷贝
obj2.name = 'Alice';
console.log(obj1.name); // 'Alice'(指向同一对象)

比较方式不同 基本数据类型比较的是是否相等。

javascript 复制代码
5 === 5; // true

引用数据类型比较的是内存地址(是否同一个对象)。

javascript 复制代码
{} === {}; // false

是否可变 基本数据类型是不可变 的,修改时会创建新值。引用数据类型是可变的,可以直接修改对象属性。

三、typeof:类型判断的常用工具

typeof 操作符是最常用的类型判断工具,它可以返回一个字符串,表示变量的数据类型。

javascript 复制代码
console.log(typeof "Hello"); // "string"
console.log(typeof 42); // "number"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object"(注意:这是一个历史遗留问题)
console.log(typeof Symbol("id")); // "symbol"
console.log(typeof 123n); // "bigint"
console.log(typeof {}); // "object"
console.log(typeof []); // "object"
console.log(typeof function() {}); // "function"

需要注意的是,typeof null 返回 "object" 是 JavaScript 早期实现的一个历史遗留问题,而不是因为 null 本身是一个对象。

另外,typeof 对于数组也返回 "object",这显然不够精确。对于数组的类型判断,可以使用 Array.isArray() 方法。

javascript 复制代码
console.log(Array.isArray([])); // true
console.log(Array.isArray({})); // false

四、null vs undefined:看似相似却不同

很多开发者对 nullundefined 的区别感到困惑。它们都表示某种"空"的概念,但在语义和使用上有所不同。

undefined 表示变量已声明但未赋值,是 JavaScript 引擎给变量分配的默认值。

javascript 复制代码
let x;
console.log(x); // 输出: undefined

null 表示"空"或"无值",是一个显式赋值的空对象指针,通常用于手动释放对象引用。

javascript 复制代码
let user = null; // 主动设置为空

在比较时,它们也表现出有趣的行为:

javascript 复制代码
console.log(null == undefined); // true(抽象相等比较)
console.log(null === undefined); // false(严格相等比较,类型不同)

五、特殊数据类型:Symbol 和 BigInt

Symbol 是 ES6 引入的一种新的原始数据类型,表示唯一的值。即使使用相同的描述创建两个 Symbol,它们也是不相等的。

javascript 复制代码
let s1 = Symbol('id');
let s2 = Symbol('id');
console.log(s1 === s2); // false

Symbol 常用于对象属性的键,确保属性名的唯一性,避免属性冲突。

javascript 复制代码
const ID = Symbol('id');
const user = {
  [ID]: 123,
  name: 'Alice'
};

BigInt 是 ES2020 引入的一种新的原始数据类型,用于表示任意精度的整数。JavaScript 的 Number 类型无法安全地表示大于 2^53 的整数,BigInt 解决了这个问题。

javascript 复制代码
const bigNum = 9007199254740991n; // 注意后面的 n
const alsoBig = BigInt("9007199254740991");

BigInt 不能直接与 Number 类型进行混合运算,需要先进行转换。

六、常见陷阱与最佳实践

陷阱一:意外修改共享对象由于引用类型的赋值是复制引用而不是值,可能会意外修改共享对象。

javascript 复制代码
let obj1 = { name: 'John' };
let obj2 = obj1; // 复制引用,而不是对象本身
obj2.name = 'Alice'; // 修改了 obj1 和 obj2 共享的对象
console.log(obj1.name); // 'Alice'

解决方案:需要时使用深拷贝创建新对象。

陷阱二:NaN 的特殊行为 NaN(Not a Number)是一个特殊的数字值,表示不是一个数字。它有一个独特的行为:它是 JavaScript 中唯一不等于自身的值。

javascript 复制代码
console.log(NaN === NaN); // false

解决方案:使用 isNaN() 函数或 Number.isNaN() 方法检查 NaN。

javascript 复制代码
console.log(isNaN(NaN)); // true
console.log(isNaN("abc")); // true(无法转换为数字)
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN("abc")); // false(Number.isNaN 更严格)

最佳实践一:使用全等比较 尽量使用 === 而不是 == 进行比较,避免隐式类型转换带来的意外结果。

最佳实践二:明确的类型检查使用组合方式进行类型检查,提高代码的健壮性。

javascript 复制代码
// 检查数组
function isArray(obj) {
  return Array.isArray ? Array.isArray(obj) : Object.prototype.toString.call(obj) === "[object Array]";
}

// 检查 null
function isNull(obj) {
  return obj === null;
}

// 检查 undefined
function isUndefined(obj) {
  return obj === void 0; // 或者 typeof obj === "undefined"
}

七、总结

JavaScript 的数据类型看似简单,但深入理解它们对于编写健壮、可靠的代码至关重要。基本数据类型和引用数据类型在存储、赋值和比较上的根本差异,是许多常见编程错误的根源。

通过掌握 typeofinstanceofObject.prototype.toString.call() 等类型判断方法,以及理解 nullundefined 的区别,你可以避免许多常见的陷阱。

希望这篇文章帮助你彻底理解了 JavaScript 的数据类型。如果有任何问题或想法,欢迎在评论区留言讨论!

相关推荐
椒盐螺丝钉13 分钟前
TypeScript类型兼容性
运维·前端·typescript
_JinHao17 分钟前
Cesium Viewer对象详解——Cesium基础笔记(快速入门)
前端·javascript·笔记·3d·webgl
正义的大古21 分钟前
OpenLayers地图交互 -- 章节十三:拖拽旋转交互详解
javascript·vue.js·openlayers
r0ad1 小时前
从痛点到解决方案:为什么我开发了Chrome元素截图插件
前端·chrome
OEC小胖胖1 小时前
连接世界:网络请求 `wx.request`
前端·微信小程序·小程序·微信开放平台
jingling5551 小时前
解决微信小程序真机调试中访问本地接口 localhost:8080 报错
前端·微信小程序·小程序
en-route1 小时前
使用 Flask 构建 Web 应用:静态页面与动态 API 访问
前端·python·flask
IT_陈寒1 小时前
Vite 5年迭代揭秘:3个核心优化让你的项目构建速度提升200%
前端·人工智能·后端
怎么吃不饱捏1 小时前
vue3+vite,引入阿里巴巴svg图标,自定义大小颜色
前端·javascript·vue.js
无敌最俊朗@1 小时前
MQTT 关键特性详解
java·前端·物联网