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/06-arrays.js

213 lines
9.8 KiB

// 06 · 数组(Array)
// 学练复习一体:概念总结 → 示范 → 轮到你
// 跑法:Quokka / 右上角 ▷ / node 本文件
// 示范区带预期输出;轮到你区只给要求,自己写
// ═════ 概念总结 ═════
//
// 数组 = 有序的一组值,用 [] 包起来。JS 里最常用的数据结构。
//
// 0. 回顾:数组是"引用类型" ⭐
// 复习 00-concepts/value-vs-reference.md:数组是对象/引用类型,
// - typeof [1,2,3] → 'object'(不是 'array')
// - 判断是不是数组用 Array.isArray(arr)
// - 可以原地修改(和字符串不可变相反)
// - let b = a 是共享同一个数组,不是复制
//
// 1. 创建 & 取值
// const fruits = ['apple', 'banana', 'cherry']
// fruits[0] // 'apple' ← 下标从 0 开始
// fruits[2] // 'cherry'
// fruits[fruits.length - 1] // 'cherry' ← 最后一个
// fruits.length // 3 ← 长度(属性,不加括号)
//
// 2. 增删(会改原数组)⭐
// ┌─────────────┬──────────────────────────────┬────────┐
// │ 方法 │ 作用 │ 位置 │
// ├─────────────┼──────────────────────────────┼────────┤
// │ .push(x) │ 加到末尾 │ 尾 │
// │ .pop() │ 删最后一个(并返回它) │ 尾 │
// │ .unshift(x) │ 加到开头 │ 头 │
// │ .shift() │ 删第一个(并返回它) │ 头 │
// └─────────────┴──────────────────────────────┴────────┘
// 记忆:push/pop 管尾,shift/unshift 管头。这四个都直接改原数组。
//
// 3. 查找
// ┌────────────────┬──────────────┬────────────────────┐
// │ 方法 │ 作用 │ 返回 │
// ├────────────────┼──────────────┼────────────────────┤
// │ .includes(x) │ 是否包含 │ true/false │
// │ .indexOf(x) │ 首次出现下标 │ 数字;找不到 -1 │
// └────────────────┴──────────────┴────────────────────┘
//
// 4. 截取 & 拼接
// .slice(start, end) —— 不改原数组,返回新的(不含 end):
// const a = [1, 2, 3, 4, 5]
// a.slice(1, 3) // [2, 3] ← 和字符串 slice 一样,不含 end
// a.slice(2) // [3, 4, 5]
// .concat() / 展开 —— 合并数组:
// [1, 2].concat([3, 4]) // [1,2,3,4]
// [...[1, 2], ...[3, 4]] // [1,2,3,4] ← 展开语法(后面章节详讲)
//
// 5. ⚠️ .splice() —— 强力但会改原数组
// splice(起点, 删几个, 要插入的...) 能删能插,直接改原数组:
// const a = [1, 2, 3, 4]
// a.splice(1, 2) // 从下标1删2个 → a: [1, 4]
// const b = ['a', 'd']
// b.splice(1, 0, 'b', 'c') // 下标1删0个,插入 b,c → b: ['a','b','c','d']
// 第一个参数是"下标",插入发生在该下标之前 ⭐
// 插入的新元素会占据 index 这个位置,原本在此及以后的元素全部后移。
// 缝隙心智模型(同时解释 slice):把下标看成元素之间的"缝":
// [ first , third ]
// ↑ ↑ ↑
// 缝0 缝1 缝2
// splice(index, 0, x) = 把 x 塞进"缝 index":
// ['first','third'].splice(0, 0, 'x') // ['x','first','third'] 塞缝0=最前
// ['first','third'].splice(1, 0, 'x') // ['first','x','third'] 塞缝1=中间 ✅
// ['first','third'].splice(2, 0, 'x') // ['first','third','x'] 塞缝2=最后(index=length)
// 同一模型解释 slice(1,3):从缝1切到缝3,夹住的是下标1、2 → 所以"不含 end"。
// ⚠️ splice 的返回值是"被删元素",不是修改后的数组:
// const q = ['first', 'third']
// const removed = q.splice(1, 0, 'second')
// console.log(q) // ['first','second','third'] ← 改的是原数组,要打印它
// console.log(removed) // [] ← 返回值是被删的元素,删0个就是空数组
// 所以插入后要 console.log(q)(原数组),别打印 q.splice(...) 的返回值。
// ⚠️ 别把 slice(切片,不改原,返回切出的新数组)和 splice(剪接,改原,
// 返回被删元素)搞混!差一个字母,行为完全不同。
//
// 6. 数组 ↔ 字符串
// ['a', 'b', 'c'].join('-') // 'a-b-c' ← 数组转字符串
// 'a-b-c'.split('-') // ['a','b','c'] ← 字符串转数组(复习 04)
//
// 7. 一个坑:== 比不了数组内容
// 数组是引用类型,=== 比的是"是不是同一个对象",不是内容:
// [1, 2] === [1, 2] // false! ← 两个不同的数组对象
// 比内容要逐个比,或转成字符串比(后面有更好的办法)。
//
// ✅ 本主题要点回顾
// 1. 数组是引用类型(可原地改;let b=a 是共享)⭐
// 2. [0] 取值,下标从 0;.length 长度
// 3. push/pop 管尾,shift/unshift 管头,都改原数组 ⭐
// 4. .slice 不改原(返回切出的新数组);.splice 改原(删/插,返回被删元素,
// 插入后要打印原数组)—— 别搞混 ⭐
// splice 第一个参数是下标,插入在其之前;用"缝隙模型"记(缝index)
// 5. .join() 数组→字符串,.split() 字符串→数组
// 6. [1,2] === [1,2] 是 false(比的是对象不是内容)⭐
// ═════ 示范 ═════
// ── 0. 数组是引用类型(复习)──────────────────────
console.log(typeof [1, 2, 3]) // object ← 不是 'array'
console.log(Array.isArray([1, 2, 3])) // true
// ── 1. 创建 & 取值 ───────────────────────────────
const fruits = ['apple', 'banana', 'cherry']
console.log(fruits[0]) // apple
console.log(fruits[fruits.length - 1]) // cherry
console.log(fruits.length) // 3
// ── 2. 增删:push/pop 管尾,shift/unshift 管头 ⭐ ──
const a = [1, 2, 3]
a.push(4)
console.log(a) // [1, 2, 3, 4]
a.pop()
console.log(a) // [1, 2, 3]
a.unshift(0)
console.log(a) // [0, 1, 2, 3]
a.shift()
console.log(a) // [1, 2, 3]
// ── 3. 查找 ──────────────────────────────────────
console.log([1, 2, 3].includes(2)) // true
console.log([1, 2, 3].indexOf(3)) // 2
console.log([1, 2, 3].indexOf(9)) // -1
// ── 4. slice 不改原(不含 end)────────────────────
const b = [1, 2, 3, 4, 5]
console.log(b.slice(1, 3)) // [2, 3]
console.log(b) // [1, 2, 3, 4, 5] ← 原数组没变
// ── 5. splice 改原(删/插)⚠️ 别和 slice 混 ────────
const c = [1, 2, 3, 4]
c.splice(1, 2) // 从下标1删2个
console.log(c) // [1, 4]
// ── 6. 数组 ↔ 字符串 ─────────────────────────────
console.log(['a', 'b', 'c'].join('-')) // a-b-c
console.log('a-b-c'.split('-')) // ['a', 'b', 'c']
// ── 7. === 比不了内容 ────────────────────────────
console.log([1, 2] === [1, 2]) // false ← 是两个不同对象
// ═════ 轮到你 ═════
// 👇 轮到你(只给要求,自己写代码)
// 练习 A:有 const nums = [10, 20, 30]
// ① 在末尾加上 40
// ② 在开头加上 5
// ③ 打印最终数组和它的长度
// (最终应是 [5, 10, 20, 30, 40],长度 5)
const num = [10, 20, 30]
num.push(40)
num.unshift(5)
console.log(num)
console.log(num.length)
// 练习 B:有 const colors = ['red', 'green', 'blue']
// ① 用 includes 判断有没有 'green'
// ② 打印 'blue' 的下标
// ③ 用 join 把它们拼成 'red, green, blue'(用 ', ' 连接)
const colors = ['red', 'green', 'blue']
console.log(colors.includes('green'))
console.log(colors.indexOf('blue'))
console.log(colors.join(', '))
// 练习 C:有 const letters = ['a', 'b', 'c', 'd', 'e']
// 用 slice 取出中间三个 ['b', 'c', 'd'],并打印。
// 打印完再打印一次 letters 本身,确认它没被改动。
const letters = ['a', 'b', 'c', 'd', 'e']
console.log(letters.slice(1, 4))
console.log(letters)
// 练习 D(动脑):有 const q = ['first', 'third']
// 用 splice 在 'first' 和 'third' 之间插入 'second',
// 让它变成 ['first', 'second', 'third'],打印。
// 提示:splice(位置, 删几个, 插入什么) —— 这里"删几个"是 0
const q = ['first', 'third']
// ❌ splice 返回的是“被删除的元素",不是修改后的数组
// console.log(q.splice(0, 0, 'second'))
// ✅
q.splice(1, 0, 'second')
console.log(q)
// 练习 E(挑战):有 const sentence = 'I love java script'
// ① 用 split 把它拆成单词数组
// ② 用 join 把单词用 '-' 重新连起来
// (最终得到 'I-love-java-script')
const sentence = 'I love java script'
// ❌
// sentence.split(' ')
// console.log(sentence)
// sentence.join('-')
// ❌ 直接写 array = ... 而没声明。这在普通模式下能跑(JS 会偷偷创建一个全局变量),但这是坏习惯,而且埋雷:
// - 严格模式('use strict')下会直接报错:array is not defined
// - 它会"泄漏"成全局变量,以后可能和别处撞名,制造诡异 bug
// array = sentence.split(' ')
// ✅
const array = sentence.split(' ')
console.log(array.join('-'))