JS 教程入门必看:从零到精通的基础之路
欢迎来到充满活力的前端世界!如果你对构建交互式的网页感兴趣,或者想踏入软件开发的大门,那么 JavaScript (JS) 将是你旅程中不可或缺的一步。它不仅是网页开发的基石之一,更是目前应用最广泛、生态最活跃的编程语言之一。
本篇文章将作为你的 JavaScript 入门指南,从最基础的概念讲起,逐步深入核心知识,帮助你建立坚实的JS基础。请记住,编程是一场马拉松,而非短跑。耐心、实践和持续学习是成功的关键。
废话不多说,让我们开始这段精彩的编程之旅吧!
第一章:初识 JavaScript – 它是什么?为什么学?
1.1 JavaScript 的定义与定位
简单来说,JavaScript 是一种轻量级、解释型、动态类型的编程语言。最初设计用于在网页浏览器中运行,使得网页具备交互性,不再是静态的信息展示。随着技术的发展,JavaScript 的应用范围早已超出了浏览器,扩展到了服务器端(Node.js)、移动应用开发(React Native, Ionic)、桌面应用开发(Electron)、甚至物联网等领域。
- 解释型:JS 代码不需要预先编译成机器码,而是由解释器逐行执行。这使得开发和调试更加便捷。
- 动态类型:变量的类型在运行时才能确定,同一个变量可以存储不同类型的数据。这提供了灵活性,但也可能带来一些潜在的问题(比如类型错误),需要开发者多加注意。
- 轻量级:相对于一些大型的企业级语言(如 Java, C++),JS 的语法相对简洁易学,非常适合作为入门语言。
1.2 JavaScript 的发展与标准 (ECMAScript)
JavaScript 最初由 Brendan Eich 在网景公司(Netscape)于 1995 年的 10 天内设计完成,最初命名为 Mocha,后改为 LiveScript,最终更名为 JavaScript。这个名字的改变与当时流行的 Java 语言有关,网景希望借助 Java 的声势推广自家的语言。
为了标准化这门语言,ECMA 国际(一个标准组织)制定了 ECMAScript(简称 ES)规范。JavaScript 是 ECMAScript 规范的一种实现。我们常听到的 ES5、ES6 (ES2015)、ES7 (ES2016) 等,指的就是不同版本的 ECMAScript 规范。学习 JS,实际上就是学习 ECMAScript 规范的核心语法,以及浏览器或 Node.js 等宿主环境提供的特定 API(例如浏览器中的 DOM API 用于操作网页元素)。
现代 JavaScript 开发通常遵循最新的 ECMAScript 标准(目前主流是 ES6 及以后版本),这些版本引入了许多重要的语法糖和新特性,极大地提高了开发效率和代码可读性。作为入门者,我们将从最基础的 ES5 语法开始,逐步接触 ES6 的常用特性。
1.3 JavaScript 在 Web 开发中的地位
在前端领域,HTML、CSS 和 JavaScript 是构建现代网页的三大核心技术:
- HTML (HyperText Markup Language):负责页面的结构和内容(骨架)。
- CSS (Cascading Style Sheets):负责页面的样式和布局(皮囊)。
- JavaScript:负责页面的行为和交互(灵魂)。
JS 可以修改 HTML 内容、改变 CSS 样式、响应用户的操作(如点击按钮、提交表单)、从服务器获取数据并更新页面等等。正是有了 JavaScript,网页才变得生动、智能和富有吸引力。
1.4 为什么选择学习 JavaScript?
- 应用广泛:无论前端还是后端,JS 都有广泛的应用,技能迁移性强。
- 易于入门:语法相对灵活,学习资源丰富,社区活跃,遇到问题容易找到解决方案。
- 前景光明:JS 生态持续繁荣,各种框架和库层出不穷(React, Vue, Angular, Node.js 等),提供了丰富的职业发展方向。
- 全栈潜力:掌握 JS,你可以在前端和后端都进行开发,成为一名“全栈工程师”。
总而言之,学习 JavaScript 是进入现代软件开发领域的一张“门票”,无论你的最终目标是什么,掌握它都将为你打开无数扇门。
第二章:踏出第一步 – 准备你的学习环境
学习编程,首先需要一个可以编写、运行和调试代码的环境。幸运的是,学习 JavaScript 非常简单,你可能已经拥有了所需的大部分工具。
2.1 所需工具
- 现代网页浏览器:如 Chrome, Firefox, Edge, Safari。这些浏览器内置了 JavaScript 引擎(如 V8, SpiderMonkey)来执行 JS 代码,并提供了强大的开发者工具。
- 文本编辑器或集成开发环境 (IDE):用于编写代码。
2.2 使用浏览器控制台 (Console)
这是学习 JS 最快捷的方式。大多数现代浏览器都提供了开发者工具,你可以直接在其中输入并运行 JavaScript 代码。
如何打开控制台:
- 在网页上右键,选择“检查”(Inspect)或“审查元素”。
- 在打开的开发者工具窗口中,切换到“Console”(控制台)选项卡。
在控制台中尝试:
输入以下代码并按回车键:
javascript
console.log("你好,JavaScript!"); // 在控制台输出信息
alert("这是一个弹窗!"); // 弹出提示框
console.log()
是一个非常常用的函数,用于在控制台输出信息,这对于调试代码非常有帮助。alert()
用于在浏览器中弹出一个简单的警告框。
控制台是一个很好的实验场,你可以随时输入一小段代码来测试某个语法或概念。
2.3 选择一个好的代码编辑器
虽然记事本也能写代码,但专业的代码编辑器能提供语法高亮、自动补全、错误检查等功能,极大地提升开发效率和体验。
推荐的编辑器(免费且流行):
- VS Code (Visual Studio Code):微软出品,功能强大,轻量级,插件生态丰富,强烈推荐新手使用。
- Sublime Text:轻量级,启动快,界面简洁。
- Atom:GitHub 出品,可高度定制。
- Notepad++ (仅限 Windows):简单易用。
选择一个你用着顺手的即可。VS Code 是目前最主流的选择,安装简单,提供中文界面,并且有很多针对前端开发的实用插件。
2.4 创建第一个 HTML 文件并链接 JS
JavaScript 通常与 HTML 和 CSS 结合使用。你可以在 HTML 文件中直接编写 JS 代码,或者链接一个外部的 JS 文件。推荐使用外部文件,这样可以保持代码的组织性和可维护性。
- 创建一个文件夹:例如命名为
my-js-project
。 - 在该文件夹中创建两个文件:
index.html
script.js
-
编辑
index.html
:“`html
<!DOCTYPE html>
我的第一个JS页面
<h1>你好,世界!</h1> <p>这是我的第一个包含 JavaScript 的页面。</p> <!-- 建议将 <script> 标签放在 <body> 结束标签之前 --> <!-- 这样可以确保 HTML 内容加载完成后再执行 JS --> <script src="script.js"></script>
“` -
编辑
script.js
:“`javascript
// 这是一个单行注释,用于解释代码
console.log(“script.js 文件已成功加载并执行!”);// 你可以在这里写更多的 JS 代码
// 例如,改变页面标题
document.title = “页面标题被JS改变了!”;// 例如,弹出一个友好的问候
alert(“欢迎来到我的页面!”);
“` -
运行
index.html
:用浏览器直接打开index.html
文件。你应该会看到页面内容,一个弹窗,并且在浏览器的控制台中看到输出信息。
通过这个简单的例子,你就成功地在网页中运行了你的第一段 JavaScript 代码!
第三章:JS 基础:构建代码的积木
掌握任何编程语言,都需要先理解其最基本的构成要素。本章将介绍 JavaScript 的核心语法概念。
3.1 注释 (Comments)
注释是写在代码中用于解释代码用途、功能或思路的文本,它不会被 JavaScript 解释器执行。养成写注释的好习惯对于自己回顾代码或与他人协作都非常重要。
-
单行注释:以
//
开始,直到行末。javascript
// 这是一行注释
let name = "张三"; // 这也是注释 -
多行注释:以
/*
开始,以*/
结束。javascript
/*
这是多行注释
可以跨越多行来描述一个复杂的逻辑块
*/
let age = 30;
3.2 变量 (Variables)
变量就像一个容器,用于存储数据。在使用变量之前,你需要先声明(定义)它。在现代 JavaScript 中,我们主要使用 let
和 const
来声明变量。
-
let
:声明一个块级作用域的变量。可以重新赋值。“`javascript
let message = “Hello”;
message = “World”; // 可以修改
console.log(message); // 输出 “World”// 在同一个作用域内不能重复声明
// let message = “Again”; // 会报错
“` -
const
:声明一个块级作用域的常量。一旦赋值后,不能再重新赋值。常用于声明不会改变的值。“`javascript
const PI = 3.14159;
// PI = 3.14; // 尝试修改常量,会报错const user = { name: “李四” };
user.name = “王五”; // 注意:const 保证变量指向的内存地址不变,但如果变量指向的是对象或数组,可以修改其内部属性/元素。
console.log(user.name); // 输出 “王五”// const user = { age: 25 }; // 尝试重新赋值整个对象,会报错
“` -
var
:声明一个函数作用域的变量。var
是 ES6 之前唯一的声明方式,存在一些问题(如变量提升和作用域混乱),在现代 JS 开发中,推荐优先使用let
和const
。javascript
var oldVar = "这是老方法";
// var 存在变量提升(hoisting)等特性,初学者了解即可,重点掌握 let 和 const。
变量命名规则:
- 名称可以包含字母、数字、$、_。
- 名称不能以数字开头。
- 名称不能是 JS 的保留字(如
if
,for
,function
等)。 - 区分大小写 (
myVar
和myvar
是不同的变量)。 - 推荐使用驼峰命名法 (camelCase):第一个单词小写,后面每个单词的首字母大写,例如
firstName
,getUserData
。
3.3 数据类型 (Data Types)
JavaScript 中的数据可以分为两大类:原始类型 (Primitive types) 和 对象类型 (Object type)。
原始类型 (共 7 种):
-
string
:表示文本。使用单引号 ('
)、双引号 ("
) 或反引号 (`) 包含。javascript
let str1 = '这是一个字符串';
let str2 = "这也是一个字符串";
let str3 = `你好, ${name}!`; // 模板字符串 (template literals),支持嵌入变量
console.log(str3); -
number
:表示数字,包括整数和浮点数。javascript
let num1 = 10; // 整数
let num2 = 3.14; // 浮点数
let num3 = NaN; // Not a Number,表示非法的数学运算结果
let num4 = Infinity; // 无穷大 -
boolean
:表示布尔值,只有两个:true
(真) 和false
(假)。常用于逻辑判断。javascript
let isloggedIn = true;
let hasPermission = false; -
null
:表示一个空值或不存在的对象。需要显式赋值为null
。javascript
let data = null; // 表示 data 变量没有指向任何对象 -
undefined
:表示一个未定义的值。通常是变量被声明了但没有赋值时的默认值,或者函数没有返回值时。“`javascript
let score; // 变量声明了但没有赋值,默认值为 undefined
console.log(score); // 输出 undefinedfunction greet() {
// 没有 return 语句,默认返回 undefined
}
console.log(greet()); // 输出 undefined
``
null
*和
undefined的区别是一个常见的面试题。简单来说,
null是一个被有意设置的空值,而
undefined是变量缺少值时的状态。虽然
typeof null的结果是
“object”`(这是 JS 历史上的一个 bug),但它们是不同的。 -
symbol
(ES6 新增):表示唯一的、不可变的值。常用于对象的属性名,避免属性名冲突。javascript
const id = Symbol('id');
const anotherId = Symbol('id');
console.log(id === anotherId); // 输出 false -
bigint
(ES11 新增):表示任意精度的整数。用于处理大于number
类型能表示的最大安全整数(2^53 - 1
)的数值。javascript
const bigNumber = 1234567890123456789012345678901234567890n; // 末尾加 n 表示 BigInt
对象类型 (Object type):表示更复杂的复合数据结构。包括:
-
object
:广义上的对象,键值对的集合。例如:普通对象、数组、函数等。-
普通对象:无序的键值对集合,用于存储结构化数据。
javascript
let person = {
name: "张三",
age: 30,
isStudent: false
};
console.log(person.name); // 访问属性:点表示法
console.log(person['age']); // 访问属性:方括号表示法
person.city = "北京"; // 添加新属性
* 数组 (Array):有序的元素集合,用索引访问。javascript
let colors = ["红", "绿", "蓝"];
console.log(colors[0]); // 访问第一个元素 (索引从0开始)
console.log(colors.length); // 数组长度
colors.push("黄"); // 在末尾添加元素
* 函数 (Function):可执行的代码块。函数在 JS 中也是一种特殊的对象。javascript
function sayHello(name) {
return `你好, ${name}!`;
}
let greeting = sayHello("李四");
console.log(greeting);
-
-
function
:虽然函数在技术上是对象类型,但typeof
操作符对函数会返回"function"
,这表明了函数在 JS 中的特殊地位(它们是可调用的对象)。
typeof
操作符:用于检测一个变量或表达式的数据类型。
javascript
console.log(typeof "Hello"); // string
console.log(typeof 123); // number
console.log(typeof true); // boolean
console.log(typeof null); // object (历史遗留问题)
console.log(typeof undefined); // undefined
console.log(typeof Symbol()); // symbol
console.log(typeof 123n); // bigint
console.log(typeof {}); // object
console.log(typeof []); // object
console.log(typeof function() {}); // function
3.4 运算符 (Operators)
运算符用于对变量或值执行操作。
-
算术运算符:
+
(加),-
(减),*
(乘),/
(除),%
(取模/余数),**
(幂运算,ES6)javascript
let a = 10;
let b = 3;
console.log(a + b); // 13
console.log(a - b); // 7
console.log(a * b); // 30
console.log(a / b); // 3.333...
console.log(a % b); // 1
console.log(a ** b); // 1000 (10的3次方)
* 注意+
在字符串中是拼接作用:"Hello" + " " + "World"
结果是"Hello World"
。如果数字和字符串相加,数字会被转换为字符串进行拼接。 -
赋值运算符:
=
(赋值),+=
,-=
,*=
,/=
,%=
,**=
javascript
let x = 5;
x += 3; // 等同于 x = x + 3; x 现在是 8
x *= 2; // 等同于 x = x * 2; x 现在是 16 -
比较运算符:用于比较两个值,返回布尔值 (
true
或false
)。==
(相等,会进行类型转换)!=
(不等,会进行类型转换)===
(严格相等,不进行类型转换,要求值和类型都相等) – 强烈推荐使用!==
(严格不等,不进行类型转换) – 强烈推荐使用>
(大于),<
(小于),>=
(大于等于),<=
(小于等于)
javascript
console.log(5 == '5'); // true (会把 '5' 转成 5)
console.log(5 === '5'); // false (类型不同)
console.log(10 > 5); // true
console.log(null == undefined); // true (特殊情况)
console.log(null === undefined); // false
* 理解==
和===
的区别至关重要,===
是更安全的比较方式。 -
逻辑运算符:
&&
(逻辑与):如果左侧为真,则返回右侧的值;否则返回左侧的值。常用于判断多个条件是否都为真。||
(逻辑或):如果左侧为真,则返回左侧的值;否则返回右侧的值。常用于判断多个条件是否至少一个为真。!
(逻辑非):取反。
“`javascript
let isAdult = true;
let isStudent = false;
console.log(isAdult && isStudent); // false (true 与 false = false)
console.log(isAdult || isStudent); // true (true 或 false = true)
console.log(!isAdult); // false (非 true = false)// 短路评估 (Short-circuit evaluation)
let y = 0;
let result = (10 > 5) || (y++); // 左侧为真,|| 后面的表达式不再执行
console.log(result); // true
console.log(y); // 0let z = 0;
let outcome = (10 < 5) && (z++); // 左侧为假,&& 后面的表达式不再执行
console.log(outcome); // false
console.log(z); // 0
“` -
一元运算符:只作用于一个操作数,如
++
(自增),--
(自减),+
(转换为数字),-
(取负)javascript
let counter = 10;
counter++; // counter 现在是 11
console.log(-"5"); // -5 (字符串转数字并取负) -
三元条件运算符:一个简写形式的
if/else
语句。- 语法:
condition ? expressionIfTrue : expressionIfFalse
javascript
let age = 18;
let status = (age >= 18) ? "成年" : "未成年";
console.log(status); // 输出 "成年" - 语法:
3.5 类型转换 (Type Coercion)
JavaScript 是一种弱类型语言,它会在不同数据类型之间进行自动转换(隐式转换)。这有时会带来便利,但也可能导致意想不到的结果。
- 隐式转换:发生在运算符操作不同类型的数据时,JS 会尝试将它们转换为相同类型。
- 数字与字符串相加:数字转字符串进行拼接。
1 + "2"
->"12"
- 数字与布尔值相加:布尔值转数字 (
true
为 1,false
为 0)。1 + true
->2
- 使用
==
比较时。5 == '5'
->true
- 数字与字符串相加:数字转字符串进行拼接。
-
显式转换:开发者主动进行的类型转换。
- 转换为字符串:
String(value)
或value.toString()
(除null
和undefined
) - 转换为数字:
Number(value)
,parseInt(string)
,parseFloat(string)
- 转换为布尔值:
Boolean(value)
或使用!!value
“`javascript
console.log(String(123)); // “123”
console.log((123).toString()); // “123”console.log(Number(“456”)); // 456
console.log(parseInt(“100px”)); // 100 (解析到非数字字符停止)
console.log(parseFloat(“3.14”)); // 3.14
console.log(Number(“hello”)); // NaNconsole.log(Boolean(0)); // false
console.log(Boolean(“”)); // false
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean(” “)); // true (非空字符串)
console.log(Boolean(10)); // true (非零数字)
``
===` (严格相等) 来避免不必要的类型转换带来的问题**。
* 在进行比较和运算时,了解 JS 的类型转换规则非常重要。对于初学者,**强烈建议使用 - 转换为字符串:
第四章:控制代码流程 – 让程序“思考”
默认情况下,JS 代码是按照书写顺序从上到下依次执行的。但很多时候,我们需要根据条件来决定执行哪些代码,或者重复执行某段代码。这就需要使用控制流程语句。
4.1 条件语句 (Conditional Statements)
根据条件的真假来选择执行不同的代码块。
-
if
语句:当条件为真时执行代码块。javascript
let temperature = 25;
if (temperature > 20) {
console.log("天气有点热。");
} -
if...else
语句:当条件为真时执行第一个代码块,否则执行第二个代码块。javascript
let age = 16;
if (age >= 18) {
console.log("你已成年。");
} else {
console.log("你未成年。");
} -
if...else if...else
语句:用于处理多个互斥的条件。javascript
let score = 85;
if (score >= 90) {
console.log("优秀");
} else if (score >= 80) {
console.log("良好");
} else if (score >= 60) {
console.log("及格");
} else {
console.log("不及格");
}
4.2 switch
语句
当需要根据一个变量的不同值执行不同的代码块时,switch
语句是 if...else if
的另一种选择,尤其适用于多个固定值判断的情况。
javascript
let day = "星期三";
switch (day) {
case "星期一":
console.log("蓝色星期一");
break; // break 关键字用于跳出 switch 语句
case "星期五":
console.log("快乐星期五");
break;
case "星期六":
case "星期日": // 多个 case 可以共用一个代码块
console.log("周末愉快!");
break;
default: // 如果所有 case 都不匹配,则执行 default 块
console.log("工作日");
// default 块通常放在最后,不需要 break
}
* break
语句非常重要,它会结束当前的 switch
执行。如果没有 break
,匹配到一个 case 后会继续执行后面的 case 块(称为“穿透”或“fall-through”),直到遇到 break
或 switch
结束。
4.3 循环语句 (Loops)
循环用于重复执行一段代码,直到满足或不再满足某个条件。
-
for
循环:最常用的循环,适用于已知循环次数或有明确循环范围的情况。javascript
// 语法:for (初始化; 条件; 递增/递减) { // 循环体 }
for (let i = 0; i < 5; i++) {
console.log("这是第 " + (i + 1) + " 次循环");
}
// 输出:
// 这是第 1 次循环
// 这是第 2 次循环
// ...
// 这是第 5 次循环 -
while
循环:当条件为真时重复执行代码块。适用于循环次数未知,只知道循环结束条件的情况。javascript
let count = 0;
while (count < 3) {
console.log("count: " + count);
count++; // 必须要有更新条件的语句,否则可能成为无限循环
}
// 输出:
// count: 0
// count: 1
// count: 2 -
do...while
循环:先执行一次代码块,然后检查条件,如果条件为真,则重复执行。保证循环体至少被执行一次。javascript
let i = 0;
do {
console.log("i: " + i);
i++;
} while (i < 3);
// 输出:
// i: 0
// i: 1
// i: 2 -
for...in
循环:遍历对象的可枚举属性。javascript
const person = { name: "张三", age: 30 };
for (const key in person) {
console.log(key + ": " + person[key]);
}
// 输出:
// name: 张三
// age: 30
*for...in
不推荐用于遍历数组,因为它会遍历原型链上的属性,并且顺序可能不是数字索引顺序。 -
for...of
循环 (ES6 新增):遍历可迭代对象(如数组、字符串、Map、Set 等)的元素值。推荐用于遍历数组。javascript
const colors = ["红", "绿", "蓝"];
for (const color of colors) {
console.log(color);
}
// 输出:
// 红
// 绿
// 蓝
4.4 跳出循环 (break
和 continue
)
break
:立即终止当前循环(或switch
语句),跳到循环后面的第一行代码。continue
:跳过当前循环的剩余部分,进入下一次循环。
“`javascript
// break 示例
for (let i = 0; i < 10; i++) {
if (i === 5) {
break; // 当 i 等于 5 时,立即停止循环
}
console.log(“break 循环:” + i);
}
// 输出:0, 1, 2, 3, 4
// continue 示例
for (let i = 0; i < 5; i++) {
if (i === 2) {
continue; // 当 i 等于 2 时,跳过本次循环的 console.log,直接进入下一次循环 (i=3)
}
console.log(“continue 循环:” + i);
}
// 输出:0, 1, 3, 4
“`
第五章:函数 – 组织和复用你的代码
函数是一段可重复使用的代码块,它执行一个特定的任务。使用函数可以提高代码的可读性、可维护性和复用性。
5.1 声明和调用函数
-
函数声明 (Function Declaration):使用
function
关键字。“`javascript
function greet(name) { // name 是参数 (parameter)
console.log(“你好,” + name + “!”);
}greet(“张三”); // 调用函数,传入参数值 (“张三”) 称为实参 (argument)
greet(“李四”); // 可以多次调用
“` -
函数表达式 (Function Expression):将一个匿名函数赋值给一个变量。
“`javascript
const sayBye = function(name) {
console.log(“再见,” + name + “!”);
}; // 注意末尾的分号 (;) 是可选的,但建议加上sayBye(“王五”);
“`
* 函数声明可以在定义之前调用(因为存在函数提升),而函数表达式必须先定义后调用。对于初学者,通常使用函数声明更直观。 -
箭头函数 (Arrow Function) (ES6 新增):一种更简洁的函数表达式语法。
“`javascript
const add = (a, b) => {
return a + b;
};// 如果函数体只有一行 return 语句,可以进一步简化
const multiply = (a, b) => a * b;// 如果只有一个参数,可以省略圆括号
const double = num => num * 2;// 如果没有参数,需要空圆括号
const sayHello = () => console.log(“Hello!”);console.log(add(5, 3)); // 8
console.log(multiply(4, 5)); // 20
console.log(double(7)); // 14
sayHello(); // Hello!
``
this` 关键字的绑定方式),但在基础使用场景下,它们提供了一种更简洁的语法。对于简单的回调函数,箭头函数非常方便。
* 箭头函数相比普通函数有一些不同之处(例如
5.2 函数参数和返回值
- 参数 (Parameters):函数定义时括号中的变量,用于接收传入的数据。
- 实参 (Arguments):函数调用时传入的实际值。
-
返回值 (Return Value):函数可以通过
return
关键字返回一个值。如果没有return
语句或return
后面没有值,函数默认返回undefined
。“`javascript
function sum(a, b) {
let result = a + b;
return result; // 返回计算结果
}let total = sum(10, 20); // 调用函数并将返回值赋给变量
console.log(total); // 30function doSomething() {
console.log(“只执行,不返回特定值”);
// 没有 return 语句
}
console.log(doSomething()); // undefined
“`
5.3 作用域 (Scope)
作用域决定了变量的可见性和生命周期。在 JS 中主要有两种作用域:
- 全局作用域 (Global Scope):在函数或块外部声明的变量具有全局作用域,在代码的任何地方都可以访问。应尽量避免滥用全局变量,以免引起命名冲突和维护困难。
- 局部作用域 (Local Scope):
- 函数作用域 (Function Scope):使用
var
在函数内部声明的变量具有函数作用域,只能在该函数内部访问。 - 块级作用域 (Block Scope):使用
let
和const
在一对花括号{}
内声明的变量具有块级作用域,只能在该块内部访问。块可以是if
语句、for
循环、函数等。
- 函数作用域 (Function Scope):使用
理解作用域对于避免变量命名冲突和理解变量生命周期非常重要。ES6 引入的块级作用域(let
/const
)是现代 JS 开发中的最佳实践。
“`javascript
let globalVar = “我是全局变量”;
function myFunction() {
let functionVar = “我是函数作用域变量”; // let 具有块级作用域
var oldFunctionVar = “我是老的函数作用域变量”; // var 具有函数作用域
console.log(globalVar); // 可以在函数内访问全局变量
console.log(functionVar);
console.log(oldFunctionVar);
if (true) {
let blockVar = "我是块级作用域变量"; // 只能在 if 块内访问
console.log(blockVar);
console.log(functionVar); // 可以在块内访问函数作用域变量
console.log(globalVar); // 可以在块内访问全局变量
}
// console.log(blockVar); // 在块外部访问块级变量会报错
}
myFunction();
console.log(globalVar); // 可以在函数外访问全局变量
// console.log(functionVar); // 在函数外访问函数作用域变量会报错
// console.log(oldFunctionVar); // 在函数外访问函数作用域变量会报错
“`
第六章:数组与对象 – 处理集合数据
在实际开发中,我们经常需要处理一组相关的数据。数组和对象是 JavaScript 中用于组织这些集合数据的基本结构。
6.1 数组 (Arrays)
数组是一种有序的集合,其中的每个元素都有一个索引(从 0 开始)。
-
创建数组:
“`javascript
// 数组字面量 (推荐)
let fruits = [“苹果”, “香蕉”, “橘子”];// 使用 Array 构造函数 (不常用,有陷阱)
// let numbers = new Array(1, 2, 3); // 创建包含 1, 2, 3 的数组
// let strangeArray = new Array(5); // 创建一个长度为 5 的空数组 (注意不是 [5])
“` -
访问数组元素:通过索引访问。
javascript
console.log(fruits[0]); // 输出 "苹果"
console.log(fruits[2]); // 输出 "橘子"
console.log(fruits[3]); // 输出 undefined (索引越界) -
修改数组元素:通过索引赋值。
javascript
fruits[1] = "葡萄"; // 将第二个元素改为 "葡萄"
console.log(fruits); // 输出 ["苹果", "葡萄", "橘子"] -
数组长度:使用
.length
属性。javascript
console.log(fruits.length); // 输出 3 (修改后是 3) -
添加/删除元素:
.push(element)
:在末尾添加一个或多个元素,返回新长度。.pop()
:删除并返回末尾元素。.unshift(element)
:在开头添加一个或多个元素,返回新长度。.shift()
:删除并返回开头元素。
javascript
let nums = [1, 2];
nums.push(3, 4); // nums becomes [1, 2, 3, 4]
let last = nums.pop(); // last is 4, nums becomes [1, 2, 3]
nums.unshift(0); // nums becomes [0, 1, 2, 3]
let first = nums.shift(); // first is 0, nums becomes [1, 2, 3] -
常用数组方法:
.forEach(callback)
:遍历数组的每个元素,对每个元素执行一次 callback 函数。.map(callback)
:创建一个新数组,新数组的元素是原数组元素调用 callback 函数的返回值。.filter(callback)
:创建一个新数组,新数组只包含通过 callback 函数测试的元素。.find(callback)
:返回数组中满足 callback 函数测试的第一个元素的值,否则返回undefined
。.indexOf(element)
:返回元素第一次出现的索引,否则返回 -1。.includes(element)
(ES7):判断数组是否包含某个元素,返回布尔值。
“`javascript
let numbers = [1, 2, 3, 4, 5];numbers.forEach(function(num) {
console.log(num * 2); // 输出 2, 4, 6, 8, 10
});let doubled = numbers.map(num => num * 2);
console.log(doubled); // 输出 [2, 4, 6, 8, 10]let evens = numbers.filter(num => num % 2 === 0);
console.log(evens); // 输出 [2, 4]console.log(numbers.includes(3)); // 输出 true
“`
* 熟悉这些数组方法能大大提高处理列表数据的效率。
6.2 对象 (Objects)
对象是无序的属性集合,每个属性由键 (key,通常是字符串或 Symbol) 和值 (value,可以是任何数据类型) 组成。对象用于表示现实世界中的实体或复杂的数据结构。
-
创建对象:
“`javascript
// 对象字面量 (推荐)
let car = {
brand: “Toyota”,
model: “Camry”,
year: 2023,
isElectric: false,
start: function() { // 属性值也可以是函数 (方法)
console.log(“Engine started!”);
}
};// 使用 Object 构造函数 (不常用)
// let anotherCar = new Object();
// anotherCar.brand = “Honda”;
“` -
访问对象属性:
- 点表示法 (Dot notation):当键是有效的变量名时使用。
object.key
- 方括号表示法 (Bracket notation):当键包含特殊字符或来自变量时使用。
object['key']
“`javascript
console.log(car.brand); // 输出 “Toyota”
console.log(car[‘model’]); // 输出 “Camry”let propName = ‘year’;
console.log(car[propName]); // 使用变量访问属性,输出 2023
“` - 点表示法 (Dot notation):当键是有效的变量名时使用。
-
修改/添加属性:通过赋值操作。
javascript
car.year = 2024; // 修改属性值
car.color = "Red"; // 添加新属性
console.log(car.year); // 2024
console.log(car.color); // Red -
删除属性:使用
delete
运算符。javascript
delete car.isElectric;
console.log(car.isElectric); // 输出 undefined -
调用对象方法:
javascript
car.start(); // 输出 "Engine started!" -
遍历对象属性:
- 使用
for...in
循环 (如前所述)。 - 使用
Object.keys(object)
获取所有键组成的数组。 - 使用
Object.values(object)
获取所有值组成的数组。 - 使用
Object.entries(object)
获取所有键值对[key, value]
组成的数组。
``javascript
${key}: ${car[key]}`);
for (const key in car) {
console.log(
}console.log(Object.keys(car)); // 输出 [“brand”, “model”, “year”, “color”, “start”]
console.log(Object.values(car)); // 输出 [“Toyota”, “Camry”, 2024, “Red”, [Function: start]]
console.log(Object.entries(car)); // 输出 [ [“brand”, “Toyota”], [“model”, “Camry”], … ]
“` - 使用
6.3 数组与对象的结合使用
数组和对象经常嵌套使用,构建更复杂的数据结构,例如:
“`javascript
// 一个包含多个用户对象的数组
let users = [
{ id: 1, name: “Alice”, city: “New York” },
{ id: 2, name: “Bob”, city: “London” },
{ id: 3, name: “Charlie”, city: “New York” }
];
// 访问第二个用户的城市
console.log(users[1].city); // 输出 “London”
// 遍历所有用户,打印他们的名字
users.forEach(user => {
console.log(user.name); // 输出 “Alice”, “Bob”, “Charlie”
});
“`
第七章:JavaScript 与 Web 页面交互 – DOM
前端 JavaScript 最核心的功能之一就是操作网页的内容、结构和样式,这就是通过 DOM (Document Object Model – 文档对象模型) 实现的。
7.1 什么是 DOM?
当你用浏览器打开一个 HTML 页面时,浏览器会解析 HTML 代码,并将其构建成一个树状结构,这个树就是 DOM。树的每个节点都代表 HTML 页面中的一个部分,比如元素 (<div>
, <p>
)、属性 (id
, class
)、文本 (Hello World!
) 等。
JavaScript 可以通过浏览器提供的 DOM API 来访问和操作这个 DOM 树,从而改变页面的外观和行为。document
对象是 DOM 的入口点,它代表了整个 HTML 文档。
7.2 获取 DOM 元素
在操作元素之前,首先需要找到它们。常用的获取元素的方法:
-
document.getElementById(id)
:通过元素的id
属性获取单个元素。id
在页面中应该是唯一的。html
<div id="myDiv">这是一个 div</div>
<script>
const myDiv = document.getElementById('myDiv');
console.log(myDiv); // 输出获取到的 div 元素
</script> -
document.getElementsByClassName(className)
:通过类名获取一组元素(返回一个类似数组的 HTMLCollection)。html
<p class="myClass">段落 1</p>
<p class="myClass">段落 2</p>
<script>
const paragraphs = document.getElementsByClassName('myClass');
console.log(paragraphs); // 输出一个包含两个 p 元素的 HTMLCollection
console.log(paragraphs[0]); // 访问第一个元素
</script> -
document.getElementsByTagName(tagName)
:通过标签名获取一组元素。html
<ul><li>Item 1</li><li>Item 2</li></ul>
<script>
const listItems = document.getElementsByTagName('li');
console.log(listItems.length); // 输出 2
</script> -
document.querySelector(selector)
:使用 CSS 选择器获取第一个匹配的元素。html
<div class="container"><p>第一个段落</p></div>
<div class="container"><p>第二个段落</p></div>
<script>
const firstPara = document.querySelector('.container p');
console.log(firstPara.textContent); // 输出 "第一个段落"
</script> -
document.querySelectorAll(selector)
:使用 CSS 选择器获取所有匹配的元素(返回一个 NodeList,类似数组)。html
<div class="container"><p>第一个段落</p></div>
<div class="container"><p>第二个段落</p></div>
<script>
const allParas = document.querySelectorAll('.container p');
console.log(allParas.length); // 输出 2
allParas.forEach(p => console.log(p.textContent)); // 可以使用 forEach 遍历 NodeList
</script>
* 推荐使用querySelector
和querySelectorAll
,因为它们使用了熟悉的 CSS 选择器语法,更灵活强大。
7.3 操作 DOM 元素
获取到元素后,就可以修改它的属性、内容或样式。
-
修改元素内容:
.textContent
:获取或设置元素的纯文本内容。.innerHTML
:获取或设置元素的 HTML 内容(会解析其中的 HTML 标签)。
html
<div id="contentDiv">原始内容</div>
<script>
const div = document.getElementById('contentDiv');
div.textContent = "新的纯文本内容"; // div 的内容变成 "新的纯文本内容"
div.innerHTML = "新的 <strong>加粗</strong> 内容"; // div 的内容变成 "新的 **加粗** 内容" (加粗会生效)
</script>
* 使用innerHTML
插入来自外部的、不可信的数据是不安全的,可能导致跨站脚本攻击 (XSS),谨慎使用。 -
修改元素属性:
.attributeName
:直接访问或设置常见的属性(如id
,class
,src
,href
,value
等)。.setAttribute(attributeName, value)
:设置任意属性的值。.getAttribute(attributeName)
:获取属性的值。.removeAttribute(attributeName)
:移除属性。
“`html
“` -
修改元素样式:使用
.style
属性,后接 CSS 属性名(注意 CSS 属性名在 JS 中需要转为驼峰命名,如background-color
变为backgroundColor
)。``html
.style
<div id="styledDiv" style="color: blue;">这段文字是蓝色的</div>
<script>
const styledDiv = document.getElementById('styledDiv');
styledDiv.style.color = "red"; // 将文字颜色改为红色
styledDiv.style.fontSize = "20px"; // 将字体大小改为 20px
styledDiv.style.backgroundColor = "yellow"; // 将背景色改为黄色
</script>
*只能修改行内样式。更好的做法是修改元素的 class,然后通过 CSS 控制不同 class 的样式。
element.classList.add(‘className’)
*:添加类名。
element.classList.remove(‘className’)
*:移除类名。
element.classList.toggle(‘className’)
*:如果存在则移除,不存在则添加。
element.classList.contains(‘className’)`:检查是否存在类名。
*html
<div id="classDiv" class="active"></div>
<style>.active { border: 1px solid black; } .highlight { background-color: yellow; }</style>
<script>
const classDiv = document.getElementById('classDiv');
classDiv.classList.remove('active'); // 移除 active 类
classDiv.classList.add('highlight'); // 添加 highlight 类
console.log(classDiv.classList.contains('highlight')); // true
</script> -
创建和移除元素:
document.createElement(tagName)
:创建一个新的元素节点。parentElement.appendChild(childElement)
:将一个子元素添加到父元素的末尾。parentElement.removeChild(childElement)
:从父元素中移除一个子元素。element.remove()
(较新方法):移除元素自身。
“`html
- 现有列表项
“`
第八章:事件处理 – 让页面响应用户
网页的交互性很大程度上是通过事件 (Events) 来实现的。事件是用户或浏览器执行的某种动作,例如点击按钮、鼠标移动、键盘按下、页面加载完成等。JavaScript 可以“监听”这些事件,并在事件发生时执行相应的代码。
8.1 什么是事件和事件监听器?
- 事件:发生在 HTML 元素上的事情。例如:
- 鼠标事件:
click
,mouseover
,mouseout
- 键盘事件:
keydown
,keyup
,keypress
- 表单事件:
submit
,input
,change
,focus
,blur
- 文档/窗口事件:
load
,scroll
,resize
- 鼠标事件:
- 事件监听器 (Event Listener):一个函数,当特定事件发生在特定元素上时会被执行。
8.2 添加事件监听器
最推荐使用的方法是 addEventListener()
。
element.addEventListener(event, handler)
:event
:事件名称的字符串(不带 “on”,如'click'
而不是'onclick'
)。handler
:一个函数,当事件发生时执行(也称为回调函数)。
“`html
“`
8.3 事件对象 (Event Object)
当事件发生时,浏览器会自动创建一个事件对象,并将其作为参数传递给事件处理函数。这个对象包含了有关事件的详细信息。
javascript
button.addEventListener('click', function(event) { // event 就是事件对象
console.log("事件类型:" + event.type); // 输出 "click"
console.log("触发事件的元素:" + event.target); // 输出触发点击事件的 DOM 元素 (<button id="myButton">...)
console.log("鼠标点击位置 (相对于文档):X=" + event.pageX + ", Y=" + event.pageY); // 对于鼠标事件
});
* 对于不同的事件类型,事件对象包含的属性也不同。了解常用的事件对象属性对于处理复杂交互非常有用。
8.4 阻止默认行为和事件冒泡
-
阻止默认行为:某些 HTML 元素的事件有默认行为(例如点击链接会跳转、提交表单会刷新页面)。可以使用
event.preventDefault()
来阻止这些默认行为。html
<a href="https://www.example.com" id="myLink">访问示例网站</a>
<script>
const link = document.getElementById('myLink');
link.addEventListener('click', function(event) {
event.preventDefault(); // 阻止链接的默认跳转行为
alert("链接的默认行为被阻止了!");
});
</script> -
事件冒泡 (Event Bubbling):当一个元素上触发某个事件时,该事件会从该元素开始,逐级向上“冒泡”到其父元素、祖先元素,直到文档根部。这意味着父元素也可以捕获到子元素触发的事件。可以使用
event.stopPropagation()
来阻止事件的冒泡。“`html
“`
* 理解事件冒泡和阻止默认行为是处理复杂页面交互的基础。
第九章:学习资源与进阶之路
恭喜你!走到这里,你已经掌握了 JavaScript 的核心基础。这只是起点,JS 的世界广阔而精彩。接下来的关键是持续学习和大量实践。
9.1 推荐的学习资源
- MDN Web Docs (Mozilla Developer Network):JavaScript 的官方文档,非常权威、全面且易懂。遇到任何 JS 语法或 Web API 的问题,MDN 都是首选的查阅资料。
- freeCodeCamp:提供免费的交互式编程课程,包括大量的 JS 练习和项目。
- Codecademy:提供交互式在线课程,通过动手实践来学习。
- Udemy / Coursera / edX 等在线教育平台:有许多高质量的付费和免费 JS 课程,可以系统学习。
- 《JavaScript 高级程序设计》、《深入理解 JavaScript》等经典书籍:系统性学习的深度资料。
- YouTube / Bilibili 上的技术教程视频:通过观看视频学习和理解概念。
- GitHub:查找开源项目,学习他人的代码。
9.2 实践的重要性
理论知识只有通过实践才能真正掌握。
- 动手敲代码:跟着教程敲,然后尝试修改、扩展代码。
- 解决小问题:尝试用 JS 解决一些实际的小问题,比如:
- 计算器
- 待办事项列表 (Todo List)
- 简单的表单验证
- 图片轮播
- 计时器
- 构建小项目:从简单的静态页面开始,逐步添加 JS 交互功能。
- 参与开源项目:等你对基础比较熟悉后,可以尝试为一些简单的开源项目贡献代码。
9.3 如何面对错误 (Bug)
编程过程中遇到错误是家常便饭。不要害怕,调试是程序员的基本功。
- 阅读错误信息:浏览器控制台会显示错误信息,包括错误类型、错误发生的文件和行号。仔细阅读这些信息,它们通常能指引你找到问题所在。
- 使用
console.log()
调试:在关键位置输出变量的值,检查程序执行流程,定位问题。 - 使用浏览器开发者工具的断点调试:在代码行号上点击可以设置断点,程序会在该行暂停执行,你可以一步步查看变量的值、执行顺序等,这是最高效的调试方法。
9.4 进阶之路
掌握基础后,JS 的学习和发展方向有很多:
- 深入 ECMAScript 新特性:ES6+ 带来了许多重要的新特性(如 Promises, Async/Await 处理异步,Classes 实现面向对象等),需要深入学习。
- 异步编程:JavaScript 处理异步操作(如网络请求、定时器)的方式比较特殊,Promises, Async/Await 是现代 JS 异步编程的核心。
- 模块化:学习如何组织大型项目,使用 ES Modules (
import
/export
)。 - 包管理器:了解 npm 或 yarn,如何使用第三方库。
- 前端框架/库:学习 React, Vue 或 Angular 等流行的前端框架,它们能帮助你更高效地构建复杂的单页面应用 (SPA)。
- Node.js:学习使用 JavaScript 进行服务器端开发。
- TypeScript:学习这门 JS 的超集,它引入了静态类型,可以提高大型项目的可维护性。
- 前端构建工具:了解 Webpack, Vite 等工具,它们用于打包、优化你的前端代码。
结语
学习 JavaScript 是一段充满挑战但也非常有成就感的旅程。从理解变量、数据类型到掌握控制流程、函数、数组、对象,再到利用 DOM 和事件与网页交互,你已经迈出了坚实的第一步。
记住,编程不是一蹴而就的技能。保持好奇心,乐于探索,勤于动手,善于利用资源,积极解决问题。随着你的不断深入,你会发现 JavaScript 的强大之处,并能够创造出令人惊叹的 Web 应用和更多可能性。
祝你在 JavaScript 的学习之路上一切顺利!未来的精彩,等你用代码去创造!