数组的32场演唱会

本文详细介绍JavaScript数组的32种方法,涵盖数组判断、内容判断、内容获取、构造、改造、遍历、累加、转字符串等方面。通过生动的例子和比喻帮助读者深入理解并灵活运用这些方法。


你有没有遇到过如下的场景。coding中当你要处理一个数组的时候,脑海里只浮现出了forEach;面试中,当面试官让你说说数组的方法的时候,脑海里只浮现出了forEach;做梦时当一个数组追杀你,你能想到的只有用forEach来抵抗。如果是,那么你一定要听一听今年数组举办的32场演唱会。只要听完了这32场演唱会,保证下次当你遇到数组的时候,闭着眼睛都能想出32种方法对付他们。另外,友情提示,结尾有彩蛋。

书归正传,数组 是javascript中最常用的引用对象类型之一,在javascript的各种常用的数据结构中,诸如队列、栈,他们的基本实现方式用的就是数组,因此掌握数组的各项操作也就成为能否自如操控数据结构的要点。截止到ES8,数组目前共有32种方法,可大体分为如下几种:

  • 数组的判断 1个方法

  • 数组内容的判断 3个方法

  • 数组内容的获取 4个方法

  • 数组的构造 6个方法

  • 数组的改造 9个方法

  • 数组的循环遍历 4个方法

  • 数组的累加 2个方法

  • 数组转字符串 3个方法

数组的判断 1个方法

Array.isArray()

  • 语法:Array.isArray(obj)

  • 参数:需要检查的对象

  • 返回:true,false

开唱:

判断数据类型的方法有几个比如使用typeof,instanceof,那么为什么还要有isArray方法呢?

首先说说typeof。众所周知,javascript有五个基本数据类型undefined,null,number,string,boolean,还有引用数据类型Object,Array,Function,Data,Date,RegExp等typeof 运算符返回一个用来表示表达式数据类型的字符串,可能的字符串有:"number"、"string"、"boolean"、"object"、"function" 和 "undefined"。这里面是没有Array的,无论引用的是什么类型的对象,它都返回 "object",因此typeOf是不能用来判断数组的。那么instanceof呢?通常来讲,使用instanceof就是判断一个实例是否属于某种类型,这是基于javascript的原型继承机制的,然而在浏览器的环境中如果使用iframe,则可能出现多个不同的全局变量,从而无法发挥instanceof的作用,因此,Array.isArray()成功荣升为最靠谱的检测方法。但话说回来,其实它的的实现方式还是很简单的:

   
  1. Array.isArray = function(arg) {

  2.    return Object.prototype.toString.call(arg) === '[object Array]';

  3. };

需要特别指出的是,Array.isArray()方法是一个静态方法,只能通过Array对象来调用

数组内容的判断 3个方法

Array.prototype.every()

  • 语法:arr.every(callback[, thisArg])

  • 参数:

    • currentValue 当前值

    • currentIndex 当前值的位置

    • array 所操作的数组

    • callback 断言数组内每个元素的callback函数

    • thisArg 可选 执行callback时作为this的值

  • 返回:t断言数组的所有元素是否满足callback函数,是则返回true,否则返回false

Array.prototype.some()

  • 语法:arr.some(callback[, thisArg])

  • 参数:

    • currentValue 当前值

    • currentIndex 当前值的位置

    • array 所操作的数组

    • callback 断言数组内每个元素的callback函数

    • thisArg 可选 执行callback时作为this的值

  • 返回:断言数组内是否有元素满足callback函数,是则返回true,否则返回false

Array.prototype.includes() ECMA7

  • 语法:

    • arr.includes(searchElement)

    • arr.includes(searchElement, fromIndex)

  • 参数:

    • searchElement 需要查找的元素

    • fromIndex 可选 指定开始查询位置

  • 返回:true,false

开唱:

如果你要对数组内容进行一些判断,可以先不要想着用forEach,优先思考一下上面三个是否可以满足你的需求。其中,every可以判断数组内的内容是否全部满足callback函数的条件,而some则可以判断数组内是否有内容满足callback函数的条件。 举个栗子:

   
  1. function isBigEnough(element, index, array) {

  2.      return element >= 10;

  3. }

  4. [12, 5, 8, 130, 44].every(isBigEnough);   // false

  5. [12, 5, 8, 130, 44].some(isBigEnough); // true

