You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
30-Days-Of-JavaScript/js_notes/00-concepts/value-vs-reference.md

2.7 KiB

通用概念 · 值 vs 引用(value vs reference)

跨主题核心概念。函数传参、对象、数组章都会反复用到。JS 最重要的底层认知之一。

一、两大阵营

原始值(primitive) 引用类型(reference)
有哪些 number string boolean undefined null bigint symbol object array function
变量里存的 值本身 指向对象的地址(引用)
赋值给别人时 复制一份副本 共享同一个对象
能原地改内部吗 不可变 可以

一句话:原始值"复制",引用类型"共享"。

二、决定性证据:改一个,另一个变不变?

原始值 → 复制副本,各改各的

let a = 'hello'
let b = a // b 拿到的是【副本】
a = 'world' // 改 a
console.log(b) // 'hello'  ← b 没变!

引用类型 → 共享同一个,牵一发动全身

let x = [1, 2, 3]
let y = x // x 和 y 指向【同一个】数组
x[0] = 99 // 改 x
console.log(y) // [99, 2, 3]  ← y 跟着变了!

这就是分水岭:值类型复制、互不影响;引用类型共享、一改都变。

三、字符串不可变:word[0] = 'Y' 会怎样

字符串是原始值,不是对象,没有"内部格子供你寻址修改"。

let word = 'hello'
word[0] = 'Y' // 静默无效(严格模式下报错)
console.log(word) // 'hello'  ← 没变!
  • 能读不能写:word[0] 读字符 OK,但赋值无效
  • word[0] 读出来的是复制的值 'h',和 word 内部已无关系 —— 不通向本体
  • 严格模式('use strict')下会报 TypeError: Cannot assign to read only property

想"改"字符串 → 造个新的再赋值回去:

let word = 'hello'
word = 'Y' + word.slice(1) // 'Y' + 'ello'
console.log(word) // 'Yello'

(这正是 04-strings D 题"首字母大写"的原理:新字符 + 剩余,再赋值)

四、对比:数组可以原地改

长得像(都用 [0]),行为相反:

let arr = [1, 2, 3]
arr[0] = 99 // ✅ 数组是引用类型 → 通向对象内部 → 改得动
console.log(arr) // [99, 2, 3]

let str = 'abc'
str[0] = 'X' // ❌ 字符串不可变 → 无效
console.log(str) // 'abc'

五、为什么这很重要(伏笔)

  • 函数传参:传原始值 = 传副本(函数内改不动外面);传对象 = 传引用(函数内能改到外面的对象)
  • 复制对象/数组:let b = a 只是共享,不是真复制;要真复制得用别的手段(后面学)
  • 很多"我明明没改它怎么变了"的 bug,根源都是引用共享

一句话记死

原始值(含字符串)= 复制的值,不可变,[0] 只能读;引用类型(对象/数组)= 共享的地址,可原地改,[0] 通向本体。