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.
83 lines
2.7 KiB
83 lines
2.7 KiB
# 通用概念 · 值 vs 引用(value vs reference)⭐⭐
|
|
|
|
> 跨主题核心概念。函数传参、对象、数组章都会反复用到。JS 最重要的底层认知之一。
|
|
|
|
## 一、两大阵营
|
|
|
|
| | 原始值(primitive) | 引用类型(reference) |
|
|
|---|---|---|
|
|
| 有哪些 | `number` `string` `boolean` `undefined` `null` `bigint` `symbol` | `object` `array` `function` |
|
|
| 变量里存的 | **值本身** | 指向对象的**地址(引用)** |
|
|
| 赋值给别人时 | **复制一份副本** | **共享同一个对象** |
|
|
| 能原地改内部吗 | ❌ 不可变 | ✅ 可以 |
|
|
|
|
**一句话:原始值"复制",引用类型"共享"。**
|
|
|
|
## 二、决定性证据:改一个,另一个变不变?
|
|
|
|
### 原始值 → 复制副本,各改各的
|
|
```js
|
|
let a = 'hello'
|
|
let b = a // b 拿到的是【副本】
|
|
a = 'world' // 改 a
|
|
console.log(b) // 'hello' ← b 没变!
|
|
```
|
|
|
|
### 引用类型 → 共享同一个,牵一发动全身
|
|
```js
|
|
let x = [1, 2, 3]
|
|
let y = x // x 和 y 指向【同一个】数组
|
|
x[0] = 99 // 改 x
|
|
console.log(y) // [99, 2, 3] ← y 跟着变了!
|
|
```
|
|
|
|
> 这就是分水岭:值类型复制、互不影响;引用类型共享、一改都变。
|
|
|
|
## 三、字符串不可变:`word[0] = 'Y'` 会怎样
|
|
|
|
字符串是**原始值**,不是对象,没有"内部格子供你寻址修改"。
|
|
|
|
```js
|
|
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`
|
|
|
|
**想"改"字符串 → 造个新的再赋值回去:**
|
|
```js
|
|
let word = 'hello'
|
|
word = 'Y' + word.slice(1) // 'Y' + 'ello'
|
|
console.log(word) // 'Yello'
|
|
```
|
|
(这正是 04-strings D 题"首字母大写"的原理:新字符 + 剩余,再赋值)
|
|
|
|
## 四、对比:数组可以原地改
|
|
|
|
长得像(都用 `[0]`),行为相反:
|
|
|
|
```js
|
|
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]` 通向本体。**
|