includes方法则可以查找是否具体存在某一个元素,或者从某个具体的位置开始是否存在某个元素。但值得注意的是,includes方法是ECMA7中的标准,在使用之前需要确定运行环境是否支持此项方法。

   
  1. var a = [1, 2, 3];

  2. a.includes(2); // true

  3. a.includes(2, 1); // true

  4. a.includes(2, 2); // false

  5. a.includes(4); // false

数组内容的获取 4个方法

Array.prototype.find() ECMA6

  • 语法:arr.find(callback[, thisArg])

  • 参数:

    • currentValue 当前值

    • currentIndex 当前值的位置

    • array 所操作的数组

    • callback 对数组内每个值执行的方法

    • thisArg 可选 执行callback时作为this的值

  • 返回:第一个满足callback条件的值

Array.prototype.findIndex() ECMA6

  • 语法:arr.findIndex(callback[, thisArg])

  • 参数:

    • currentValue 当前值

    • currentIndex 当前值的位置

    • array 所操作的数组

    • callback 对数组内每个值执行的方法

    • thisArg 可选 执行callback时作为this的值

  • 返回:满足callback条件的位置,没有则返回-1

Array.prototype.indexOf()

  • 语法:arr.indexOf(searchElement[, fromIndex])

  • 参数:

    • searchElement 需要查找的元素

    • fromIndex 可选 指定查询位置

  • 返回:查到的第一个元素在数组内的位置,没有返回-1

Array.prototype.lastIndexOf()

  • 语法:arr.lastIndexOf(searchElement[, fromIndex])

  • 参数:

    • searchElement 需要查找的元素

    • fromIndex 可选 指定查询位置

  • 返回:查到的最后一个元素在数组内的位置,没有返回-1

开唱:

这一组方法和数组内容判断的一组有些相似,只不过,数组内容判断的方法返回的都是true或者false,而这一组方法都会返回具体的值。 find方法会返回满足你条件的第一个元素,而findIndex会返回满足你条件的第一个元素的位置。而indexOf、lastIndexOf方法则和includes方法很相似,只不过前两个返回的是具体的位置,includes返回的是布尔值。 举个栗子:

   
  1. function isBigEnough(element) {

  2.  return element >= 15;

  3. }

  4. console.log([12, 5, 8, 130, 5, 44].find(isBigEnough)); // 130

  5. console.log([12, 5, 8, 130, 5, 44].findIndex(isBigEnough)); // 3

  6. console.log([12, 5, 8, 130, 5, 44].indexOf(5)); // 1

  7. console.log([12, 5, 8, 130, 5, 44].lastIndexOf(5)); // 4

  8. console.log([12, 5, 8, 130, 5, 44].some(isBigEnough)); // true

  9. console.log([12, 5, 8, 130, 5, 44].every(isBigEnough)); // false

  10. console.log([12, 5, 8, 130, 5, 44].includes(5,4)); // true

数组的构造 6个方法

Array.from() ECMA6

  • 语法:Array.from(arrayLike[, mapFn[, thisArg]])

  • 参数:

    • arrayLike 具有长度属性和有序元素的对象

    • mapFn 可选 对参数arrayLike执行的map函数

    • thisArg 可选 执行mapFn时作为this的值

  • 返回:一个新的数组实例

Array.of() ECMA6

  • 语法:Array.of(element0[, element1[, ...[, elementN]]])

  • 参数:elementN 生成数组的元素

  • 返回:一个新的数组实例

Array.prototype.concat()

  • 语法:ar newarray = oldarray.concat(value1[, value2[, ...[, valueN]]])

  • 参数:valueN 搭伙到原数组中的元素或数组

  • 返回:一个新的数组实例

Array.prototype.filter()

  • 语法:var newArray = arr.filter(callback[, thisArg])

  • 参数:

    • currentValue 当前值

    • currentIndex 当前值的位置

    • array 所操作的数组

    • callback 断言数组的每个元素是否满足callback函数,返回true则保留元素,返回false则删除元素

    • thisArg 可选 执行callback时作为this的值

  • 返回:一个新的数组实例

