JavaScript 零基础深入浅出教程:从只会 IF → 高级程序员思维
JavaScript 零基础深入浅出教程:从只会 IF → 高级程序员思维
🎯 学习目标:
不是单纯背语法,建立编程思维。看懂:不同水平的人,同一个需求写出完全不一样的代码;学会权衡【可读性、简洁、性能】,理解底层执行过程。
📌 核心案例贯穿全程:求数组里面所有正数的总和
输入数组:[1, -3, 5, -2, 8, 0],预期结果:14
规则:只把大于0的数字相加,负数、0忽略。
✨ 开篇一句话(给学员)
编程的本质:指挥计算机处理数据。初级程序员只会让计算机重复干活;高级程序员懂得控制循环次数、减少内存浪费,同时代码容易看懂。
第1章:最基础概念(零基础入门)
1.1 变量:存放数据的盒子
// 声明变量,let 代表可变的数据
let num = 10;
let arr = [1, -3, 5, -2, 8, 0]; // 数组:一组数据的集合
let sum = 0; // sum用来保存累加的结果,初始是0
console.log(sum); // 在控制台打印输出
1.2 if 判断:做选择
计算机可以判断条件是否成立,成立就执行代码。
let a = 5;
if(a > 0){
console.log("a是正数");
}
1.3 数组下标
数组里每一项都有编号(下标,从0开始)
const arr = [1, -3, 5, -2, 8, 0];
console.log(arr[0]); // 1
console.log(arr[1]); // -3
console.log(arr[2]); //5
第2阶段:只会 if 语句(纯新手,不会循环)
思维局限:只能处理固定长度数组,数组元素增减,代码就要增删if。
// 版本1:只会if,硬编码写法
const arr = [1, -3, 5, -2, 8, 0];
let sum = 0;
if(arr[0] > 0){
sum += arr[0]; // sum = sum + arr[0]
}
if(arr[1] > 0){
sum += arr[1];
}
if(arr[2] > 0){
sum += arr[2];
}
if(arr[3] > 0){
sum += arr[3];
}
if(arr[4] > 0){
sum += arr[4];
}
if(arr[5] > 0){
sum += arr[5];
}
console.log(sum); //14
✅ 优点:逻辑直白,只学if就能看懂
❌ 巨大缺点:数组一旦增加元素,就要新增if。数组有1000个元素,要写1000个if!
🧠 思维:只能处理写死的固定场景,没有通用解决问题的能力。
第3阶段:学会 for 循环(入门,学会重复执行)
循环:让计算机自动重复执行一段代码,不用手写一堆if。
i 就是下标,自动从 0,1,2……一直增加到数组末尾。
// 版本2:for循环写法
const arr = [1, -3, 5, -2, 8, 0];
let sum = 0;
// i从0开始;i < arr.length(数组长度);每次循环 i++
for(let i = 0; i < arr.length; i++){
const item = arr[i]; // 取出当前数组元素
if(item > 0){
sum += item;
}
}
console.log(sum); //14
✅ 优点:任意长度数组都能用,不用改if。只遍历数组1次,不创建新数组,内存开销很小。
❌ 缺点:代码和数据写死在一起。如果想计算另外一个数组正数和,必须复制整段代码。
🧠 思维升级:学会批量处理一组数据,指挥计算机重复劳动。
这种写法叫命令式编程:告诉计算机每一步怎么做。
拓展:for...of 简化循环(不用管下标i)
const arr = [1, -3, 5, -2, 8, 0];
let sum = 0;
for(const item of arr){
if(item > 0){
sum += item;
}
}
console.log(sum);
第4阶段:学会函数封装(中级:学会代码复用)
函数:把一段完成特定功能的代码打包成工具。输入数据,返回结果。
一处定义,到处调用。还可以增加校验,防止错误输入。
// 版本3:函数封装 + for循环
/**
* 计算数组正数之和
* @param {Array} list 传入的数组
* @returns {number} 正数总和
*/
function getPositiveSum(list){
// 防御校验:如果传入不是数组,直接返回0,避免报错
if(!Array.isArray(list)) return 0;
let sum = 0;
for(let i = 0; i < list.length; i++){
const item = list[i];
if(typeof item === "number" && item > 0){
sum += item;
}
}
return sum;
}
// 调用函数,可以传入不同数组
const arr1 = [1, -3, 5, -2, 8, 0];
const arr2 = [2, -1, 10];
console.log(getPositiveSum(arr1)); //14
console.log(getPositiveSum(arr2)); //12
✅ 优点:代码复用、方便维护,支持多组数据。底层依旧1次遍历,无临时数组。
🧠 思维升级:抽象能力。把“计算正数总和”做成一个工具。
第5阶段:学会数组高阶API filter / reduce(JS进阶:声明式编程)
命令式:告诉计算机怎么做。
声明式:告诉计算机,我想要什么结果。
filter:筛选数组,返回满足条件的新数组
reduce:把数组“压缩”成一个值(总和、对象等)
版本4 filter + reduce(简洁好读)
// 版本4 filter + reduce
function getPositiveSum(list){
if(!Array.isArray(list)) return 0;
return list
.filter(item => typeof item === "number" && item > 0) // 筛选正数,生成新数组
.reduce((total, item) => total + item, 0); // 累加新数组
}
const arr = [1, -3, 5, -2, 8, 0];
console.log(getPositiveSum(arr)); //14
✅ 优点:代码可读性极高,一眼看懂逻辑:筛选正数,然后求和。
❌ 底层代价(重点!中级学员容易忽略)
- 两次遍历:原数组遍历一次生成新数组;新数组再遍历一次求和
- filter会创建中间临时数组,占用内存;大数据会增加垃圾回收压力。
适用场景:数组不大(几十几百条数据),可读性优先。
第6阶段:高级程序员写法:兼顾简洁 + 性能(重点章节)
核心思想:减少遍历次数、减少临时内存开销,同时保持代码简洁可读。
✅ 只用 reduce,只遍历数组1次,不生成中间数组。在一轮遍历里面同时完成判断+累加。
/**
* 【推荐:高级平衡写法】reduce单遍遍历
* 一次遍历,无中间数组;兼顾简洁性与性能
* @param {Array} list
* @returns {number}
*/
function getPositiveSum(list) {
if (!Array.isArray(list)) return 0;
return list.reduce((sum, item) => {
if (typeof item === 'number' && item > 0) {
sum += item;
}
return sum;
}, 0); // sum初始值=0
}
const arr = [1, -3, 5, -2, 8, 0];
console.log(getPositiveSum(arr)); //14
✅ 底层分析
- 遍历次数:仅1次
- 内存:没有创建额外临时数组
✅ 优点:
- 声明式风格,代码干净,不用手动管理下标i
- 性能接近原生for循环,没有额外内存开销
🧠 高级思维:
不要无脑链式调用 filter+map。链式好看,但背后藏着额外遍历、临时数组。
写代码前自问3个问题:
- 需要遍历数组多少次?
- 是否产生额外临时数组,增加内存压力?
- 是否需要中途停止循环?
⚠️ 重要底层知识点(面试必问)
filter map reduce 不能中途break停止遍历! 必须遍历完整个数组。
如果需要找到目标就提前终止循环(例如:总和大于10就停止),只能用 for / for...of:
// for循环可以break提前退出
function getPositiveSumBreak(list) {
if (!Array.isArray(list)) return 0;
let sum = 0;
for (const item of list) {
if (typeof item === 'number' && item > 0) {
sum += item;
}
if (sum >= 10) {
break; // 满足条件,直接跳出循环,不再继续遍历
}
}
return sum;
}
console.log(getPositiveSumBreak([1, -3, 5, -2, 8, 0]));
第7章:性能实测(现场演示代码,浏览器控制台直接运行)
console.time 用来计时,对比不同写法耗时,直观感受性能差异。
// 性能测试代码
// 构造超大数组,10万元素
const bigArr = [];
for(let i = 0; i < 100000; i++){
bigArr.push(Math.random() * 100 - 50); // -50 ~ 50随机数字
}
// 测试 for循环
console.time("for循环");
function sumFor(list){
let sum =0;
for(let i=0;i<list.length;i++){
if(list[i]>0) sum+=list[i];
}
return sum;
}
sumFor(bigArr);
console.timeEnd("for循环");
// 测试 reduce单遍
console.time("reduce单遍历");
function sumReduce(list){
return list.reduce((s,item)=>{
if(item>0)s+=item;return s;
},0);
}
sumReduce(bigArr);
console.timeEnd("reduce单遍历");
// 测试 filter + reduce
console.time("filter+reduce");
function sumFilterReduce(list){
return list.filter(x=>x>0).reduce((s,i)=>s+i,0);
}
sumFilterReduce(bigArr);
console.timeEnd("filter+reduce");
运行现象:大数据下 filter+reduce 耗时更高,因为两次遍历+创建临时数组。
💡 结论:小数据看不出差别;大数据,开销才会显现。不要过早优化!优先可读性,只在性能瓶颈处优化。
全版本对比总表(上课总结)
| 版本 | 知识点 | 遍历次数 | 临时数组 | 思维层次 | 适用场景 |
|---|---|---|---|---|---|
| 1 | if硬编码 | 0(手动写死) | 无 | 新手 | 固定少量数据,无法通用 |
| 2 | for循环 | 1次 | 无 | 入门 | 大数据,需要break提前退出 |
| 3 | 函数封装+for | 1次 | 无 | 中级 | 代码复用,业务基础开发 |
| 4 | filter+reduce | 2次 | 有 | 进阶 | 小数据,追求可读性 |
| 5 | reduce单遍历 | 1次 | 无 | 高级 | 绝大多数业务,可读性+性能平衡点 |
📖 核心学习总结(给学员背诵)
- 初级:只会写if硬编码;只能处理固定数据。
- 入门:学会循环,让计算机重复干活。
- 中级:学会函数封装,代码复用。
- 进阶:掌握数组高阶API,写出简洁声明式代码,但忽略底层开销。
- 高级:写出代码时,心里清楚遍历次数、内存开销。懂得权衡可读性和性能。
💡 终极口诀
小数据,可读性优先;大数据,减少遍历与临时变量;需要提前终止,就用for循环。
✍️ 课后练习
需求:给定数组,计算数组所有偶数总和
- for循环版本
- filter + reduce版本,并分析遍历次数和临时数组
- reduce单遍历版本
如果你需要,我可以:
- 精简成一页讲义;
- 或者配套课后答案解析。
要不要我把课后练习题加上完整参考答案?

浙公网安备 33010602011771号