JavaScript 教程 [最新版]:新手起步 – 从零到一的编程之旅
欢迎来到 JavaScript 的世界!无论你是完全的编程新手,还是希望扩展技能栈的开发者,这份详尽的 JavaScript 入门教程都将为你打下坚实的基础。JavaScript 是当今互联网的基石之一,驱动着绝大多数现代网站的交互性和动态功能。掌握它,你将能够为网页添加活力,构建复杂的 Web 应用程序,甚至涉足服务器端开发(Node.js)、移动应用(React Native, NativeScript)等领域。
本教程面向绝对零基础的初学者,我们将从最基本的概念讲起,逐步深入,力求让你不仅“知其然”,更能“知其其所以然”。
教程目标:
- 理解 JavaScript 是什么,以及它在 Web 开发中的作用。
- 掌握 JavaScript 的基本语法、数据类型和核心结构。
- 学会如何在网页中引入和运行 JavaScript 代码。
- 能够编写简单的脚本来操作网页内容(DOM 基础)。
- 为后续深入学习打下坚实基础。
准备工作:
你只需要两样东西:
- 一个现代的网页浏览器: Chrome、Firefox、Edge 或 Safari 都可以。它们都内置了强大的开发者工具,是学习和调试 JavaScript 的利器。
- 一个文本编辑器: 你可以用系统自带的记事本(Windows)或文本编辑(Mac),但强烈推荐使用更专业的代码编辑器,如 VS Code (Visual Studio Code,免费且功能强大)、Sublime Text 或 Atom。这些编辑器提供语法高亮、代码提示等功能,能极大提升你的学习和开发效率。
第一章:JavaScript 简介 – 开启你的编程之门
1.1 什么是 JavaScript?
JavaScript (简称 JS) 是一种轻量级、解释型、面向对象的脚本语言。听起来很复杂?别担心,我们来分解一下:
- 脚本语言 (Scripting Language): 意味着它通常不需要像 C++ 或 Java 那样先编译成机器码再运行。浏览器(或 Node.js 环境)会直接读取你的 JS 代码,并一行行地解释执行。这使得开发周期更快,更容易上手。
- 轻量级 (Lightweight): 相对于一些大型编程语言,JS 的核心功能集相对较小,但通过其强大的生态系统(库和框架)可以实现极其复杂的功能。
- 解释型 (Interpreted): 代码在运行时由解释器(浏览器中的 JS 引擎,如 V8、SpiderMonkey)逐行翻译执行。
- 面向对象 (Object-Oriented): 虽然 JS 的面向对象模型与其他语言(如 Java)有所不同(基于原型),但它确实支持封装、继承(通过原型链)和多态等面向对象的概念,允许你用对象来组织代码。
最重要的是: JavaScript 是唯一一种能够直接在网页浏览器中运行的编程语言。它赋予了网页动态交互的能力。
1.2 JavaScript 能做什么?
想象一下没有 JavaScript 的网页:它就像一张静态的海报,内容固定,无法响应你的操作。有了 JavaScript,网页就能:
- 响应用户操作: 点击按钮、鼠标悬停、键盘输入等,都可以触发 JS 代码执行相应的功能(如弹出菜单、验证表单、发送数据)。
- 修改网页内容: 动态地添加、删除或修改 HTML 元素和文本内容,无需刷新整个页面(想想无限滚动的社交媒体信息流)。
- 改变网页样式: 动态地修改 CSS 样式,实现动画效果、主题切换等。
- 与用户交互: 创建弹出窗口、提示框、确认框等。
- 与服务器通信: 在后台发送和接收数据(AJAX/Fetch API),实现无需页面刷新的数据更新(如在线聊天、实时股价)。
- 执行复杂的计算和逻辑: 在浏览器端处理数据、进行游戏逻辑运算等。
超越浏览器:
- Node.js: 让 JavaScript 能够运行在服务器端,用于构建后端服务、API 等。
- 移动应用: 框架如 React Native, NativeScript 允许使用 JavaScript 构建原生移动应用。
- 桌面应用: 框架如 Electron 允许使用 Web 技术(包括 JS)构建跨平台桌面应用(如 VS Code 本身就是用 Electron 构建的)。
1.3 JavaScript 不是 Java!
这是一个常见的误区。JavaScript 和 Java 是两种完全不同的编程语言,尽管名字相似。它们由不同的公司开发,语法、设计哲学和应用领域都有很大差异。记住这一点!
第二章:初识 JavaScript – 环境搭建与第一个程序
2.1 JavaScript 的运行环境
最常见的运行环境就是你的网页浏览器。每个现代浏览器都内置了一个 JavaScript 引擎:
- Chrome: V8 引擎
- Firefox: SpiderMonkey 引擎
- Safari: JavaScriptCore 引擎
- Edge: (基于 Chromium) V8 引擎
此外,Node.js 提供了一个可以在服务器或本地计算机上运行 JavaScript 的环境。在本入门教程中,我们主要关注浏览器环境。
2.2 如何在 HTML 中引入 JavaScript
有三种主要方式将 JavaScript 代码添加到 HTML 页面中:
-
内部脚本 (Internal Script): 使用
<script>
标签将代码直接嵌入 HTML 文件中。通常放在<head>
或<body>
标签的末尾。“`html
<!DOCTYPE html>
我的第一个 JS 页面
欢迎!
<script> // 这是 JavaScript 代码 console.log("你好,JavaScript!来自内部脚本"); alert("这是一个弹窗!"); // alert 会弹出一个提示框 </script>
“` -
外部脚本 (External Script): 这是推荐的方式。将 JavaScript 代码保存在一个单独的
.js
文件中,然后通过<script>
标签的src
属性链接到 HTML 文件。这使得代码更易于维护、重用和缓存。-
创建一个
main.js
文件 (与 HTML 文件放在同一目录下或指定路径):javascript
// main.js
console.log("你好,JavaScript!来自外部文件");
alert("来自外部文件的弹窗!"); -
在 HTML 文件中引用它:
“`html
<!DOCTYPE html>
使用外部 JS 文件
查看控制台和弹窗
<!-- 推荐将 script 标签放在 body 结束标签之前 --> <!-- 这样可以确保 HTML 元素加载完毕后再执行 JS --> <script src="main.js"></script>
“`
-
-
内联脚本 (Inline Script – 不推荐): 直接将少量 JS 代码写在 HTML 元素的事件属性中(如
onclick
)。这种方式难以维护,应尽量避免。html
<button onclick="alert('按钮被点击了!');">点我</button>
最佳实践: 始终优先使用外部脚本,并将 <script>
标签放在 </body>
之前。这可以确保 HTML 结构完全加载解析完毕后,JS 代码再去操作它们,避免因元素未加载而导致的错误,同时也能提高页面的初始渲染速度。
2.3 “Hello, World!” – 你的第一个 JavaScript 程序
让我们通过最经典的 “Hello, World!” 来正式开始。我们将使用 console.log()
,这是一个非常有用的函数,可以将信息输出到浏览器的开发者控制台。
-
创建 HTML 文件 (
index.html
):“`html
<!DOCTYPE html>
Hello World
打开开发者控制台查看消息
<script src="app.js"></script>
“` -
创建 JavaScript 文件 (
app.js
):javascript
// app.js
console.log("Hello, World!");
console.log("你好,世界!"); -
运行:
- 用浏览器打开
index.html
文件。 - 页面上会显示 “打开开发者控制台查看消息”。
- 打开开发者控制台: 在页面上右键 -> 选择 “检查” (Inspect) 或 “检查元素” (Inspect Element),然后切换到 “控制台” (Console) 标签页。
- 你将在控制台中看到输出的两行文字:”Hello, World!” 和 “你好,世界!”。
- 用浏览器打开
console.log()
是你最好的朋友! 在学习和调试过程中,你会频繁使用 console.log()
来检查变量的值、代码的执行流程等。
第三章:JavaScript 基础语法 – 构建代码的砖瓦
3.1 注释 (Comments)
注释是代码中不会被执行的部分,用于解释代码的功能、目的或留下笔记。良好的注释习惯非常重要。
“`javascript
// 这是一个单行注释
/
这是一个
多行注释。
可以跨越多行。
/
let message = “Hello”; // 也可以在代码行后面添加注释
“`
3.2 语句 (Statements)
JavaScript 代码由一系列语句组成,每个语句执行一个特定的任务。语句通常以分号 (;
) 结尾。虽然在很多情况下 JavaScript 会自动插入分号(ASI – Automatic Semicolon Insertion),但强烈建议始终手动添加分号,以避免潜在的歧义和错误。
javascript
let name = "Alice"; // 这是一个赋值语句
console.log(name); // 这是一个函数调用语句
let age = 30; // 另一个赋值语句
3.3 变量 (Variables)
变量是用来存储数据的容器。在使用变量之前,需要先声明它。在现代 JavaScript (ES6 及以后版本) 中,我们主要使用 let
和 const
来声明变量。
-
let
: 声明一个可以被重新赋值的变量。“`javascript
let score = 0;
console.log(score); // 输出: 0score = 100; // 可以重新赋值
console.log(score); // 输出: 100let userName; // 可以只声明,不立即赋值,此时它的值是 undefined
console.log(userName); // 输出: undefined
userName = “Bob”;
console.log(userName); // 输出: Bob
“` -
const
: 声明一个常量,其值在声明时必须初始化,并且不能被重新赋值。这有助于代码的健壮性,表示这个值不应该改变。“`javascript
const PI = 3.14159;
console.log(PI); // 输出: 3.14159// PI = 3.14; // 这会抛出一个错误 (TypeError: Assignment to constant variable.)
// const MAX_USERS; // 错误!常量必须在声明时初始化
“`注意: 对于用
const
声明的对象或数组,虽然不能重新赋值整个变量,但可以修改对象内部的属性或数组的元素。“`javascript
const user = { name: “Charlie”, age: 25 };
user.age = 26; // 这是允许的,我们修改的是对象的属性,不是 user 变量本身
console.log(user); // 输出: { name: ‘Charlie’, age: 26 }// user = { name: “David” }; // 错误!不能给常量重新赋值
const colors = [“red”, “green”];
colors.push(“blue”); // 这是允许的,我们修改的是数组的内容
console.log(colors); // 输出: [‘red’, ‘green’, ‘blue’]// colors = [“yellow”]; // 错误!不能给常量重新赋值
“` -
var
(旧方式 – 避免使用): 在 ES6 之前,var
是声明变量的唯一方式。它有一些作用域(后面会讲)和提升 (hoisting) 方面的问题,容易导致意想不到的行为。在现代 JavaScript 开发中,应优先使用let
和const
,避免使用var
。
变量命名规则:
- 可以包含字母、数字、下划线 (
_
) 和美元符号 ($
)。 - 必须以字母、下划线或美元符号开头,不能以数字开头。
- 区分大小写 (
myVariable
和myvariable
是不同的变量)。 - 不能使用 JavaScript 的保留关键字(如
let
,const
,if
,for
,function
等)作为变量名。 - 推荐使用驼峰命名法 (camelCase): 第一个单词小写,后续单词首字母大写,如
firstName
,totalAmount
,isUserLoggedIn
。
3.4 数据类型 (Data Types)
JavaScript 是一种动态类型语言,这意味着你不需要在声明变量时指定它的数据类型,变量的类型会在运行时根据赋给它的值自动确定。
JavaScript 主要有以下几种基本(原始)数据类型和一种复杂数据类型:
基本(原始)数据类型 (Primitive Types):
-
string
(字符串): 用于表示文本。用单引号 ('
) 或双引号 ("
) 包裹。`javascript
`),可以方便地嵌入变量
let greeting = "Hello, world!";
let name = 'Alice';
let message = `你好,${name}!`; // ES6 模板字符串 (Template Literals),使用反引号 (`console.log(greeting);
console.log(message); // 输出: 你好,Alice!
“` -
number
(数字): 用于表示整数或浮点数(小数)。包括特殊值Infinity
(无穷大),-Infinity
(负无穷大) 和NaN
(Not-a-Number,表示一个无法表示的数值结果,如0 / 0
)。“`javascript
let age = 30;
let price = 99.99;
let temperature = -10;
let result = 0 / 0; // NaN
let infinity = Infinity;console.log(typeof age); // 输出: “number”
console.log(typeof price); // 输出: “number”
console.log(result); // 输出: NaN
console.log(typeof NaN); // 输出: “number” (注意 NaN 本身是 number 类型)
“` -
boolean
(布尔值): 只有两个值:true
(真) 和false
(假)。常用于逻辑判断。“`javascript
let isLoggedIn = true;
let hasPermission = false;console.log(typeof isLoggedIn); // 输出: “boolean”
“` -
null
: 表示一个有意设置的“空值”或“无对象”。它是一个表示“没有值”的值。javascript
let selectedUser = null; // 表示当前没有选中用户
console.log(selectedUser); // 输出: null
console.log(typeof null); // 输出: "object" (这是一个历史遗留的 bug,但已被广泛接受) -
undefined
: 表示一个变量已被声明,但尚未被赋值。或者访问对象上不存在的属性时也会得到undefined
。javascript
let address;
console.log(address); // 输出: undefined
console.log(typeof address); // 输出: "undefined" -
symbol
(ES6新增): 表示唯一的、不可变的值。通常用作对象属性的键,以避免命名冲突。初学阶段可以暂时不用深入了解。 -
bigint
(ES2020新增): 用于表示超出number
类型安全整数范围的极大整数。通过在整数末尾添加n
来创建。初学阶段可以暂时不用深入了解。javascript
const veryLargeNumber = 9007199254740991n; // 注意末尾的 'n'
console.log(typeof veryLargeNumber); // 输出: "bigint"
复杂数据类型 (Complex Type):
-
object
(对象): 用于存储键值对的集合。是 JavaScript 中最重要的数据结构之一。可以包含各种数据类型(包括其他对象或函数)。“`javascript
let person = {
firstName: “John”, // firstName 是键 (key),”John” 是值 (value)
lastName: “Doe”,
age: 30,
isStudent: false,
address: { // 值可以是另一个对象
street: “123 Main St”,
city: “Anytown”
},
greet: function() { // 值可以是一个函数(称为方法)
console.log(“Hello!”);
}
};console.log(person.firstName); // 访问属性:使用点 . 表示法
console.log(person[“lastName”]); // 访问属性:也可以使用方括号 [] 表示法(键需要是字符串)
console.log(person.address.city); // 访问嵌套对象的属性
person.greet(); // 调用对象的方法console.log(typeof person); // 输出: “object”
“`数组 (Array) 在 JavaScript 中也是一种特殊的对象。
typeof
操作符:
可以使用 typeof
操作符来检查一个变量的数据类型。
javascript
console.log(typeof "Hello"); // "string"
console.log(typeof 100); // "number"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object" (特殊情况)
console.log(typeof {}); // "object"
console.log(typeof []); // "object" (数组也是对象)
console.log(typeof function(){}); // "function" (函数有自己的 typeof 结果)
第四章:运算符与表达式 – 让代码动起来
运算符用于对值(操作数)执行操作。
4.1 算术运算符 (Arithmetic Operators)
用于执行数学计算。
+
: 加法 (也可用于字符串连接)-
: 减法*
: 乘法/
: 除法%
: 取模 (求余数)**
: 幂运算 (ES7)++
: 自增 (加 1)--
: 自减 (减 1)
“`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 (10 除以 3 余 1)
console.log(a ** b); // 1000 (10 的 3 次方)
let count = 5;
count++; // count 现在是 6 (后自增)
++count; // count 现在是 7 (前自增)
console.log(count); // 7
let str1 = “Hello”;
let str2 = ” World”;
console.log(str1 + str2); // “Hello World” (字符串连接)
console.log(“Score: ” + 100); // “Score: 100” (数字会转换为字符串再连接)
“`
注意 +
的特殊性: 如果 +
的操作数中有一个是字符串,它会执行字符串连接,而不是数学加法。如果想确保进行数学运算,可以使用 parseInt()
或 parseFloat()
或 Number()
将字符串转换为数字。
4.2 赋值运算符 (Assignment Operators)
用于给变量赋值。
=
: 简单赋值+=
: 加法赋值 (x += y
等同于x = x + y
)-=
: 减法赋值*=
: 乘法赋值/=
: 除法赋值%=
: 取模赋值**=
: 幂赋值
“`javascript
let x = 10;
let y = 5;
x += y; // x = x + y => x = 15
console.log(x); // 15
x *= 2; // x = x * 2 => x = 30
console.log(x); // 30
“`
4.3 比较运算符 (Comparison Operators)
用于比较两个值,返回一个布尔值 (true
或 false
)。
==
: 等于 (值相等,会进行类型转换) – 不推荐===
: 严格等于 (值和类型都相等) – 推荐!=
: 不等于 (值不相等,会进行类型转换) – 不推荐!==
: 严格不等于 (值或类型不相等) – 推荐>
: 大于<
: 小于>=
: 大于等于<=
: 小于等于
“`javascript
let num1 = 10;
let num2 = “10”;
let num3 = 20;
console.log(num1 == num2); // true (值相等,”10″ 被转换为 10)
console.log(num1 === num2); // false (类型不同,number vs string) – 推荐用这个!
console.log(num1 != num2); // false
console.log(num1 !== num2); // true – 推荐用这个!
console.log(num1 < num3); // true
console.log(num1 >= 10); // true
“`
重要: 始终优先使用严格等于 ===
和严格不等于 !==
来进行比较,这可以避免因隐式类型转换带来的潜在问题,让代码更可预测。
4.4 逻辑运算符 (Logical Operators)
用于组合多个布尔表达式。
&&
: 逻辑与 (AND) – 左右两边都为true
时,结果才为true
。||
: 逻辑或 (OR) – 左右两边只要有一个为true
时,结果就为true
。!
: 逻辑非 (NOT) – 将true
变为false
,false
变为true
。
“`javascript
let isAdult = true;
let hasLicense = false;
console.log(isAdult && hasLicense); // false (必须都为 true)
console.log(isAdult || hasLicense); // true (只要有一个为 true)
console.log(!isAdult); // false (取反)
console.log(!hasLicense); // true (取反)
// 短路求值 (Short-circuiting):
// &&: 如果左边为 false,则不再计算右边
// ||: 如果左边为 true,则不再计算右边
let result1 = false && (console.log(“这不会执行”));
let result2 = true || (console.log(“这也不会执行”));
“`
4.5 三元运算符 (Ternary Operator)
是 if...else
语句的简洁形式。
语法:condition ? value_if_true : value_if_false
“`javascript
let age = 20;
let status = (age >= 18) ? “成年人” : “未成年人”;
console.log(status); // 输出: 成年人
let score = 75;
let grade = (score >= 90) ? “A” : (score >= 60) ? “B” : “C”;
console.log(grade); // 输出: B
“`
第五章:控制流程 – 决定代码的执行路径
控制流程语句用于根据条件或重复执行某段代码。
5.1 条件语句 (Conditional Statements)
-
if
语句: 如果条件为true
,则执行代码块。javascript
let temperature = 25;
if (temperature > 30) {
console.log("天气炎热!");
} -
if...else
语句: 如果条件为true
,执行if
块;否则,执行else
块。javascript
let hour = 14;
if (hour < 12) {
console.log("上午好!");
} else {
console.log("下午或晚上好!");
} -
if...else if...else
语句: 检查多个条件。javascript
let grade = 85;
if (grade >= 90) {
console.log("优秀 (A)");
} else if (grade >= 80) {
console.log("良好 (B)"); // 这个会执行
} else if (grade >= 60) {
console.log("及格 (C)");
} else {
console.log("不及格 (D)");
} -
switch
语句: 基于一个表达式的值,执行多个可能匹配的代码块。通常用于替代多个if...else if
判断同一个变量的情况。“`javascript
let day = new Date().getDay(); // 获取今天是星期几 (0=周日, 1=周一, …)
let dayName;switch (day) {
case 0:
dayName = “星期日”;
break; // break 语句用于跳出 switch,否则会继续执行下一个 case
case 1:
dayName = “星期一”;
break;
case 2:
dayName = “星期二”;
break;
case 3:
dayName = “星期三”;
break;
case 4:
dayName = “星期四”;
break;
case 5:
dayName = “星期五”;
break;
case 6:
dayName = “星期六”;
break;
default: // 如果没有任何 case 匹配,则执行 default
dayName = “未知”;
}
console.log(今天是${dayName}
);
“`注意
break
的重要性! 如果省略break
,代码会从匹配的case
开始,一直执行下去,直到遇到break
或switch
结束,这通常不是我们想要的结果(称为“穿透” fall-through)。
5.2 循环语句 (Looping Statements)
用于重复执行一段代码。
-
for
循环: 最常用的循环,适用于已知循环次数的情况。
语法:for (初始化; 条件; 迭代表达式)
javascript
// 打印 0 到 4
for (let i = 0; i < 5; i++) {
// i = 0, 条件 0 < 5 为 true, 执行代码块, i++ (i 变为 1)
// i = 1, 条件 1 < 5 为 true, 执行代码块, i++ (i 变为 2)
// ...
// i = 4, 条件 4 < 5 为 true, 执行代码块, i++ (i 变为 5)
// i = 5, 条件 5 < 5 为 false, 循环结束
console.log("当前数字是: " + i);
} -
while
循环: 当条件为true
时,持续执行代码块。适用于不知道具体循环次数,但知道循环结束条件的情况。javascript
let count = 0;
while (count < 3) {
console.log("While 循环计数: " + count);
count++; // 必须在循环体内改变条件变量,否则可能导致死循环!
} -
do...while
循环: 与while
类似,但它至少会执行一次代码块,然后再检查条件。javascript
let num = 5;
do {
console.log("Do...while 执行了一次,num 是: " + num);
num++;
} while (num < 5); // 即使条件初始为 false (5 < 5 是 false),代码块也执行了一次 -
for...in
循环 (用于遍历对象属性):javascript
const user = { name: "Eve", age: 28, city: "London" };
for (let key in user) {
// key 是对象的属性名 (字符串)
console.log(`${key}: ${user[key]}`); // 注意这里用方括号访问属性
}
// 输出:
// name: Eve
// age: 28
// city: London -
for...of
循环 (ES6 – 用于遍历可迭代对象,如数组、字符串): 这是遍历数组等更常用的方式。“`javascript
const colors = [“red”, “green”, “blue”];
for (let color of colors) {
// color 是数组中的每个元素值
console.log(color);
}
// 输出:
// red
// green
// blueconst text = “Hello”;
for (let char of text) {
// char 是字符串中的每个字符
console.log(char);
}
// 输出:
// H
// e
// l
// l
// o
“`
break
和 continue
:
break
: 完全跳出当前循环。continue
: 跳过当前这次循环的剩余代码,直接进入下一次迭代。
javascript
for (let i = 0; i < 10; i++) {
if (i === 3) {
continue; // 当 i 等于 3 时,跳过 console.log(i),进入下一次循环 (i 变成 4)
}
if (i === 7) {
break; // 当 i 等于 7 时,完全跳出 for 循环
}
console.log("循环数字: " + i); // 会打印 0, 1, 2, 4, 5, 6
}
第六章:函数 – 代码的复用与组织
函数是一段可以被重复调用(执行)的代码块。它们是组织和构建复杂程序的基本单元。
6.1 函数声明 (Function Declaration)
``javascript
你好, ${name}!`);
// 定义一个名为 greet 的函数
function greet(name) { // name 是参数 (parameter)
console.log(
}
// 调用函数
greet(“张三”); // “张三” 是参数 (argument)
greet(“李四”);
“`
6.2 函数表达式 (Function Expression)
将一个匿名函数(没有名字的函数)赋值给一个变量。
“`javascript
const add = function(a, b) {
return a + b; // return 语句用于返回函数的结果
};
let sum = add(5, 3); // 调用函数并将返回值赋给 sum
console.log(sum); // 输出: 8
“`
函数声明 vs 函数表达式: 主要区别在于提升 (Hoisting)。函数声明会被提升到其作用域的顶部,意味着你可以在声明之前调用它。而函数表达式(用 let
或 const
声明)不会被提升,必须在声明之后才能调用。通常建议将函数声明放在调用之前,以保持代码清晰。
6.3 箭头函数 (Arrow Functions – ES6)
提供了一种更简洁的函数写法,尤其适用于简单的函数和回调函数。
“`javascript
// 传统函数表达式
const multiply = function(a, b) {
return a * b;
};
// 箭头函数 (基本形式)
const multiplyArrow = (a, b) => {
return a * b;
};
// 如果函数体只有一条 return 语句,可以省略 {} 和 return
const subtract = (a, b) => a – b;
// 如果只有一个参数,可以省略参数的 ()
const square = x => x * x;
// 如果没有参数,需要写一对空 ()
const sayHi = () => console.log(“Hi!”);
console.log(multiplyArrow(4, 5)); // 20
console.log(subtract(10, 4)); // 6
console.log(square(9)); // 81
sayHi(); // Hi!
“`
箭头函数还有一个重要的特性:它们不绑定自己的 this
值,this
的值继承自外围作用域。这在处理事件监听器和回调函数时非常有用,但对于初学者,可以暂时不必深入 this
的复杂性。
6.4 参数与返回值
- 参数 (Parameters): 函数定义时列出的变量名,用于接收传入的数据。
- 参数 (Arguments): 调用函数时实际传入的值。
return
语句: 指定函数执行后返回的值。如果函数没有return
语句,或者return
后面没有值,它会默认返回undefined
。一个函数只能有一个return
语句被执行(一旦执行return
,函数就结束了)。
“`javascript
function checkAge(age) {
if (age >= 18) {
return “允许访问”; // 如果满足条件,返回字符串并结束函数
} else {
return “禁止访问”; // 否则,返回这个字符串并结束函数
}
console.log(“这行代码永远不会执行”);
}
let accessStatus = checkAge(20);
console.log(accessStatus); // 输出: 允许访问
let accessStatus2 = checkAge(15);
console.log(accessStatus2); // 输出: 禁止访问
function noReturnValue() {
console.log(“这个函数没有返回值”);
}
let result = noReturnValue();
console.log(result); // 输出: undefined
“`
6.5 作用域 (Scope)
作用域决定了变量和函数的可访问性(在哪里可以被使用)。
- 全局作用域 (Global Scope): 在所有函数外部声明的变量拥有全局作用域,可以在代码的任何地方被访问。应尽量避免过多使用全局变量,以防命名冲突和难以追踪的 bug。
- 局部作用域 (Local Scope / Function Scope): 在函数内部声明的变量(使用
let
,const
,var
)拥有局部作用域,只能在该函数内部访问。 - 块级作用域 (Block Scope – ES6): 使用
let
和const
在代码块(如if
语句、for
循环的{}
)内声明的变量,只在该代码块内部可访问。var
不具有块级作用域。
“`javascript
let globalVar = “我是全局变量”; // 全局作用域
function myFunction() {
let localVar = “我是局部变量”; // 局部作用域
console.log(globalVar); // 可以访问全局变量
console.log(localVar); // 可以访问局部变量
if (true) {
let blockVar = "我是块级作用域变量 (let)"; // 块级作用域
const blockConst = "我也是块级作用域 (const)";
var functionScopedVar = "我是函数作用域变量 (var)"; // var 没有块级作用域
console.log(blockVar);
console.log(blockConst);
}
// console.log(blockVar); // 错误!在块外部无法访问 blockVar
// console.log(blockConst); // 错误!
console.log(functionScopedVar); // 可以访问,因为 var 是函数作用域
}
myFunction();
console.log(globalVar); // 可以访问全局变量
// console.log(localVar); // 错误!在函数外部无法访问局部变量
// console.log(functionScopedVar); // 错误!
“`
理解作用域对于避免变量冲突和编写健壮的代码至关重要。优先使用 let
和 const
来利用块级作用域。
第七章:数据结构:数组与对象 – 组织你的数据
7.1 数组 (Arrays)
数组是有序的值的列表。数组中的每个值称为一个元素,每个元素都有一个从 0 开始的索引 (index)。
“`javascript
// 创建数组 (字面量语法 – 推荐)
let fruits = [“苹果”, “香蕉”, “橙子”];
let numbers = [1, 2, 3, 4, 5];
let mixed = [“文本”, 100, true, null, { name: “对象” }]; // 可以包含不同类型的数据
// 访问数组元素 (通过索引)
console.log(fruits[0]); // 输出: 苹果 (第一个元素的索引是 0)
console.log(fruits[1]); // 输出: 香蕉
console.log(fruits[2]); // 输出: 橙子
console.log(fruits[3]); // 输出: undefined (索引超出范围)
// 修改数组元素
fruits[1] = “芒果”;
console.log(fruits); // 输出: [“苹果”, “芒果”, “橙子”]
// 获取数组长度 (元素个数)
console.log(fruits.length); // 输出: 3
// 常用数组方法 (方法是可以在对象/数组上执行的函数)
fruits.push(“草莓”); // 在末尾添加元素
console.log(fruits); // 输出: [“苹果”, “芒果”, “橙子”, “草莓”]
console.log(fruits.length); // 输出: 4
let removedFruit = fruits.pop(); // 移除并返回末尾的元素
console.log(removedFruit); // 输出: 草莓
console.log(fruits); // 输出: [“苹果”, “芒果”, “橙子”]
fruits.unshift(“西瓜”); // 在开头添加元素
console.log(fruits); // 输出: [“西瓜”, “苹果”, “芒果”, “橙子”]
let shiftedFruit = fruits.shift(); // 移除并返回开头的元素
console.log(shiftedFruit); // 输出: 西瓜
console.log(fruits); // 输出: [“苹果”, “芒果”, “橙子”]
console.log(fruits.indexOf(“芒果”)); // 查找元素的索引,输出: 1
console.log(fruits.indexOf(“葡萄”)); // 找不到,返回 -1
// 使用 for…of 遍历数组
for (let fruit of fruits) {
console.log(我喜欢吃 ${fruit}
);
}
// 使用 forEach 方法遍历数组 (接收一个回调函数)
fruits.forEach(function(fruit, index) {
console.log(索引 ${index}: ${fruit}
);
});
// 使用箭头函数更简洁
fruits.forEach((fruit, index) => console.log(索引 ${index}: ${fruit}
));
“`
数组还有很多其他强大的方法,如 slice
, splice
, map
, filter
, reduce
等,这些可以在后续学习中深入探索。
7.2 对象 (Objects) – 再深入
对象是无序的键值对 (key-value pair) 的集合。键 (key) 通常是字符串(或者 Symbol),值 (value) 可以是任何数据类型。
“`javascript
// 创建对象 (字面量语法 – 推荐)
let car = {
make: “Toyota”,
model: “Camry”,
year: 2022,
color: “red”,
isRunning: false,
start: function() { // 对象的方法
this.isRunning = true; // this 指向当前对象 (car)
console.log(“引擎启动!”);
},
stop: function() {
this.isRunning = false;
console.log(“引擎关闭!”);
},
// 键也可以用引号包裹,特别是包含特殊字符或空格时
“fuel type”: “Gasoline”
};
// 访问属性
console.log(car.make); // 点表示法
console.log(car[“model”]); // 方括号表示法 (键是字符串)
console.log(car[“fuel type”]); // 访问带特殊字符的键,必须用方括号
// 修改属性
car.color = “blue”;
console.log(car.color); // 输出: blue
// 添加新属性
car.owner = “Alice”;
console.log(car.owner); // 输出: Alice
// 调用方法
car.start(); // 输出: 引擎启动!
console.log(car.isRunning); // 输出: true
car.stop(); // 输出: 引擎关闭!
console.log(car.isRunning); // 输出: false
// 使用 for…in 遍历对象属性
for (let key in car) {
// 最好检查属性是否是对象自身的,而不是继承来的
if (car.hasOwnProperty(key)) {
console.log(${key} -> ${car[key]}
);
}
}
// 输出类似 (顺序可能不同):
// make -> Toyota
// model -> Camry
// year -> 2022
// color -> blue
// isRunning -> false
// start -> function() { … }
// stop -> function() { … }
// fuel type -> Gasoline
// owner -> Alice
“`
对象是构建复杂数据结构和模拟现实世界事物的基础。
第八章:与网页交互:DOM 基础
到目前为止,我们主要在控制台打印信息。JavaScript 最强大的能力之一是操作网页内容。这是通过 DOM (Document Object Model) 实现的。
DOM 是浏览器为 HTML 文档创建的一个树状结构模型。每个 HTML 元素、属性、文本节点都对应 DOM 树中的一个节点 (node)。JavaScript 可以通过 DOM API 来访问和修改这些节点,从而改变网页的外观和内容。
8.1 选取 HTML 元素
首先,需要选中你想要操作的 HTML 元素。常用的方法有:
-
document.getElementById(id)
: 通过元素的id
属性选取,返回单个元素。ID 在一个页面中应该是唯一的。html
<h1 id="main-title">我是标题</h1>
<p id="intro">这是一段介绍文字。</p>“`javascript
const mainTitle = document.getElementById(“main-title”);
const introParagraph = document.getElementById(“intro”);console.log(mainTitle); // 输出 HTMLHeadingElement 对象
console.log(introParagraph); // 输出 HTMLParagraphElement 对象
“` -
document.querySelector(selector)
: 使用 CSS 选择器选取第一个匹配的元素。非常灵活强大。html
<div class="content">
<p>第一个段落</p>
<p class="highlight">第二个段落</p>
<button>按钮</button>
</div>“`javascript
const firstParagraph = document.querySelector(“.content p”); // 选取 .content 下的第一个 p
const highlighted = document.querySelector(“.highlight”); // 选取 class=”highlight” 的元素
const button = document.querySelector(“button”); // 选取第一个 button 元素
const titleById = document.querySelector(“#main-title”); // 也可以用 ID 选择器console.log(firstParagraph);
console.log(highlighted);
“` -
document.querySelectorAll(selector)
: 使用 CSS 选择器选取所有匹配的元素,返回一个 NodeList (类似数组的对象)。html
<ul>
<li class="item">列表项 1</li>
<li class="item">列表项 2</li>
<li>列表项 3</li>
</ul>“`javascript
const listItems = document.querySelectorAll(“li”); // 选取所有 li
const specificItems = document.querySelectorAll(“.item”); // 选取所有 class=”item” 的 liconsole.log(listItems.length); // 输出: 3
console.log(specificItems.length); // 输出: 2// NodeList 可以像数组一样使用 forEach 遍历
listItems.forEach(function(item, index) {
console.log(列表项 ${index}:
, item);
});// 也可以用 for…of 遍历
for (let item of specificItems) {
console.log(“特定项:”, item);
}
“`
8.2 修改元素内容
-
element.textContent
: 获取或设置元素的纯文本内容(忽略 HTML 标签)。javascript
const mainTitle = document.getElementById("main-title");
console.log(mainTitle.textContent); // 输出: 我是标题
mainTitle.textContent = "新的标题!"; // 修改标题文本 -
element.innerHTML
: 获取或设置元素的包含 HTML 标签的内容。注意: 直接设置innerHTML
可能存在安全风险 (XSS – Cross-Site Scripting),如果内容来自用户输入,需要谨慎处理,避免注入恶意脚本。javascript
const introParagraph = document.getElementById("intro");
introParagraph.innerHTML = "这是<strong>加粗</strong>的介绍文字。"; // 可以插入 HTML 标签
8.3 修改元素样式
可以通过元素的 style
属性来修改 CSS 样式。属性名需要使用驼峰命名法(如 backgroundColor
对应 CSS 的 background-color
)。
“`javascript
const mainTitle = document.getElementById(“main-title”);
mainTitle.style.color = “blue”; // 设置文字颜色
mainTitle.style.backgroundColor = “#eee”; // 设置背景色
mainTitle.style.padding = “10px”;
mainTitle.style.borderBottom = “2px solid darkblue”; // 设置下边框
“`
8.4 处理事件 (Event Handling)
事件是用户在网页上的操作(如点击、鼠标移动、键盘按下)或浏览器自身发生的事情(如页面加载完成)。我们可以让 JavaScript 对这些事件做出响应。
最常用的方法是 element.addEventListener(eventName, eventHandler)
:
eventName
: 事件名称(字符串),如"click"
,"mouseover"
,"keydown"
.eventHandler
: 事件发生时要执行的函数(回调函数)。
“`html
“`
“`javascript
const myButton = document.getElementById(“myButton”);
const messageArea = document.getElementById(“message”);
// 为按钮添加一个点击事件监听器
myButton.addEventListener(“click”, function() {
// 当按钮被点击时,这个函数会被执行
messageArea.textContent = “按钮被点击了! 时间:” + new Date();
myButton.style.backgroundColor = “lightgreen”;
});
// 添加鼠标悬停事件
myButton.addEventListener(“mouseover”, () => {
messageArea.textContent = “鼠标悬停在按钮上…”;
myButton.style.fontWeight = “bold”;
});
// 添加鼠标离开事件
myButton.addEventListener(“mouseout”, () => {
messageArea.textContent = “”; // 清空消息
myButton.style.fontWeight = “normal”;
myButton.style.backgroundColor = “”; // 恢复默认背景色
});
“`
现在,当你用浏览器打开包含这段 HTML 和 JS 的页面时,点击按钮、鼠标移入移出都会触发相应的 JS 代码,改变页面内容和样式!
第九章:下一步与学习资源
恭喜你!你已经完成了 JavaScript 新手入门的核心内容。你现在应该对 JavaScript 的基本概念、语法和如何在网页中使用它有了初步的了解。
接下来该学什么?
- 深入 DOM 操作: 学习如何创建、添加、删除 HTML 元素,处理更复杂的事件(如表单提交、键盘事件),操作元素的属性和类 (classList)。
- 异步 JavaScript: 理解 JavaScript 的单线程和事件循环机制,学习处理耗时操作(如从服务器获取数据)的方法:回调函数、Promises、
async/await
(现代推荐)。 - 错误处理: 使用
try...catch
语句优雅地处理代码中可能出现的错误。 - ES6+ 新特性: 深入学习 ES6 及之后版本引入的更多特性,如解构赋值、扩展运算符、模块化 (import/export) 等,它们能让你的代码更简洁、更强大。
- 数据请求 (AJAX/Fetch): 学习如何使用 Fetch API 或 XMLHttpRequest (旧) 从服务器异步获取数据。
- 面向对象编程 (OOP) 深入: 学习 JavaScript 的原型链、类 (ES6 class 语法糖)、继承等。
- 实践!实践!实践! 理论学习后,最重要的就是动手编写代码。尝试做一些小项目:待办事项列表、简单的计算器、图片库、简单的表单验证等。
推荐学习资源:
- MDN Web Docs (Mozilla Developer Network): 最权威、最全面的 Web 技术文档,包括详尽的 JavaScript 参考。当你对某个概念或方法不确定时,首先查阅 MDN。(https://developer.mozilla.org/zh-CN/docs/Web/JavaScript)
- freeCodeCamp: 提供免费的交互式编程课程,包含大量的 JavaScript 练习和项目。(https://www.freecodecamp.org/)
- JavaScript.info: 一个现代化的、内容非常深入的 JavaScript 教程网站。(https://javascript.info/)
- W3Schools: 提供简洁的入门教程和在线实例。(内容可能不如 MDN 严谨,但适合快速查找)(https://www.w3schools.com/js/)
- 书籍: 《JavaScript 高级程序设计》(红宝书)、《你不知道的 JavaScript》系列等经典书籍。
结语
学习编程是一个持续的过程,尤其是像 JavaScript 这样快速发展的语言。不要害怕犯错,错误是学习过程中宝贵的一部分。多动手实践,多查阅文档,多思考,多向社区提问。
希望这篇详尽的入门教程能为你打开 JavaScript 的大门,并激发你继续探索 Web 开发的兴趣。祝你编程愉快!