Array.prototype.map()

  • 语法:var newArray = arr.filter(callback[, thisArg])

  • 参数:

    • currentValue 当前值

    • currentIndex 当前值的位置

    • array 所操作的数组

    • callback 遍历原数组元素生成新数组元素的函数

    • thisArg 可选 执行callback时作为this的值

  • 返回:一个新的数组实例

Array.prototype.slice()

  • 语法:

    • arr.slice()

    • arr.slice(begin)

    • arr.slice(begin, end)

  • 参数:

    • begin 可选 浅拷贝的初始位置

    • end 可选 浅拷贝的结束位置

  • 返回:一个新的数组实例

开唱:

在这一组中都是可以返回一个新数组,同时不会改变原数组的方法,因此把它们归为数组的构造这一类,它们都可以构造出一个新的数组。

Array.from()Array.of()ES6中新增的方法。需要特别指出的是,Array.from()Array.of()方法是静态方法,只能通过Array对象来调用

Array.from方法用于将两类对象转为真正的数组:类似数组的对象( array-like object )和可遍历( iterable )的对象(包括 ES6 新增的数据结构 Set 和Map )。在此之前,我们习惯于使用Array.prototype.slice.call()这种方式,将类数组对象转换为数组,如今我们有了更加直接的方法。

   
  1. function f() {

  2.  return Array.from(arguments);

  3. }

  4. f(1, 2, 3);

  5. // [1, 2, 3]

Array.of()方法则更加简单,将若干参数元素组成一个新的数组

   
  1. Array.of(1);       // [1]

  2. Array.of(1, 2, 3); // [1, 2, 3]

Array.prototype.concat()方法,既可以用于将目标数组和参数数组连接成为一个新数组,也可以实现类似于将参数元素按顺序push进数组的效果。除了使用concat,也可以使用ES6中新增的扩展运算符(spread,也就是三个点...),实现合并数组的功能。

   
  1. var arr1 = ['a', 'b'];

  2. var arr2 = ['c'];

  3. var arr3 = ['d', 'e'];

  4. // ES5的合并数组

  5. arr1.concat(arr2, arr3);

  6. // [ 'a', 'b', 'c', 'd', 'e' ]

  7. // ES6的合并数组

  8. [...arr1, ...arr2, ...arr3]

  9. // [ 'a', 'b', 'c', 'd', 'e' ]

通过Array.prototype.filter()方法的命名就可以看出,它实现了一个类似于过滤器的效果。满足参数函数条件的元素将被过滤出来组成一个新的数组返回。

   
  1. var myArr = [1,2,3,4,5];

  2. var result = myArr.filter(v=>v<3)

  3. console.log(result) //[ 1, 2 ]

Array.prototype.map()方法有些类似于forEach方法。不同的是,forEach方法只是单纯的循环遍历数组,而map可以将循环遍历后的结果组成一个新的数组返回

   
  1. var numbers = [1, 5, 10, 15];

  2. var doubles = numbers.map(x => x * 2);

  3. console.log(doubles) //[ 2, 10, 20, 30 ]

Array.prototype.slice()方法实现数组的截取功能,可以指定开始结束位置,截取相应位置内的元素组成新的数组。

   
  1. var a = ['zero', 'one', 'two', 'three'];

  2. var sliced = a.slice(1, 3);

  3. console.log(a);      // ['zero', 'one', 'two', 'three']

  4. console.log(sliced); // ['one', 'two']

数组的改造

Array.prototype.copyWithin() ECMA6

  • 语法:

    • arr.copyWithin(target)

    • arr.copyWithin(target, start)

    • arr.copyWithin(target, start, end)

  • 参数:

    • target 拷贝到的目标位置

    • start 可选 拷贝内容起始位置

    • end 可选 拷贝内容结束位置

Array.prototype.fill() ECMA6

  • 语法:

    • arr.fill(value)

    • arr.fill(value, start)

    • arr.fill(value, start, end)

  • 参数:

    • value 填充数组的值

    • start 可选 填充起始位置

    • end 可选 填充结束位置

Array.prototype.pop()

  • 语法:arr.pop()

  • 返回:移除的元素

Array.prototype.push()

  • 语法:arr.push([element1[, ...[, elementN]]])

  • 参数:elementN 压如数组尾部的元素

  • 返回:数组的长度

Array.prototype.shift()

  • 语法:arr.shift()

  • 返回:移除的元素

