基本类型与引用类型的核心区别在于内存存储方式:基本类型值存栈中,赋值传参时复制值;引用类型变量存堆中对象地址,赋值传参时复制地址,导致共享修改和相等性判断差异。

基本类型和引用类型不是语法细节,而是影响代码可读性、可维护性和运行行为的底层机制。理解它们的区别,能直接减少隐式bug、避免意外共享、提升协作效率。
内存存储方式决定行为逻辑
基本类型(如 number、string、boolean)的值直接存在栈中,赋值或传参时复制的是值本身;引用类型(如 object、array、function)变量存的是堆中对象的地址,赋值或传参时复制的是这个地址。
- 这意味着修改一个基本类型变量,不会影响另一个同值变量
- 而修改一个引用类型变量所指向的对象(比如往数组 push 一个元素),所有持有该地址的变量都会看到变化
- 判断两个变量是否“相等”时,=== 对基本类型比值,对引用类型比地址——即使内容完全一样,两个独立创建的对象也不相等
赋值与函数传参中的常见陷阱
很多看似奇怪的“值被改了”或“没改”的问题,根源都在这里。
- 给函数传入一个数组,函数内部 push 或 splice,原数组会变;但传入一个数字,函数里重新赋值,外部变量不受影响
- 用 let obj1 = {a: 1}; let obj2 = obj1; 后修改 obj2.a,obj1.a 也会变——这不是“绑定”,只是两个变量指向同一块内存
- 需要真正拷贝对象时,得显式处理:浅拷贝用 {...obj} 或 Array.from(arr),深拷贝考虑 structuredClone() 或 JSON 序列化(注意限制)
类型判断与调试技巧
仅靠 typeof 很难区分引用类型(所有对象都返回 "object"),容易误判 null、数组、日期等。
- 判断数组:Array.isArray(value)
- 判断 null:value === null(typeof null 返回 "object",是历史遗留 bug)
- 判断普通对象(非 null、非数组、非日期等):Object.prototype.toString.call(value) === "[object Object]"
- 开发中多用 console.log({ value, type: typeof value }) 或直接用 debugger 查看变量实际结构
代码质量落地建议
把类型意识转化为日常习惯,比写注释更有效。
- 函数参数如果是引用类型,文档或 JSDoc 中明确写出“会修改原对象”或“返回新对象”,避免调用方误解
- 组件 props 设计时,避免让父组件传来的对象被子组件直接修改;优先用不可变更新(如 {...state, x: y})或提供 setter 函数
- 单元测试中,对引用类型输入做隔离:不要复用同一个对象实例,防止测试间相互污染
- ESLint 可启用 no-param-reassign 规则,禁止直接修改函数参数(尤其对引用类型)

















