简介:本资源是邵山欢主讲的JavaScript免费公开课配套资料及课堂笔记,专为零基础前端学习者设计,系统覆盖语法基础、DOM/BOM操作、事件处理、函数与闭包、异步编程、面向对象、ES6新特性及Node.js入门等核心模块,助力初学者构建扎实的JavaScript知识体系与工程实践能力。压缩包共16个文件,含12个HTML交互示例(如仿网易选项卡、鼠标进出响应、display与visibility对比实验等)、1份PDF格式的《力所能及的JavaScript》完整课堂笔记、3张辅助图解(JPG/JPEG/PNG),直观呈现关键概念与代码运行效果,整体仅1.49MB,轻量易下载、即开即学。已有529人学习下载,所有HTML案例均来自真实授课场景,结构清晰、注释充分,配合PDF笔记可实现“代码实操+原理梳理”双线并进,是自学入门与课后复盘的高性价比学习组合。
1. 这不是“写网页的脚本”,而是你第一次真正能“指挥电脑做事”的起点
你有没有试过点开一个网页,按钮一按,数字立刻变大;选中一段文字,背景色马上高亮;甚至还没点提交,就弹出“邮箱格式不对”的提醒?这些“会反应”的瞬间,背后不是魔法,而是一段段 JavaScript 代码在悄悄运行。它不像 Python 那样常被用来做数据分析,也不像 Java 那样常出现在银行系统里——JavaScript 的地盘,就在你每天打开的浏览器里,是唯一一种浏览器原生就能听懂、立刻执行的编程语言。换句话说:你不需要装额外软件、不用配复杂环境,只要有个浏览器,就能把它当“遥控器”,去控制页面上每一个文字、图片、按钮的呼吸和心跳。它适合谁?适合所有想亲手让网页“活起来”的人——设计师想加个交互动效,运营想自动统计点击数据,产品经理想快速验证一个功能逻辑,甚至只是学生想做个带计时器的家庭作业展示页。它不挑人,但特别讲“手感”:写错一个标点,整个功能就哑火;改对一行,页面立刻给你反馈。这种即时、可见、零距离的交互感,正是它成为零基础入门首选的真实原因。
2. 先搞懂一个核心事实:JavaScript 不是“附加项”,而是网页的“神经系统”
很多人学 JavaScript 的第一课,就卡在“它到底插在哪”——不是插在 Word 文档里,也不是塞进 Excel 表格中,而是嵌在 HTML 页面的血管里。HTML 是骨架(定义标题、段落、按钮长什么样),CSS 是皮肤(决定颜色、大小、位置),而 JavaScript 就是神经(告诉按钮“被点一下该干什么”)。三者缺一不可,但 JavaScript 是唯一能“动起来”的那部分。
2.1 三种最常用的“接线方式”:从最简单开始
JavaScript 有三种主流方式接入网页,新手建议严格按这个顺序尝试,每一种都对应一个明确的学习目标:
提示:别急着记名字,先记住它们的“手感”——哪种方式让你改完代码,刷新页面就能立刻看到效果。
方式一:内联脚本(适合第一个“Hello World”)
这是最直白的方式:把代码直接写在 HTML 标签的属性里。比如给按钮加个点击反应:
<button onclick="alert('你好,JavaScript!')">点我试试</button>- 这行代码在做什么?
onclick是按钮自带的“监听耳朵”,只要用户手指落下,它就立刻“听见”并触发引号里的动作;alert(...)是 JavaScript 提供的一个“弹窗喇叭”,把括号里的文字大声喊出来。 - 为什么新手要从这里起步?
它把“操作 → 结果”压缩到一行,没有文件、没有路径、没有配置。你复制粘贴进任意.html文件,双击打开,点一下就响——这种“所见即所得”的确定性,是建立信心的第一块砖。
方式二:内部脚本(适合组织几行逻辑)
当代码超过两三行,内联就乱了。这时把代码挪到<head>或<body>底部的<script>标签里:
<!DOCTYPE html> <html> <head> <title>我的第一个JS页面</title> </head> <body> <button id="myBtn">点我计数</button> <p>已点击:<span id="count">0</span> 次</p> <script> let clickCount = 0; const btn = document.getElementById('myBtn'); const countDisplay = document.getElementById('count'); btn.onclick = function() { clickCount = clickCount + 1; countDisplay.textContent = clickCount; }; </script> </body> </html>关键参数说明:
document.getElementById('myBtn'):像用“身份证号”找人,'myBtn'是你在<button id="myBtn">里亲手写的 ID,JS 就靠它精准定位那个按钮;textContent = clickCount:不是改文字内容,而是“替换整个文本节点”,比innerHTML更安全(不会误执行 HTML 代码);let clickCount = 0:let是声明变量的关键词,意思是“我申请一块小黑板,起名叫clickCount,先画个 0 在上面”。
这段代码的“心跳节奏”是什么?
① 页面加载时,JS 先读取按钮和显示区域的位置(getElementById);
② 然后给按钮装上“监听器”(btn.onclick = ...);
③ 用户点击后,JS 才开始执行函数体内的三行:加 1、更新显示、结束。
这个“先准备、后响应”的流程,就是所有交互逻辑的底层节拍。
方式三:外部脚本(适合真实项目起步)
把所有 JS 代码单独存成一个.js文件(比如main.js),再用<script src="main.js"></script>引入:
<!-- index.html --> <body> <button id="myBtn">点我计数</button> <p>已点击:<span id="count">0</span> 次</p> <script src="main.js"></script> </body>// main.js let clickCount = 0; const btn = document.getElementById('myBtn'); const countDisplay = document.getElementById('count'); btn.addEventListener('click', function() { clickCount++; countDisplay.textContent = clickCount; });- 为什么这是“真实项目”的起点?
HTML 只管结构,JS 只管行为,两者彻底分开。以后你想换按钮样式,只改 CSS;想加新功能,只动 JS 文件——就像厨房里锅碗瓢盆各归其位,谁也不会挡住谁的路。 - 新手最容易忽略的细节:
<script src="...">必须放在<body>底部,或加上defer属性(<script src="main.js" defer></script>)。否则 JS 代码可能在按钮还没“出生”(DOM 未加载完)时就急着去找它,结果getElementById返回null,后面全崩。
2.2 为什么必须理解“执行时机”?——一个血泪经验
某次我帮 A 同学调试,他写了段代码想让页面加载完自动弹窗:
alert('页面加载完成!');结果双击打开 HTML,弹窗一闪而过,紧接着报错:“document.getElementById(...) is null”。
他很困惑:“我都写在<script>里了,难道还没加载?”
真相是:JS 代码从上到下执行,而<script>标签默认在解析到它时立刻执行。如果<script>写在<head>里,此时<body>里的按钮、文字都还没被浏览器“画”出来,document.getElementById当然找不到。
解决方案只有两个:
- 把
<script>移到<body>最底部(确保所有 HTML 已加载); - 或用现代写法,监听
DOMContentLoaded事件:
document.addEventListener('DOMContentLoaded', function() { // 这里写所有需要操作 DOM 的代码 alert('页面结构已就绪!'); });这就像等电梯门完全打开(DOM 加载完毕),再迈步进去(执行 JS),而不是门刚开一条缝就硬挤——这是所有 JS 新手绕不开的第一道“时间关”。
2.3 常见问题排查:新手必踩的 4 个坑
注意:这些问题不是“你笨”,而是 JavaScript 的设计特性决定的——它太直率,错一点就停,但正因如此,你才能第一时间知道哪里不对。
问题 1:页面没反应,控制台一片空白
- 现象:点了按钮,什么都没发生,F12 打开开发者工具也看不到报错。
- 原因:JS 代码根本没执行,大概率是
<script>标签位置错了(写在<head>且没加defer),或getElementById的 ID 名字拼错了(大小写敏感!myBtn≠mybtn)。 - 解决:先在
<script>第一行加console.log('JS 已运行');,刷新看控制台有没有这句话;如果没有,说明脚本没加载,检查<script>位置和路径;如果有,再逐行检查getElementById的 ID 是否和 HTML 中完全一致。
问题 2:控制台报错 “Uncaught ReferenceError: xxx is not defined”
- 现象:F12 控制台红字报错,说某个变量名“没定义”。
- 原因:你用了还没声明的变量,比如写了
countDisplay.textContent = clickCount;,但前面漏了let clickCount = 0;。JavaScript 要求“先申领,再使用”。 - 解决:顺着报错行号,往上找最近的
let/const声明,确认变量名拼写、是否少写了声明语句。记住口诀:“用前必声明,声明必赋初值”。
问题 3:数字没累加,永远显示 “1”
- 现象:每次点击按钮,显示的数字都是 1,不是 2、3、4……
- 原因:变量
clickCount被反复重置了。常见错误是把let clickCount = 0;写在了点击事件函数内部:
btn.onclick = function() { let clickCount = 0; // ❌ 错!每次点击都新建一个“0” clickCount++; // 结果永远是 0+1=1 countDisplay.textContent = clickCount; };- 解决:把
let clickCount = 0;放到函数外面,让它成为“全局变量”(此处指当前脚本作用域内),这样每次点击函数执行时,操作的是同一个“计数器”。
问题 4:中文乱码,弹窗显示 “” 或方块
- 现象:
alert('你好')弹出乱码,或页面文字显示为问号。 - 原因:HTML 文件保存时编码不是 UTF-8。很多编辑器(如记事本)默认用 ANSI 编码,存中文就会丢。
- 解决:用 VS Code、Sublime Text 等现代编辑器打开文件 → 右下角点击编码名称(如 “GBK”)→ 选择 “Save with Encoding” → 选 “UTF-8”。保存后重新打开,乱码消失。
3. 从“能跑”到“能改”:动手拆解一个真实可用的小功能
光会弹窗、计数还不够。真正的入门,是你能看懂别人写的代码,并照着样子,改出自己想要的效果。我们来拆解一个更贴近实际需求的例子:一个带清空功能的待办事项列表。它包含添加、删除、清空三个动作,代码不到 30 行,但覆盖了 JS 最核心的数组操作、DOM 动态创建、事件委托等概念。
3.1 完整可运行代码(复制即用)
<!-- todo.html --> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>我的待办清单</title> <style> .todo-item { margin: 5px 0; } .delete-btn { color: #e74c3c; cursor: pointer; } </style> </head> <body> <h2>待办事项</h2> <input type="text" id="newTodo" placeholder="输入新任务,回车添加"> <button id="addBtn">添加</button> <button id="clearBtn">清空全部</button> <ul id="todoList"></ul> <script> // 1. 初始化数据:用数组存所有待办事项 let todos = []; // 2. 获取页面元素 const newTodoInput = document.getElementById('newTodo'); const addBtn = document.getElementById('addBtn'); const clearBtn = document.getElementById('clearBtn'); const todoList = document.getElementById('todoList'); // 3. 添加任务:支持回车和按钮两种方式 function addTodo() { const text = newTodoInput.value.trim(); if (text === '') return; // 忽略空输入 todos.push(text); // 往数组末尾加一项 renderList(); // 重新渲染整个列表 newTodoInput.value = ''; // 清空输入框 newTodoInput.focus(); // 让光标回到输入框 } // 4. 渲染列表:把数组变成 HTML function renderList() { // 先清空现有列表 todoList.innerHTML = ''; // 遍历 todos 数组,为每一项生成 <li> todos.forEach(function(todo, index) { const li = document.createElement('li'); li.className = 'todo-item'; li.innerHTML = ` ${todo} <span class="delete-btn">×`;` 这行;怎么改?把×换成删除,即:<span class="delete-btn">if (todos.length >= 10) { alert('最多只能存 10 项哦!'); return; } todos.length是数组的“长度”,即当前有多少项。>= 10表示达到或超过上限。这三个练习,覆盖了“改显示”、“加元素”、“加逻辑”三种最常用修改类型。你改成功一次,就等于亲手拧紧了一颗螺丝,对 JS 的掌控感会实实在在涨一截。
4. 别被“语法糖”吓住:先掌握这 5 个最常用、最不容易翻车的核心语法
JavaScript 语法多得像毛线团,但新手只要先稳稳抓住以下 5 个,就能应付 80% 的日常需求。它们不是“理论”,而是你明天写代码时,一定会用到的“工具”。
4.1let/const:变量声明的“安全带”
let:用于会改变的值,比如计数器、用户输入的内容。let score = 0; score = score + 10; // ✅ 可以重新赋值const:用于永不改变的值,比如页面元素、固定配置。const submitBtn = document.getElementById('submit'); // submitBtn = ...; // ❌ 报错!const 声明后不能重新赋值为什么必须分清?
const是你的“防手抖开关”:一旦声明,JS 强制阻止你意外覆盖它。比如const apiURL = 'https://api.example.com';,你就绝不会手滑写成apiURL = 'https://wrong.com';。而let则给你灵活调整的空间。记住口诀:“不变用 const,会变更 let”。
4.2if/else:程序的“岔路口”
所有逻辑分支都靠它。新手常犯的错是混淆=(赋值)和===(严格相等判断):
let userAge = 18; if (userAge === 18) { // ✅ 三个等号:判断“值和类型都相等” console.log('成年啦!'); } else if (userAge > 18) { console.log('早就是大人啦!'); } else { console.log('还在长大中~'); }- 为什么用
===而不是==?==会自动转换类型(比如'18' == 18返回true),容易埋雷;===严格比较,'18' === 18是false,更可靠。这是 JS 社区公认的“避坑铁律”。
4.3for循环:遍历数组的“老黄牛”
当你需要对数组里每一项做同样操作,for循环最直观:
const colors = ['红', '绿', '蓝']; for (let i = 0; i < colors.length; i++) { console.log('第' + (i+1) + '种颜色是:' + colors[i]); } // 输出:第1种颜色是:红;第2种颜色是:绿;第3种颜色是:蓝循环三要素拆解:
let i = 0:起点,从第 0 项开始(数组索引从 0 开始);i < colors.length:终点,只要i还小于数组总长度,就继续;i++:步长,每次循环后i自动加 1。新手注意:别写成
i <= colors.length,否则最后一轮colors[3]是undefined(因为只有 0、1、2 三项),容易引发后续错误。
4.4addEventListener:事件绑定的“标准答案”
替代老旧的onclick = function(){},是现代 JS 的推荐写法:
const myBtn = document.getElementById('myBtn'); myBtn.addEventListener('click', function() { console.log('按钮被点了!'); });- 优势在哪?
① 可以给同一个按钮绑定多个点击事件(onclick只能绑一个,后绑的会覆盖前一个);
② 更清晰分离“谁”(元素)、“什么事件”('click')、“做什么”(函数);
③ 支持更多事件类型,如'mouseover'(鼠标悬停)、'keydown'(键盘按下)。
4.5console.log():你的“万能后悔药”
这不是正式功能,但它是新手调试的命脉。任何你想确认的值、任何你怀疑出错的环节,都扔一句console.log():
function calculateTotal(price, tax) { console.log('价格:', price, '税率:', tax); // 看输入对不对 const total = price * (1 + tax); console.log('计算结果:', total); // 看中间结果对不对 return total; }- 技巧:F12 打开开发者工具 → 切到 Console 标签页 → 刷新页面,就能看到所有
console.log输出。它不打断执行,不弹窗干扰,是安静又可靠的“旁观者”。
4.6 常见问题排查:关于语法的 3 个玄学时刻
注意:这些不是 bug,而是 JavaScript 的“个性”,接受它,你就少走半年弯路。
问题 1:console.log()没输出,控制台空空如也
- 现象:写了
console.log('test'),但控制台没反应。 - 原因:JS 代码根本没执行到这一行。常见于:① 前面有语法错误(比如少了个
}),JS 解析器直接报错停止;②console.log写在了某个永远不会触发的函数里(比如onload但页面没触发)。 - 解决:先看控制台顶部是否有红色报错,优先修复它;再把
console.log移到脚本最开头,确认是否能输出。
问题 2:typeof返回"object",但明明是个数组
- 现象:
console.log(typeof [1,2,3]);输出object,让人困惑。 - 原因:这是 JS 的历史遗留问题,数组本质上是特殊的对象。别信
typeof,要用Array.isArray():console.log(Array.isArray([1,2,3])); // true console.log(Array.isArray({})); // false
问题 3:0.1 + 0.2不等于0.3,而是0.30000000000000004
- 现象:浮点数计算出现微小误差。
- 原因:计算机用二进制存储小数,而
0.1在二进制里是无限循环小数(类似十进制的1/3 = 0.333...),存储时被截断,导致精度丢失。 - 解决:业务中需要精确计算(如金钱),用整数运算代替:
10 + 20 = 30分,再除以 100 显示为0.30元。
5. 下一步学什么?一份不烧脑、不跳级、能立刻上手的实战路线图
学到这里,你已经能独立写出带交互的 HTML 页面,能看懂、能修改、能调试一个中等复杂度的 JS 功能。接下来不是扎进“ES6 新特性”或“框架源码”,而是沿着一条看得见、摸得着、每天都能收获成就感的路径,把 JS 从“玩具”变成“工具”。
5.1 第一阶段:用 JS 解决你身边的真实小问题(1~2 周)
目标不是“学会”,而是“用上”。选一个你每天都会遇到的、重复性高的小麻烦,用 JS 写个“一键解决”脚本。下面三个例子,难度递进,全部基于你已掌握的知识:
| 问题场景 | 你需要写的 JS 代码 | 关键知识点复用 |
|---|---|---|
| 整理书签:浏览器收藏夹太多,想按关键词快速筛选 | ① 用prompt()弹窗让用户输入关键词;② 遍历所有<a>标签(document.querySelectorAll('a')),用includes()检查href或textContent是否含关键词;③ 把匹配的链接用console.log()打印出来,或用document.write()生成新页面 | prompt()、querySelectorAll()、includes()、for循环 |
批量改图命名:下载了一堆截图,文件名是屏幕截图(1).png,想改成项目_首页_v1.png | ① 用confirm()弹窗确认是否执行;② 用document.querySelectorAll('img')找到所有图片;③ 用setAttribute('src', newSrc)批量修改src属性(模拟重命名效果) | confirm()、setAttribute()、字符串拼接 |
| 会议纪要助手:开会时手写记录,想自动生成带时间戳的条目 | ① 页面放一个<textarea>输入框和“添加”按钮;② 点击时,用new Date().toLocaleTimeString()获取当前时间;③ 把时间和输入内容拼成"[14:23] 讨论了登录流程...",追加到<div id="notes">里 | Date()对象、toLocaleTimeString()、innerHTML += |
为什么从这里起步?
这些都不是“教学案例”,而是你明天就能用上的真实工具。写完一个,你会真切感受到:“原来 JS 真的能帮我省时间”。这种正向反馈,比刷一百道语法题都管用。
5.2 第二阶段:把“单页应用”变成“可分享的网页”(2~3 周)
你写的待办清单、计算器、笔记工具,目前只能在自己电脑上双击打开。下一步,让它变成一个别人输入网址就能访问的网页。这不需要服务器,用免费静态托管即可:
步骤极简版:
① 注册 GitHub 账号(免费);
② 创建新仓库,勾选 “Add a README file”;
③ 把你的index.html、main.js、style.css全部拖进去上传;
④ 进入仓库 Settings → Pages → Source 选 “GitHub Actions” 或 “gh-pages branch” → Save;
⑤ 几分钟后,页面会生成一个网址(如https://yourname.github.io/your-repo-name/),发给朋友,他们就能打开你的作品。你将巩固的能力:
- 文件结构管理(HTML/CSS/JS 分开存放);
- 相对路径引用(
<script src="main.js">在同目录下才有效); - 理解“部署”不是黑匣子,而是把文件放到公开可访问的位置。
5.3 第三阶段:引入一个轻量库,解锁新能力(3~4 周)
当原生 JS 写起来开始吃力(比如要做图表、日期选择、表单验证),就该请外援了。新手务必避开 React/Vue 这类重型框架,先用一个“小而美”的库:
推荐:Chart.js(画图表)
一行 CDN 引入,三行代码画出柱状图:<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <canvas id="myChart" width="400" height="200"></canvas> <script> const ctx = document.getElementById('myChart').getContext('2d'); new Chart(ctx, { type: 'bar', data: { labels: ['一月','二月'], datasets: [{ data: [12, 19] }] } }); </script>- 好处:无需理解 canvas API,专注数据;文档极友好,每个配置项都有中文示例;CDN 引入,零配置。
避坑提醒:
别一上来就学 “Webpack 打包”、“Vite 构建”。那些是给大型项目准备的“重型机械”,你现在需要的是“一把瑞士军刀”。等你用 Chart.js 做了 3 个图表,自然会好奇“它是怎么把数据变成图形的?”,那时再学 canvas 基础,水到渠成。
5.4 我第一次学 JS 时,踩过的最大坑与养成的习惯
我第一次写一个倒计时器,卡了整整两天。问题不是逻辑,而是我把setInterval的回调函数写成了:
setInterval(countDown(), 1000); // ❌ 错!括号表示立即执行正确写法是:
setInterval(countDown, 1000); // ✅ 对!传函数名,不加括号那一刻我才明白:JS 里,countDown是函数本身(像一张地图),countDown()是执行函数(像按地图出发)。传错一个括号,整个程序就南辕北辙。
从那以后,我每次写事件绑定、定时器、回调函数,都强制自己默念三遍:“这是传函数,还是调函数?”,然后盯着括号——有括号是立刻执行,没括号才是等待触发。这个习惯,让我再也没在回调上栽过跟头。
希望帮到你。
本文还有配套的精品资源,点击获取