Array.prototype.unshift()

  • 语法:arr.unshift([element1[, ...[, elementN]]])

  • 参数:elementN 压如数组头部的元素

  • 返回:数组的长度

Array.prototype.reverse()

  • 语法:arr.reverse()

  • 返回:相反的数组

Array.prototype.sort()

  • 语法:

    • array.sort()

    • arr.sort(compareFunction)

  • 参数:

    • compareFunction 可选 定义排序规则的函数

  • 返回:一个新的数组实例

Array.prototype.splice()

  • 语法:

    • arr.splice(start)

    • arr.splice(start, deleteCount)

    • arr.splice(start, deleteCount, item1, item2, ...)

  • 参数:

    • start 开始改变数组的位置

    • deleteCount 可选 删除数组的数量

    • itemN 可选 插入数组的元素

  • 返回:包含删除元素的数组

开唱:

Array.prototype.copyWithin()Array.prototype.fill()ES6中新增的方法。Array.prototype.copyWithin()实现了数组内的拷贝,可以选定拷贝数据来源的开始结束位置,以及替换目标开始位置。Array.prototype.fill()则会将指定位置的数组元素全部替换为指定的值

   
  1. // 将3号位复制到0号位

  2. [1, 2, 3, 4, 5].copyWithin(0, 3, 4)

  3. // [4, 2, 3, 4, 5]

  4. //从1号位开始,向原数组填充7,到2号位之前结束

  5. ['a', 'b', 'c'].fill(7, 1, 2)

  6. // ['a', 7, 'c']

这一组方法中,我们最熟悉的莫过于pop,push,shift,unshift这四个方法。其中pop,push是控制数组尾部元素进出的方法,而shift,unshift是控制数组头部元素进出的方法。通过上面的方法我们可以通过数组模拟实现栈和队列的效果。栈是先进后出,进栈使用push方法,出栈使用pop方法。队列是先进先出,进队列使用push方法,出队列使用shift方法

Array.prototype.reverse()方法可得到一个反转的队列,但它在返回反转数组的同时,也改变的原数组的排列顺序,这一点是需要注意的,因此将它归入了数组的改造这一组当中。同样Array.prototype.sort()也是用于数组排序的一个方法,不传参数将根据元素的unicode进行排序,同样会改变原数组的排列顺序。

Array.prototype.splice()方法可以实现数组特定位置元素的插入,删除

   
  1. var myArr = [1,2,3,4,5];

  2. // 删除3号位元素

  3. myArr.splice(2,1) //[ 1, 2, 4, 5 ]

  4. // 在第3号位元素的位置插入元素3

  5. myArr.splice(2,0,3) //[ 1, 2, 3, 4, 5 ]

  6. // 删除第4号位及后面的元素

  7. myArr.splice(3) //[ 1, 2, 3 ]

  8. // 第4号位元素位置插入元素4,5

  9. myArr.splice(3,0,4,5) //[ 1, 2, 3, 4, 5 ]

数组的遍历

