在我们深入学习数组的高级功能之前,需要理解一个重要的概念:数组变量和基础类型变量的行为不同。
在我们学习编程时,会遇到不同类型的数据。基础类型变量是最简单的数据类型,它们每次只能存储一个单一的数据值。
基础类型(Primitive Types)是编程中最基本的数据类型
常用的3种基础类型:
100、3.14、-5"你好"、"Hello"、'编程'true(真)和 false(假)重要观察:
score2 = score1 时,系统将 score1 存储的值100完整复制给 score2score2 的值时,score1 保持不变,这证明了两个变量是完全独立的理解基础类型变量的独立性:
值复制 (Value Copy)是编程中的一个重要概念。当我们在基础类型变量之间进行赋值时,发生的是值复制:
重要提示:值复制是基础类型变量的行为特征。而我们前面刚刚学习的数组类型将展示完全不同的行为——引用复制,这是我们接下来要深入理解的关键概念。
停下来思考一下:
我们明明只给 inventory2 添加了物品,为什么 inventory1 的内容也跟着变化了?这和我们之前学习的基础类型完全不同!
让我们回顾一下在数组基础课程中学到的比喻,然后深入理解:
回顾:基础类型的独立储物盒:
let score = 100;)现在学习数组的储物柜系统:
let scores = [100, 85, 92];)理解这个比喻:
重要对比:
现在让我们回到原始的例子,用储物柜比喻来理解:
关键理解:
现在我们引入专业的技术术语:
引用 (Reference) 就是我们比喻中的"钥匙",它是:
你可能会问:为什么要这样复杂的设计?直接复制内容不是更简单吗?
在解释这个之前,我们需要理解什么是内存。
内存(Memory)是计算机的短期记忆系统,就像我们人类的短期记忆能力:
🧠 人类记忆 vs 计算机内存的类比:
📊 计算机内存的特点:
💡 为什么这个概念重要? 理解内存有限性有助于我们:
现在我们理解了内存的概念,就能明白引用设计的优势了:
1. 内存效率:大数组只需要在内存中存储一份
想象一下:
内存使用情况:
2. 同步更新:多个"观察者"看到的都是最新的数据
因为所有变量都指向同一个数组:
3. 性能优化:复制引用比复制大量数据快得多
总结:引用设计是一种聪明的方法,让我们用最少的内存空间,实现最快的访问速度,还能保证所有变量都能看到最新的数据!
让我们深入理解 === 这个相等运算符在不同类型数据上的行为差异。
还记得在数据类型基础课程中,我们学习了基础类型的相等判断 === 吗?
基础类型相等判断的特点:
现在让我们看看数组类型的相等判断,你会发现完全不同的结果:
停下来思考一下:
10 === 10 返回 true,但 [10] === [10] 返回 false?array1 和 array2 内容相同,但 array1 === array2 返回 false?array1 和 array3 的相等判断返回 true?基础类型(数字、字符串、布尔值):
10 === 10:比较值是否相同数组类型:
[10] === [10] 的左边和右边实际上是两个完全不同的数组,就像两个不同的储物柜[10] === [10]:比较引用是否相同(是否指向同一个数组)[10],但它们是独立创建的,所以不相等场景1:不同的储物柜,内容相同
arrayA 和 arrayB 就像两个不同的储物柜arrayA === arrayB 返回 false场景2:同一把钥匙的不同拷贝
arrayC 和 arrayD 就像两把开同一个储物柜的钥匙arrayC === arrayD 返回 true记住这个关键区别:
| 数据类型 | === 比较的是什么? | 例子 | 结果 |
|---|---|---|---|
| 基础类型 | 值是否相同 | 10 === 10 | true |
| 数组类型 | 引用是否相同 | [10] === [10] | false |
为什么这样设计?
这就是为什么我们需要理解引用概念的原因!数组的相等判断逻辑与基础类型完全不同。
既然 === 不能比较数组内容,那我们如何判断两个数组的内容是否相同呢?
基本思路:
理解这个算法:
长度优先检查:
逐个元素比较:
arraysEqual 记录比较结果,初始为 truefor 循环遍历数组的每个位置array1[i] !== array2[i] 比较对应位置的元素arraysEqual 改为 false,并用 break 跳出循环最终结果:
arraysEqual 仍然是 true,说明所有元素都相同arraysEqual 会被改为 false理解了数组相等判断后,我们现在知道:如果我们需要两个内容相同但独立的数组,需要创建真正的独立副本(两个不同的储物柜)。
这是最基础的方法,让我们一步步手动创建副本:
理解手动构建的过程:
manualCopy = []slice 是什么意思?
slice 在英语中是"切片"的意思,就像切面包片一样,可以从数组中切出一片。
slice() 方法的基本用法:
在编程中,我们经常使用数学中的区间概念来表示范围。
什么是区间? 区间就是表示一段范围的符号,就像说"从第1页到第3页"一样。
两种区间类型:
[ ]:包括两端的值,比如 [1, 3] 表示"从1到3,包括1和3"( ):不包括两端的值,比如 (1, 3) 表示"大于1且小于3,不包括1和3"半开半闭区间:
[1, 3):表示"从1到3,包括1但不包括3"(1, 3]:表示"从1到3,不包括1但包括3"为什么编程中常用半开区间 [开始, 结束)?
结束 - 开始 = 元素个数,比如 3 - 1 = 2 个元素[0, 3) 和 [3, 6]重要说明:
slice() 复制整个数组slice(开始索引) 从指定索引复制到末尾slice(开始索引, 结束索引) 复制从开始索引到结束索引(不包括结束索引)的元素使用 slice() 创建独立副本:
| 方法 | 语法 | 优点 | 缺点 | 推荐场景 |
|---|---|---|---|---|
| for循环 + push | 代码较长,逻辑清晰 | 理解底层原理,适合学习 | 代码复杂 | 学习和理解原理时 |
| slice() | array.slice() | 传统语法,兼容性好 | 语法稍长,功能丰富 | 需要部分复制时 |
使用共享的情况(多个变量指向同一个数组):
使用独立副本的情况(每个变量有自己的数组):
| 数据类型 | 赋值行为 | 修改影响 | 相等判断 |
|---|---|---|---|
| 基础类型(数字、字符串、布尔值) | 创建独立副本 | 互不影响 | 比较值:10 === 10 → true |
| 数组类型 | 共享同一个数组 | 相互影响 | 比较引用:[10] === [10] → false |
引用 vs 值的核心区别:
基础类型变量(数字、字符串、布尔值):
数组变量:
1. 比较数组内容是否相同
2. 创建数组独立副本的两种方法
array.slice() 复制整个数组(推荐)选择建议:
引用概念是编程的重要基础,理解了它你就掌握了数据在程序中的工作方式!