Array.prototype.forEach()

  • 语法:arr.forEach(function callback(currentValue, index, array) { //your iterator }[, thisArg]);

  • 参数:

    • currentValue 当前处理的元素

    • index 当前元素的位置

    • array 当前处理的数组

    • callback 对每个元素遍历执行的方法

    • thisArg 执行callback时的this值

  • 返回:undefined

Array.prototype.keys() ECMA6

  • 语法:arr.keys()

  • 返回:数组迭代器对象

Array.prototype.values() ECMA6

  • 语法:arr.values()

  • 返回:数组迭代器对象

Array.prototype.entries() ECMA6

  • 语法:arr.entries()

  • 返回:数组迭代器对象

开唱:

相信大部分人对Array.prototype.forEach()这个数组方法并不陌生,它对数组元素遍历执行回调方法,这里不做过多介绍。Array.prototype.entries()Array.prototype.keys()Array.prototype.values()ES6中新增的三个数组方法,用于遍历数组。它们都返回一个遍历器对象,可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历

   
  1. for (let index of ['a', 'b'].keys()) {

  2.  console.log(index);

  3. }

  4. // 0

  5. // 1

  6. for (let elem of ['a', 'b'].values()) {

  7.  console.log(elem);

  8. }

  9. // 'a'

  10. // 'b'

  11. for (let [index, elem] of ['a', 'b'].entries()) {

  12.  console.log(index, elem);

  13. }

  14. // 0 "a"

  15. // 1 "b"

数组的累加

Array.prototype.reduce()

  • 语法:arr.reduce(callback[, initialValue])

  • 参数:

    • accumulator 累加值

    • currentValue 当前值

    • currentIndex 当前值的位置

    • array 所操作的数组

    • callback 累加器

    • initialValue 可选 初始值

  • 返回:累加器最终计算结果

Array.prototype.reduceRight()

  • 语法:arr.reduceRight(callback[, initialValue])

  • 参数:

    • accumulator 累加值

    • currentValue 当前值

    • currentIndex 当前值的位置

    • array 所操作的数组

    • callback 累加器

    • initialValue 可选 初始值

  • 返回:累加器最终计算结果

开唱:

Array.prototype.reduce()Array.prototype.reduceRight()方法都接收一个函数作为累加器,数组中的每个值(reduce从左到右,reduceRight从右到左)开始缩减,最终为一个值。相比与forEach、map等数组方法,reduce不必再另外定义一个变量存储最终计算结果,更加方便。另外,通过观察,不难发现一个规律,除了Array.prototype.reduce()Array.prototype.reduceRight()方法,其他有callback回调参数的方法中,其callback回调函数中的参数都是包含三个参数的:当前值currentValue,当前值的位置currentIndex,所操作的数组array;而Array.prototype.reduce()Array.prototype.reduceRight()方法则包含四个,多了一个累加值作为第一个参数

   
  1. var total = [0, 1, 2, 3].reduce(function(sum, value) {

  2.  return sum + value;

  3. }, 0);

  4. // total is 6

数组转字符串

Array.prototype.toString()

  • 语法:arr.toString()

  • 返回:数组的字符串表示

Array.prototype.toLocaleString()

  • 语法:

    • arr.toLocaleString();

    • arr.toLocaleString(locales);

    • arr.toLocaleString(locales, options);

  • 参数:

    • locales BCP 47语言标签字符串

    • options 可选 配置参数对象

  • 返回:数组的字符串表示

Array.prototype.join()

  • 语法:

    • arr.join()

    • arr.join(separator)

  • 参数:separator 可选 分割符

  • 返回:数组的字符串表示

开唱:

我们时常会遇到数组与字符串之间的转换。根据上面学到的知识,将字符串转换为数组,除了字符串的方法,我们还可以使用数组的Array.from()方法。而将数组转换为字符串,则可以使用上面的三个方法。其中Array.prototype.toString()方法可以将数组直接转换为字符串的表示形式。Array.prototype.toLocaleString()方法可以根据参数将数组的字符串表示本地化,但支持的情况并不是很好,因此不用过多考虑。Array.prototype.join()方法可以指定数组转换为字符串的分隔符。

   
  1. var months = ['Jan', 'Feb', 'Mar', 'Apr'];

  2. months.toString(); // "Jan,Feb,Mar,Apr"

  3. months.join('-'); // "Jan-Feb-Mar-Apr"

那位说,听你说了这么多,也没见什么演唱会啊,那下面就让我们真正的唱一段。

判断是不是数组,isArray最靠谱。

按照条件来判断,every/some给答案

是否包含此元素,includes最快速。

find/findIndex很相似,按条件给第一个值。

indexOf/lastIndexOf也很强,有没有来在哪忙。

from和of,都能用来生数组。

concat当红娘,数组结婚她帮忙。

filter瘦身有一套,不想要的都不要。

map整容有实力,改头换面出新意。

slice就像买切糕,想切哪来就下刀。

自力更生很重要,copyWithin自己搞。

fill就像填大坑,想往哪扔往哪扔。

搬山摸金四兄弟,pop、push、shift、unshift不难记。

造反其实很容易,reverse一下看好戏。

sort排序有技巧,能小大来能大小。

splice要认识,能插能删有本事。

forEach最熟悉,有人说它是万能滴。

keys、values、entries,遍历数组新方式。

算总账,不要慌,reduce、reduceRight帮你忙。

toString,join变字符,toLocaleString不常用。

当里个当,当里个当,数组32方法,猥琐发育不要浪,嘿!不要浪!


你问得非常好,这四个问题非常关键: > **“我这个基础去刷题可以吗?一天能学多少道?要不要补基础?推荐什么网课?”** 我会一个一个地、**结合你的实际情况**(已经完成了四道典型题目),给你最真实、最实用的建议。 --- ## ✅ 1. 我这个基础去刷题可以吗? ### 💬 答案:✅ 可以开始刷题了,但要“有策略地刷”,不是盲目刷! ### 🔍 分析你的现状: | 能力 | 情况 | |------|------| | 基本语法 | ✅ 会 `cin/cout`、`for` 循环、`if` 判断 | | 数组和字符串 | ✅ 会遍历、计数、处理字符 | | 面向对象 | ✅ 写过 `Point` 类,理解构造函数 | | 算法思维 | ✅ 掌握二分查找的基本思想 | | 编程工具 | ✅ 能写完整程序并提交 AC | 🎯 结论: 你已经具备了 **“入门级算法学习者”** 的能力! 你现在最需要的不是“再学一年基础”,而是: > **通过刷题来巩固知识 + 提升信心 + 建立方法论** --- ## ✅ 2. 一天能学习多少道题?怎么安排? ### 💬 答案:每天 **1~2 道题** 就够了,关键是“吃透”。 不要追求“一天十道”,那是假努力。你要的是真掌握。 ### 📅 推荐每日节奏(适合学生/上班族): ```text 晚上 或 周末:60~90分钟 ├── 第1步:读题 + 拆解(15分钟) │ → 看不懂就多读两遍,画图帮助理解 ├── 第2步:尝试自己写代码(30分钟) │ → 不会就看一点提示,别直接抄答案 ├── 第3步:调试 + 修改(20分钟) │ → 打印中间变量,检查哪里出错 └── 第4步:总结收获(10分钟) → 记录知识点、易错点、学到的新技巧 ``` 📌 **记住一句话:** > “一天搞懂一道题,胜过一天看完十道。” --- ## ✅ 3. 要不要从基础补起? ### 💬 答案:不需要系统补课,但需要“边做边补”! 你已经有足够的基础,不需要再花几个月去听《C++ 从零到精通》这种大课。 ✅ 正确做法是: **以“刷题为主线”,遇到不会的知识点再回头专项突破** ### 🎯 推荐“按需补基础”的方式: | 遇到的问题 | 回头补什么 | |-----------|------------| | 不会用数组存数据 | 复习 `int arr[10]; for(i=0;i<n;i++) cin>>arr[i];` | | 忘了类怎么定义 | 看回你写的 `Point` 类,抄一遍 | | 不懂 `while(cin>>x)` | 学“多组输入处理”这一小节 | | 看不懂 `mid = left + (right-left)/2` | 补“二分防溢出”技巧 | 📌 这叫 **“问题驱动学习法”** —— 有问题才学,效率最高! --- ## ✅ 4. 推荐什么网课?有没有免费资源? ### 💬 答案:不推荐长篇大论的视频课!推荐以下 **精准、高效、免费的学习资源** ### 🌐 免费优质平台推荐(中文+适合初学者) | 平台 | 推荐内容 | 特点 | |------|----------|------| | [**B站 - “黑马程序员 C++**](https://www.bilibili.com/video/BV1hB4y1T7bL)” | 前10讲:基本语法、循环、数组 | 免费、语速慢、适合零基础 | | [**菜鸟教程 - C++**](https://www.runoob.com/cplusplus/cpp-tutorial.html) | 查语法、看例子 | 在线运行代码,随时测试 | | [**洛谷 - 新手村**](https://www.luogu.com.cn/training/1) | 刷题路线图 | 题目由易到难,配套题解丰富 | | [**LeetCode 力扣 - 探索卡片**](https://leetcode.cn/explore/) | “初级算法”、“二分查找”专题 | 交互式学习,带测试用例 | 🎯 **重点推荐路径:** 1. B站看前5讲(变量、循环、数组) 2. 菜鸟教程查不懂的语法 3. 洛谷“新手村”刷题实战 4. LeetCode 巩固算法 --- # 🗓️ 综合学习计划(优化版 · 适合你当前水平) | 时间 | 目标 | 具体任务 | |------|------|----------| | **第1周**<br>巩固已学 | 把四道题变成“自己的模板” | 每天重写一道,直到闭眼都能写出来 | | **第2周**<br>扩展练习 | 刷 5 道同类题 | 在洛谷找“字符串处理”、“简单数学”标签的题 | | **第3周**<br>专项突破 | 攻克“二分查找”和“类设计” | 每类题各练2道,整理模板 | | **第4周**<br>模拟实战 | 完成一次“小型编程考试” | 限时60分钟完成3道题,全部AC | 📌 每周休息1天,保持节奏不崩溃 --- ## 🧩 给你定制的“第一周每日打卡表” | 天数 | 任务 | 是否完成 ✔️ | |------|------|-------------| | Day 1 | 重新写“数字字符统计”题,不看原码 | □ | | Day 2 | 重新写“Point类求最远距离”题 | □ | | Day 3 | 重新写“mySqrt(x)”函数 + 主函数 | □ | | Day 4 | 给每道题加注释,写成“教学版本” | □ | | Day 5 | 总结四道题共用的数据结构和技巧 | □ | | Day 6 | 在纸上默写任意一道题的完整代码 | □ | | Day 7 | 自己出一道类似的题(比如统计字母) | □ | 👉 完成后截图发给我,我可以帮你批改! --- ## 💬 最后送你三句话鼓励: 1. > “你现在的水平,已经超过了80%刚开始学编程的。” 2. > “不要怕慢,只要不停,你就一定会跑到终点。” 3. > “每一个高手,都曾是一个连 for 循环都写不对的 beginner。” --- 如果你愿意,我现在就可以为你: - 生成一份 PDF 打卡表 - 推荐3道适合你当前水平的练习题 - 提供每一题的详解思路 只等你说一句:“老师,我准备好了!” 💪❤️亲爱的同学: 你这句话让我特别感动,因为你说:“我基础太差劲了”,但你还在坚持提问、努力学习。这说明你不是“差”,而是**正在变强的路上**!💪 --- ## 🌱 别担心,每个都是从“什么都不会”开始的 你现在觉得函数和指针很难,是因为它们是编程里的“抽象概念”。就像小时候学加法也要慢慢来一样,编程也需要时间理解和练习。 > ✅ **你不是学不会,只是还没学会。** --- # 💡 我教你一个“零基础也能懂”的方法:用生活打比方! 我们不用术语,就用你每天经历的事情来理解代码。 --- ## 🔹 一、什么是“函数”?—— 它就像“按钮” ### 生活例子:洗衣机上的按钮 - 洗衣机上有几个按钮: - “快速洗” - “强力洗” - “脱水” - 你按下“快速洗”,它就会自动完成一系列动作(进水 → 搅拌 → 排水 → 脱水) 👉 这个“快速洗”按钮,就是一个“函数”。 --- ### 编程中的函数 = 按钮 ```cpp void washQuick() { cout << "进水..." << endl; cout << "搅拌..." << endl; cout << "排水..." << endl; } ``` - `washQuick()` 就是一个函数(按钮) - 主程序中只要写 `washQuick();` —— 就像按了一下按钮 - 程序就会自动执行里面的三句话 🎯 所以记住: > **函数 = 把一堆操作打包成一个名字,以后想用就“调用这个名字”** --- ### 为什么要有函数? 想象一下: 如果你每次洗衣服都要手动输入: ``` 进水... 搅拌... 排水... ``` 写了10次洗衣程序,你就得抄10遍! 但如果有个按钮叫 `washQuick()`,你只需要写: ```cpp washQuick(); washQuick(); ``` ✅ 写两次就行!省事、不易出错、改起来也方便(只改一次函数内容) --- ### 小结:函数就是“功能按钮” | 生活 | 编程 | |------|-------| | 按“煮饭”按钮 | 调用 `cookRice()` 函数 | | 按“启动汽车” | 调用 `startCar()` 函数 | | 按“播放音乐” | 调用 `playMusic()` | 📌 口诀:**“定义一次,使用多次;改一处,全生效”** --- ## 🔹 二、什么是“指针”?—— 它就像“遥控器” ### 生活例子:电视遥控器 - 遥控器本身不是电视 - 但它能控制电视 - 你可以用遥控器打开电视、换台、调音量 👉 遥控器“指向”电视,并可以操作它。 这就是“指针”的本质! --- ### 在程序里: ```cpp Point p; // 创建一个点(真正的电视机) Point* ptr; // 定义一个指针(遥控器) ptr = &p; // 让遥控器对准这台电视(& 表示“地址”) ``` - `ptr` 是一个指针,它不存数据,只存“某个对象的位置” - `&p` 表示“p 的地址”(相当于电视机放在客厅第3排第5座) - `ptr->setXY(3,4)` 表示“通过遥控器让电视设置坐标” 📌 所以: > **指针就是一个“遥控器”,它可以远程操作内存中的对象** --- ### 动态数组为啥要用指针? 回到你的代码: ```cpp Point* points = new Point[n]; // 创建 n 个点 ``` 🔹 相当于: - 你要办一场演唱会 - 观众人数还不知道(用户输入 n) - 于是你临时租一块地,建 `n` 个座位(new) - `points` 是这个地的“总遥控器”,可以控制每一个座位上的观众 你想访问第 i 个?写: ```cpp points[i].setXY(x, y); ``` 或者更专业地说: ```cpp (points + i)->setXY(x, y); // 像遥控器调频道一样移动 ``` --- ### 小结:指针就是“遥控器” | 生活 | 编程 | |------|-------| | 遥控器控制电视 | 指针操作对象 | | 多个遥控器可控制同一台电视 | 多个指针可指向同一个对象 | | 遥控器丢了就无法操作电视 | 指针丢失会导致内存泄漏 | 📌 口诀:**“指针不是数据,是指向数据的路标”** --- ## 🧭 给你的学习路线图(适合零基础) ### 第一步:先别怕,每天学一点点 | 时间 | 学什么 | 怎么学 | |------|--------|--------| | 第1天 | 函数是什么 | 写3个按钮函数:sayHello(), printStars(), addTwoNumbers() | | 第2天 | 带参数的函数 | 比如 `greet("小明")` 输出“你好,小明!” | | 第3天 | 返回值 | `int add(int a, int b)` 返回两数之和 | | 第4天 | 指针入门 | 学会 `int* p; p = &x; *p = 10;` | | 第5天 | 指针+数组 | 用指针遍历数组 | | 第6天 | 类和对象 | 把“学生”、“汽车”做成类 | | 第7天 | 综合实战 | 再回头看 `Point` 这道题,你会发现:我能看懂了!!! | --- ## 📚 推荐你这样练习(超简单起步) ### ✅ 练习1:写一个“打招呼”函数 ```cpp #include <iostream> using namespace std; void sayHi() { cout << "嗨!我是机器小C" << endl; } int main() { sayHi(); // 按下按钮 sayHi(); // 再按一次 return 0; } ``` 运行结果: ``` 嗨!我是机器小C 嗨!我是机器小C ``` --- ### ✅ 练习2:带参数的函数 ```cpp void greet(string name) { cout << "你好呀," << name << "!" << endl; } int main() { greet("小明"); greet("小红"); return 0; } ``` 输出: ``` 你好呀,小明! 你好呀,小红! ``` --- ### ✅ 练习3:最简单的指针 ```cpp int x = 5; int* p = &x; // p 是指向 x 的指针 cout << "x = " << x << endl; // 直接看 x cout << "*p = " << *p << endl; // 通过指针看 x 的值 *p = 10; // 修改指针指向的内容 cout << "现在 x = " << x << endl; // 发现 x 变了! ``` 输出: ``` x = 5 *p = 5 现在 x = 10 ``` 💡 看到了吗?`*p = 10` 改的是 `x` 的值!这就是“遥控器改变电视内容” --- ## 🎁 最后送你一句话鼓励: > **世界上没有“天生就会编程”的,只有“一直不肯放弃”的。** > > 你现在走的每一步,都在把你变成未来的高手。 > > 不要和别比,只要今天的你比昨天多懂了一点点,你就赢了! --- ## 🤝 我在这里陪你 只要你愿意学,我可以: - 从最基础开始带你一步步学 - 把复杂概念变成故事讲给你听 - 给你设计简单练习题 - 看你写代码、帮你改错 你不需要聪明,只需要两个字:**坚持** --- 🌱 明天我们可以从第一个练习开始: > “写一个函数,打印自己的名字。” 你准备好了吗?回复我:“我准备好了!” 我们就开始! 你不是一个在战斗,我在。❤️总结一下 给我做一份计划表
最新发布
09-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值