1. PHP简述

详细解释

PHP(Hypertext Preprocessor,超文本预处理器)是一种通用开源脚本语言,主要用于Web开发。它最初被设计为服务器端脚本语言,现在已发展成为一种通用编程语言。

核心特点:

  • 开源免费:PHP是完全开源的,可以自由使用和修改
  • 跨平台:可以在Windows、Linux、macOS等操作系统上运行
  • 嵌入HTML:PHP代码可以嵌入到HTML中,便于Web开发
  • 服务器端执行:PHP代码在服务器上执行,结果以纯HTML形式返回给浏览器
  • 丰富的库:PHP拥有超过1000个内置函数,支持各种功能

PHP在Web开发中的角色:

  • 生成动态网页内容
  • 处理表单数据
  • 与数据库交互
  • 创建会话和Cookie
  • 生成图像和PDF
  • 与其他系统通信

PHP与Java/JavaScript的区别:

  • PHP是服务器端语言,Java可以是客户端也可以是服务器端
  • Java与JavaScript没有关系,只是名字相似
  • PHP执行在服务器上,JavaScript执行在客户端

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php
// PHP基本示例
echo "Hello, World!";

// 生成动态内容
$greeting = "Welcome to our website!";
$date = date("Y-m-d H:i:s");

echo "<h1>$greeting</h1>";
echo "<p>Current time: $date</p>";

// 表单处理示例
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$name = $_POST["name"] ?? "Guest";
echo "<p>Hello, $name! Your form was submitted successfully.</p>";
}
?>

<!DOCTYPE html>
<html>
<head>
<title>PHP Basic Example</title>
</head>
<body>
<h2>Simple Form</h2>
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>">
<label for="name">Name:</label>
<input type="text" name="name" id="name">
<input type="submit" value="Submit">
</form>

<h3>Current Server Time</h3>
<?php echo date("Y-m-d H:i:s"); ?>
</body>
</html>

2. 基本语法格式

详细解释

PHP脚本以<?php开始,以?>结束。PHP代码可以嵌入到HTML中。

语法特点:

  • 标记:PHP代码需要放在特定的标记中
  • 注释:支持单行和多行注释
  • 变量:以$符号开头,后面跟着变量名
  • 语句:以分号;结束

PHP标记类型:

  • <?php ... ?>:标准标记(推荐)
  • <? ... ?>:短标记(需要在php.ini中启用short_open_tag)
  • <% ... %>:ASP风格标记(不推荐)
  • <script language="php"> ... </script>:脚本标记(不推荐)

变量命名规则:

  • 变量名必须以字母或下划线开头
  • 变量名可以包含字母、数字和下划线
  • 变量名区分大小写
  • 变量名不能包含空格

注释类型:

  • //:单行注释
  • #:单行注释(Unix风格)
  • /* ... */:多行注释

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php
// 标准PHP标记
echo "This is a standard PHP tag";

// 短标记(需要启用short_open_tag)
// <? echo "This is a short tag"; ?>

// 单行注释
echo "This is not a comment"; // This is a comment

# Another single-line comment

/*
* Multi-line comment
* This is line 2
* This is line 3
*/

// 变量声明
$myVariable = "Hello";
$number = 10;
$boolean = true;
$nullValue = null;

// 变量命名示例
$firstName = "John";
$last_name = "Doe";
$_private = "This is a private variable";
// $1stName = "Invalid"; // 以数字开头的变量名是无效的

// 语句以分号结束
$var1 = "Value 1";
$var2 = "Value 2";

// 混合HTML和PHP
?>
<h1><?php echo "Welcome to PHP"; ?></h1>
<p>This is HTML with PHP inside.</p>

<?php
// 代码块
if (true) {
echo "This is inside a code block";
}
?>

3. 数据类型、常量以及字符串

详细解释

PHP是一种弱类型语言,变量不需要显式声明类型,PHP会根据上下文自动确定类型。

PHP数据类型:

  • 标量类型boolean, integer, float, string
  • 复合类型array, object, callable, iterable
  • 特殊类型resource, null

常量:

  • 常量在定义后不可更改
  • 常量名通常大写
  • 常量名不需要$前缀
  • 常量可以是任何标量类型

字符串:

  • PHP支持单引号和双引号字符串
  • 双引号字符串会解析变量
  • 单引号字符串不会解析变量
  • 支持HEREDOC和NOWDOC语法

3.1 基本数据类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php
// 布尔类型
$isTrue = true;
$isFalse = false;
var_dump($isTrue); // bool(true)
var_dump($isFalse); // bool(false)

// 整型
$int1 = 123; // 十进制
$int2 = 0123; // 八进制 (1*64 + 2*8 + 3 = 83)
$int3 = 0x1A; // 十六进制 (1*16 + 10 = 26)
$int4 = 0b101; // 二进制 (1*4 + 0*2 + 1 = 5)
var_dump($int1, $int2, $int3, $int4);

// 浮点型
$float1 = 3.14;
$float2 = 2.4e3; // 科学计数法 (2.4 * 10^3 = 2400)
var_dump($float1, $float2);

// 字符串
$string1 = 'This is a string';
$string2 = "This is a string with $float1";
$string3 = "This is a string with {$float1}"; // 使用花括号明确变量边界
var_dump($string1, $string2, $string3);

// NULL
$nullValue = null;
var_dump($nullValue); // NULL

// 数组
$array = array(1, 2, 3);
var_dump($array);

// 对象
class Person {
public $name;
}
$person = new Person();
$person->name = "John";
var_dump($person);

// 资源
$resource = fopen("example.txt", "r");
var_dump($resource);
fclose($resource);

3.2 常量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
// 定义常量
define("PI", 3.14159);
define("APP_NAME", "My Awesome App", true); // 第三个参数表示是否大小写不敏感

// 使用常量
echo "The value of PI is " . PI . "\n";
echo "App name: " . APP_NAME . "\n";

// 大小写敏感性
// echo app_name; // 如果第三个参数为false,这会报错
echo app_name; // 如果第三个参数为true,这会输出 "My Awesome App"

// 预定义常量
echo "Current file: " . __FILE__ . "\n";
echo "Current line: " . __LINE__ . "\n";
echo "PHP version: " . PHP_VERSION . "\n";
echo "OS: " . PHP_OS . "\n";

// 动态常量
$constantName = "PI";
echo "Value of $constantName: " . constant($constantName) . "\n";

3.3 字符串操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?php
// 字符串操作
$str1 = "Hello";
$str2 = "World";
$concat = $str1 . " " . $str2; // 字符串连接
echo "Concatenated: " . $concat . "\n";

// 字符串长度
echo "Length of '$concat': " . strlen($concat) . "\n";

// 字符串查找
$position = strpos($concat, "World");
echo "Position of 'World': " . $position . "\n";

// 字符串替换
$replaced = str_replace("World", "PHP", $concat);
echo "Replaced: " . $replaced . "\n";

// 字符串截取
$substring = substr($replaced, 0, 5);
echo "Substring: " . $substring . "\n";

// 字符串大小写转换
echo "Uppercase: " . strtoupper($replaced) . "\n";
echo "Lowercase: " . strtolower($replaced) . "\n";

// 字符串分割
$words = explode(" ", $replaced);
echo "Words: ";
print_r($words);

// 字符串格式化
$price = 19.99;
$formatted = sprintf("Price: $%.2f", $price);
echo "Formatted price: " . $formatted . "\n";

// HEREDOC语法
$heredoc = <<<EOT
This is a heredoc string.
It can span multiple lines.
Variables like $price will be parsed.
EOT;
echo "HEREDOC: " . $heredoc . "\n";

// NOWDOC语法(不解析变量)
$nowdoc = <<<'EOT'
This is a nowdoc string.
It can span multiple lines.
Variables like $price will NOT be parsed.
EOT;
echo "NOWDOC: " . $nowdoc . "\n";

4. 运算符

详细解释

PHP支持多种运算符,用于执行各种操作。

主要运算符类型:

  • 算术运算符+, -, *, /, %, **, ++, --
  • 赋值运算符=, +=, -=, *=, /=, %=, **=
  • 比较运算符==, !=, ===, !==, >, <, >=, <=
  • 逻辑运算符&&, ||, !, and, or, xor
  • 三元运算符? :
  • 其他运算符.(字符串连接),??(空合并)

4.1 算术运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
$a = 10;
$b = 3;

// 基本算术
echo "Addition: " . ($a + $b) . "\n"; // 13
echo "Subtraction: " . ($a - $b) . "\n"; // 7
echo "Multiplication: " . ($a * $b) . "\n"; // 30
echo "Division: " . ($a / $b) . "\n"; // 3.333...
echo "Modulo: " . ($a % $b) . "\n"; // 1
echo "Exponentiation: " . ($a ** $b) . "\n"; // 1000

// 递增/递减
$c = 5;
echo "Pre-increment: " . ++$c . "\n"; // 6
echo "Post-increment: " . $c++ . "\n"; // 6 (but $c is now 7
echo "Value after post-increment: " . $c . "\n"; // 7
echo "Pre-decrement: " . --$c . "\n"; // 6
echo "Post-decrement: " . $c-- . "\n"; // 6 (but $c is now 5
echo "Value after post-decrement: " . $c . "\n"; // 5

4.2 赋值运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
$a = 10;
echo "Initial value: " . $a . "\n"; // 10

// 简单赋值
$a = 20;
echo "After simple assignment: " . $a . "\n"; // 20

// 复合赋值
$a += 5; // $a = $a + 5
echo "After +=: " . $a . "\n"; // 25

$a -= 3; // $a = $a - 3
echo "After -=: " . $a . "\n"; // 22

$a *= 2; // $a = $a * 2
echo "After *=: " . $a . "\n"; // 44

$a /= 4; // $a = $a / 4
echo "After /=: " . $a . "\n"; // 11

$a %= 3; // $a = $a % 3
echo "After %=: " . $a . "\n"; // 2

$a **= 3; // $a = $a ** 3
echo "After **=: " . $a . "\n"; // 8

4.3 比较运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
$a = 5;
$b = "5";
$c = 10;

// 相等比较
echo "5 == 5: " . ($a == $a) . "\n"; // 1 (true)
echo "5 == '5': " . ($a == $b) . "\n"; // 1 (true)
echo "5 === 5: " . ($a === $a) . "\n"; // 1 (true)
echo "5 === '5': " . ($a === $b) . "\n"; // (empty string) (false)

// 不等比较
echo "5 != 10: " . ($a != $c) . "\n"; // 1 (true)
echo "5 !== '5': " . ($a !== $b) . "\n"; // 1 (true)

// 大小比较
echo "5 < 10: " . ($a < $c) . "\n"; // 1 (true)
echo "5 > 10: " . ($a > $c) . "\n"; // (empty string) (false)
echo "5 <= 5: " . ($a <= $a) . "\n"; // 1 (true)
echo "5 >= 10: " . ($a >= $c) . "\n"; // (empty string) (false)

// 空合并运算符 (PHP 7+)
$var1 = null;
$var2 = "Default value";
echo "Value: " . ($var1 ?? $var2) . "\n"; // "Default value"
echo "Value: " . ($var2 ?? "Another default") . "\n"; // "Default value"

4.4 逻辑运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
$age = 25;
$isStudent = true;
$hasDiscount = false;

// 逻辑与
echo "Adult and student: " . ($age >= 18 && $isStudent) . "\n"; // 1 (true)
echo "Adult and not student: " . ($age >= 18 && !$isStudent) . "\n"; // (empty string) (false)

// 逻辑或
echo "Student or has discount: " . ($isStudent || $hasDiscount) . "\n"; // 1 (true)
echo "Not student and no discount: " . (!$isStudent || !$hasDiscount) . "\n"; // 1 (true)

// 逻辑非
echo "Not student: " . (!$isStudent) . "\n"; // (empty string) (false)

// 逻辑运算符优先级
echo "Complex expression: " . ($age >= 18 && $isStudent || $hasDiscount) . "\n"; // 1 (true)
echo "Complex expression with parentheses: " . ($age >= 18 && ($isStudent || $hasDiscount)) . "\n"; // 1 (true)

4.5 三元运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
$age = 25;
$isStudent = true;

// 基本三元运算符
$greeting = ($age >= 18) ? "Adult" : "Minor";
echo "Greeting: " . $greeting . "\n"; // "Adult"

// 嵌套三元运算符
$discount = ($age >= 65) ? "Senior" : ($isStudent ? "Student" : "Regular");
echo "Discount: " . $discount . "\n"; // "Student"

// 空合并运算符 (PHP 7+)
$username = null;
$displayName = $username ?? "Guest";
echo "Display name: " . $displayName . "\n"; // "Guest"

// 短路三元运算符 (PHP 7.4+)
$role = "admin";
$permission = $role === "admin" ? "Full access" : ($role === "editor" ? "Edit access" : "View only");
echo "Permission: " . $permission . "\n"; // "Full access"

5. 控制语句

详细解释

控制语句用于控制程序的执行流程。

主要控制语句:

  • 条件语句if, if...else, if...elseif...else, switch
  • 循环语句while, do...while, for, foreach
  • 流程控制语句break, continue, return, exit

5.1 条件语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?php
$score = 85;

// if语句
if ($score >= 90) {
echo "Excellent!\n";
}

// if...else语句
if ($score >= 60) {
echo "Passed!\n";
} else {
echo "Failed!\n";
}

// if...elseif...else语句
if ($score >= 90) {
echo "A - Excellent!\n";
} elseif ($score >= 80) {
echo "B - Good!\n";
} elseif ($score >= 70) {
echo "C - Satisfactory!\n";
} elseif ($score >= 60) {
echo "D - Needs improvement!\n";
} else {
echo "F - Failed!\n";
}

// switch语句
$day = date("l"); // 获取当前星期

switch ($day) {
case "Monday":
echo "Start of the work week.\n";
break;
case "Tuesday":
case "Wednesday":
case "Thursday":
echo "Midweek.\n";
break;
case "Friday":
echo "End of the work week.\n";
break;
case "Saturday":
case "Sunday":
echo "Weekend!\n";
break;
default:
echo "Unknown day.\n";
}

5.2 循环语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php
// while循环
$i = 1;
while ($i <= 5) {
echo "While loop: $i\n";
$i++;
}

// do...while循环
$j = 1;
do {
echo "Do...while loop: $j\n";
$j++;
} while ($j <= 5);

// for循环
for ($k = 1; $k <= 5; $k++) {
echo "For loop: $k\n";
}

// foreach循环(数组)
$colors = ["red", "green", "blue"];
foreach ($colors as $color) {
echo "Color: $color\n";
}

// foreach循环(关联数组)
$person = [
"name" => "John",
"age" => 30,
"city" => "New York"
];
foreach ($person as $key => $value) {
echo "Person $key: $value\n";
}

5.3 流程控制语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
// break语句
for ($i = 1; $i <= 10; $i++) {
if ($i == 5) {
break; // 退出循环
}
echo "Break example: $i\n";
}

// continue语句
for ($i = 1; $i <= 5; $i++) {
if ($i == 3) {
continue; // 跳过本次迭代
}
echo "Continue example: $i\n";
}

// return语句(在函数中)
function getGreeting($name) {
if (empty($name)) {
return "Hello, Guest!";
}
return "Hello, $name!";
}
echo getGreeting("Alice") . "\n";
echo getGreeting(" ") . "\n";

// exit语句
$shouldExit = false;
if ($shouldExit) {
echo "Exiting...\n";
exit;
}
echo "This will be printed if shouldExit is false.\n";

6. PHP数组

详细解释

PHP数组是一种有序映射,可以存储多个值。

数组类型:

  • 索引数组:数字键名
  • 关联数组:字符串键名
  • 多维数组:数组中包含数组

数组操作:

  • 创建数组
  • 添加元素
  • 删除元素
  • 遍历数组
  • 数组排序
  • 数组函数

6.1 数组的创建与操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?php
// 创建索引数组
$fruits = array("Apple", "Banana", "Cherry");
// 或
$fruits = ["Apple", "Banana", "Cherry"];

// 创建关联数组
$person = array(
"name" => "John",
"age" => 30,
"city" => "New York"
);
// 或
$person = [
"name" => "John",
"age" => 30,
"city" => "New York"
];

// 创建多维数组
$students = [
["id" => 1, "name" => "Alice", "age" => 20],
["id" => 2, "name" => "Bob", "age" => 22],
["id" => 3, "name" => "Charlie", "age" => 21]
];

// 访问数组元素
echo "First fruit: " . $fruits[0] . "\n";
echo "Person name: " . $person["name"] . "\n";
echo "Second student name: " . $students[1]["name"] . "\n";

// 修改数组元素
$fruits[1] = "Blueberry";
$person["age"] = 31;

// 添加元素
$fruits[] = "Date"; // 添加到末尾
$person["email"] = "john@example.com"; // 添加新键值对

// 删除元素
unset($fruits[0]); // 删除索引0的元素
unset($person["city"]); // 删除"city"键

// 检查元素是否存在
echo "Fruit 'Banana' exists: " . (in_array("Banana", $fruits) ? "Yes" : "No") . "\n";
echo "Key 'email' exists: " . (array_key_exists("email", $person) ? "Yes" : "No") . "\n";

// 数组长度
echo "Number of fruits: " . count($fruits) . "\n";

6.2 数组函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<?php
$numbers = [5, 3, 8, 1, 9, 4, 2, 7, 6];

// 排序函数
$sorted = $numbers;
sort($sorted); // 升序
echo "Sorted: " . implode(", ", $sorted) . "\n";

$sorted = $numbers;
rsort($sorted); // 降序
echo "Reverse sorted: " . implode(", ", $sorted) . "\n";

// 关联数组排序
$ages = [
"Alice" => 20,
"Bob" => 22,
"Charlie" => 21
];
asort($ages); // 按值排序
echo "Ages sorted by value: ";
foreach ($ages as $name => $age) {
echo "$name($age), ";
}
echo "\n";

ksort($ages); // 按键排序
echo "Ages sorted by key: ";
foreach ($ages as $name => $age) {
echo "$name($age), ";
}
echo "\n";

// 数组操作函数
$colors = ["red", "green", "blue"];
array_push($colors, "yellow"); // 添加到末尾
array_unshift($colors, "purple"); // 添加到开头
echo "After push and unshift: " . implode(", ", $colors) . "\n";

$last = array_pop($colors); // 移除末尾元素
$first = array_shift($colors); // 移除开头元素
echo "After pop and shift: " . implode(", ", $colors) . "\n";

// 数组切片
$subset = array_slice($colors, 1, 2); // 从索引1开始,取2个元素
echo "Array slice: " . implode(", ", $subset) . "\n";

// 数组映射
$squared = array_map(function($n) { return $n * $n; }, $numbers);
echo "Squared numbers: " . implode(", ", $squared) . "\n";

// 数组过滤
$even = array_filter($numbers, function($n) { return $n % 2 == 0; });
echo "Even numbers: " . implode(", ", $even) . "\n";

// 数组合并
$colors1 = ["red", "green"];
$colors2 = ["blue", "yellow"];
$allColors = array_merge($colors1, $colors2);
echo "Merged colors: " . implode(", ", $allColors) . "\n";

7. PHP 函数

详细解释

函数是可重用的代码块,用于执行特定任务。

函数特点:

  • 可以接受参数
  • 可以返回值
  • 可以有默认参数
  • 可以有类型声明(PHP 7+)
  • 支持可变参数(PHP 5.6+)

函数类型:

  • 用户定义函数:开发者创建的函数
  • 内置函数:PHP自带的函数
  • 匿名函数:没有名称的函数

7.1 函数定义与调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?php
// 基本函数
function greet($name) {
return "Hello, $name!";
}
echo greet("Alice") . "\n";

// 带默认参数的函数
function sayHello($name = "Guest") {
return "Hello, $name!";
}
echo sayHello() . "\n";
echo sayHello("Bob") . "\n";

// 返回多个值(通过数组)
function getPerson() {
return [
"name" => "Charlie",
"age" => 30,
"city" => "London"
];
}
$person = getPerson();
echo "Person name: " . $person["name"] . "\n";

// 类型声明(PHP 7+)
function add(int $a, int $b): int {
return $a + $b;
}
echo "5 + 3 = " . add(5, 3) . "\n";

// 可变参数(PHP 5.6+)
function sum(...$numbers) {
return array_sum($numbers);
}
echo "Sum: " . sum(1, 2, 3, 4, 5) . "\n";

// 匿名函数
$greet = function($name) {
return "Hi, $name!";
};
echo $greet("Dave") . "\n";

// 闭包(访问外部变量)
$prefix = "Welcome";
$greetWithPrefix = function($name) use ($prefix) {
return "$prefix, $name!";
};
echo $greetWithPrefix("Eve") . "\n";

7.2 函数高级特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
// 递归函数
function factorial($n) {
if ($n <= 1) {
return 1;
}
return $n * factorial($n - 1);
}
echo "Factorial of 5: " . factorial(5) . "\n";

// 生成器(PHP 5.5+)
function rangeGenerator($start, $end) {
for ($i = $start; $i <= $end; $i++) {
yield $i;
}
}
foreach (rangeGenerator(1, 5) as $number) {
echo "Number: $number\n";
}

// 通过引用传递参数
function increment(&$value) {
$value++;
}
$counter = 10;
increment($counter);
echo "Counter after increment: $counter\n";

// 函数作为参数
function apply($value, callable $callback) {
return $callback($value);
}
$squared = apply(5, function($n) { return $n * $n; });
echo "5 squared: $squared\n";

8. PHP 变量作用域

详细解释

变量作用域决定了变量在哪些部分可以被访问。

主要作用域:

  • 局部作用域:在函数内部声明的变量
  • 全局作用域:在函数外部声明的变量
  • 静态作用域:使用static关键字声明的变量

变量作用域特点:

  • 局部变量在函数执行完毕后销毁
  • 全局变量在脚本执行期间一直存在
  • 静态变量在函数执行完毕后保留其值

8.1 局部变量与全局变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
// 全局变量
$globalVar = "I'm global";

function testScope() {
// 局部变量
$localVar = "I'm local";

// 访问全局变量
global $globalVar;
echo "Global variable: $globalVar\n";

// 修改全局变量
$globalVar = "Modified global";

// 尝试访问外部变量(会报错)
// echo $externalVar;
}

// 调用函数
testScope();

// 检查全局变量是否被修改
echo "Global variable after function: $globalVar\n";

// 尝试访问局部变量(会报错)
// echo $localVar;

8.2 使用$GLOBAL数组

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
$globalVar = "Original global value";

function testGlobalArray() {
// 使用$GLOBAL数组访问全局变量
$GLOBALS['globalVar'] = "Modified global value";
}

// 调用函数
testGlobalArray();

// 检查全局变量是否被修改
echo "Global variable: " . $globalVar . "\n";

8.3 静态变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php
function counter() {
// 静态变量,函数执行后保留其值
static $count = 0;
$count++;
return $count;
}

echo "Counter 1: " . counter() . "\n"; // 1
echo "Counter 2: " . counter() . "\n"; // 2
echo "Counter 3: " . counter() . "\n"; // 3

// 静态变量在函数外部不可访问
// echo $count; // 会报错

// 静态变量示例:缓存计算结果
function fibonacci($n) {
static $cache = [];

if (isset($cache[$n])) {
return $cache[$n];
}

if ($n <= 1) {
$result = $n;
} else {
$result = fibonacci($n - 1) + fibonacci($n - 2);
}

$cache[$n] = $result;
return $result;
}

echo "Fibonacci(10): " . fibonacci(10) . "\n"; // 55
echo "Fibonacci(20): " . fibonacci(20) . "\n"; // 6765

9. 类与对象

详细解释

PHP支持面向对象编程(OOP),允许开发者创建类和对象。

核心概念:

  • :对象的蓝图或模板
  • 对象:类的实例
  • 属性:类的变量
  • 方法:类的函数
  • 构造函数:对象创建时自动调用的方法
  • 析构函数:对象销毁时自动调用的方法
  • 继承:子类继承父类的属性和方法
  • 多态:同一方法在不同对象中有不同实现
  • 静态成员:属于类而非对象的成员
  • 静态方法:可以直接通过类名调用的方法

访问控制:

  • public:任何地方都可以访问
  • protected:类内部和子类可以访问
  • private:仅类内部可以访问
  • static:静态成员或方法,可直接通过类名访问

9.1 基本类与对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?php
class Person {
// 属性
public $name;
public $age;
// 静态成员变量
public static $count = 0;

// 构造函数
public function __construct($name, $age) {
$this->name = $name;
$this->age = $age;
// 每创建一个对象,静态计数器增加
self::$count++;
}

// 方法
public function greet() {
return "Hello, my name is " . $this->name . " and I am " . $this->age . " years old.";
}

// 静态方法
public static function createDefault() {
return new Person("Anonymous", 0);
}

// 静态方法访问静态成员
public static function getCount() {
return "Total persons created: " . self::$count;
}
}

// 创建对象
$person1 = new Person("Alice", 25);
echo $person1->greet() . "\n";

// 访问静态成员
echo Person::$count . "\n"; // 1

// 使用静态方法
$person2 = Person::createDefault();
echo $person2->greet() . "\n";

// 调用静态方法
echo Person::getCount() . "\n"; // Total persons created: 2

// 访问属性
echo "Name: " . $person1->name . "\n";

// 检查对象类型
echo "Is Person: " . (is_a($person1, 'Person') ? "Yes" : "No") . "\n";

9.2 继承与多态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<?php
abstract class Animal {
protected $name;
protected $species;
// 静态成员变量
protected static $animalCount = 0;

public function __construct(string $name, string $species) {
$this->name = $name;
$this->species = $species;
// 每创建一个动物,静态计数器增加
self::$animalCount++;
}

public function getName(): string {
return $this->name;
}

public function getSpecies(): string {
return $this->species;
}

// 静态方法:获取动物总数
public static function getAnimalCount(): int {
return self::$animalCount;
}

// 抽象方法
abstract public function makeSound(): string;

// 多态核心:不同动物移动方式不同
abstract public function move(): string;

// 公共行为(所有动物共享)
public function introduce(): string {
return "I'm {$this->name}, a {$this->species}.";
}
}

class Dog extends Animal {
public function __construct(string $name) {
parent::__construct($name, "Dog");
}

// 实现抽象方法
public function makeSound(): string {
return "Woof! Woof!";
}

// 实现抽象方法
public function move(): string {
return "runs on four legs";
}

// 子类特有行为
public function fetch(string $item): string {
return "{$this->name} is fetching the {$item}!";
}
}

class Cat extends Animal {
public function __construct(string $name) {
parent::__construct($name, "Cat");
}

public function makeSound(): string {
return "Meow! Meow!";
}

public function move(): string {
return "sneaks silently";
}

public function scratch(string $surface): string {
return "{$this->name} is scratching the {$surface}!";
}
}

class Bird extends Animal {
public function __construct(string $name) {
parent::__construct($name, "Bird");
}

public function makeSound(): string {
return "Chirp! Chirp!";
}

public function move(): string {
return "flies through the air";
}

public function layEggs(int $count): string {
return "{$this->name} laid {$count} eggs.";
}
}

// 多态函数:接受任何Animal子类
function observeAnimal(Animal $animal): void {
echo $animal->introduce() . "\n";
echo " - Sound: " . $animal->makeSound() . "\n";
echo " - Movement: " . $animal->move() . "\n";

// 类型检测:安全调用子类特有方法
if ($animal instanceof Dog) {
echo " - Special: " . $animal->fetch("ball") . "\n";
} else if ($animal instanceof Cat) {
echo " - Special: " . $animal->scratch("couch") . "\n";
} else if ($animal instanceof Bird) {
echo " - Special: " . $animal->layEggs(3) . "\n";
}

echo "------------------------\n";
}

// 创建不同动物
$animals = [
new Dog("Buddy"),
new Cat("Whiskers"),
new Bird("Tweety")
];

// 统一处理所有动物
foreach ($animals as $animal) {
observeAnimal($animal);
}

// 使用静态方法获取动物总数
echo "Total animals created: " . Animal::getAnimalCount() . "\n";

9.3 接口与抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
<?php
// 接口
interface Shape {
public function getArea();
public function getPerimeter();
}

// 抽象类
abstract class GeometricShape implements Shape {
protected $color;
// 静态成员变量
protected static $shapeCount = 0;

public function __construct($color) {
$this->color = $color;
// 每创建一个形状,静态计数器增加
self::$shapeCount++;
}

public function getColor() {
return $this->color;
}

// 静态方法
public static function getShapeCount() {
return self::$shapeCount;
}

// 抽象方法
abstract public function getArea();
abstract public function getPerimeter();
}

// 具体实现
class Circle extends GeometricShape {
private $radius;

public function __construct($color, $radius) {
parent::__construct($color);
$this->radius = $radius;
}

public function getArea() {
return pi() * $this->radius * $this->radius;
}

public function getPerimeter() {
return 2 * pi() * $this->radius;
}
}

class Rectangle extends GeometricShape {
private $width;
private $height;

public function __construct($color, $width, $height) {
parent::__construct($color);
$this->width = $width;
$this->height = $height;
}

public function getArea() {
return $this->width * $this->height;
}

public function getPerimeter() {
return 2 * ($this->width + $this->height);
}
}

// 使用接口
function printShapeInfo(Shape $shape) {
echo "Shape info:\n";
echo "- Area: " . $shape->getArea() . "\n";
echo "- Perimeter: " . $shape->getPerimeter() . "\n";
if ($shape instanceof GeometricShape) {
echo "- Color: " . $shape->getColor() . "\n";
}
}

$circle = new Circle("red", 5);
$rectangle = new Rectangle("blue", 4, 6);

printShapeInfo($circle);
printShapeInfo($rectangle);

// 使用静态方法获取形状总数
echo "Total shapes created: " . GeometricShape::getShapeCount() . "\n";

9.4 静态方法与静态属性详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<?php
class Database {
// 静态属性 - 单例模式
private static $instance = null;
private $connection;

// 私有构造函数 - 防止直接实例化
private function __construct($host, $username, $password, $database) {
$this->connection = new mysqli($host, $username, $password, $database);
}

// 静态方法 - 获取单例实例
public static function getInstance($host = 'localhost', $username = 'root', $password = '', $database = 'test') {
if (self::$instance === null) {
self::$instance = new self($host, $username, $password, $database);
}
return self::$instance;
}

// 静态方法 - 直接执行查询
public static function query($sql, $params = []) {
$instance = self::getInstance();
$stmt = $instance->connection->prepare($sql);
if ($params) {
$types = str_repeat('s', count($params));
$stmt->bind_param($types, ...$params);
}
$stmt->execute();
return $stmt->get_result();
}

// 静态实用方法
public static function sanitize($input) {
return htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
}

// 防止克隆
private function __clone() {}

// 防止反序列化
private function __wakeup() {}
}

// 使用单例模式
$db = Database::getInstance();
$results = Database::query("SELECT * FROM users WHERE name = ?", ["John"]);
while ($row = $results->fetch_assoc()) {
echo "User: " . Database::sanitize($row['name']) . "<br>";
}

// 静态实用类示例
class MathUtils {
// 静态常量
const PI = 3.14159265359;

// 静态属性
private static $instances = 0;

// 静态方法
public static function add($a, $b) {
self::$instances++;
return $a + $b;
}

public static function multiply($a, $b) {
self::$instances++;
return $a * $b;
}

public static function getInstanceCount() {
return self::$instances;
}

// 静态方法使用静态常量
public static function circleArea($radius) {
return self::PI * $radius * $radius;
}
}

// 使用静态方法
echo "2 + 3 = " . MathUtils::add(2, 3) . "<br>";
echo "4 * 5 = " . MathUtils::multiply(4, 5) . "<br>";
echo "Circle area (radius=5): " . MathUtils::circleArea(5) . "<br>";
echo "Total method calls: " . MathUtils::getInstanceCount() . "<br>";

9.5 命名空间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<?php
// 命名空间示例
namespace MyProject\Utils;

class StringHelper {
// 静态成员变量
private static $instanceCount = 0;

// 构造函数
public function __construct() {
self::$instanceCount++;
}

// 静态方法
public static function reverse($string) {
self::$instanceCount++;
return strrev($string);
}

// 静态方法访问静态成员
public static function getInstanceCount() {
return self::$instanceCount;
}
}

// 另一个命名空间
namespace MyProject\Database;

class Connection {
// 静态连接实例
private static $connection = null;

// 静态方法
public static function connect($host, $username, $password, $database) {
if (self::$connection === null) {
self::$connection = new \mysqli($host, $username, $password, $database);
}
return self::$connection;
}

// 静态方法
public static function disconnect() {
if (self::$connection !== null) {
self::$connection->close();
self::$connection = null;
}
}
}

// 使用命名空间
namespace Main;

// 导入命名空间
use MyProject\Utils\StringHelper;
use MyProject\Database\Connection as DB;

// 使用静态方法
echo StringHelper::reverse("Hello") . "\n"; // olleH
echo "StringHelper instances: " . StringHelper::getInstanceCount() . "\n"; // 1

// 创建实例会增加计数
new StringHelper();
echo "StringHelper instances: " . StringHelper::getInstanceCount() . "\n"; // 2

// 使用别名
$conn = DB::connect("localhost", "root", "password", "test_db");
echo "Database connected\n";

// 完全限定名称
echo \MyProject\Utils\StringHelper::reverse("World") . "\n"; // dlroW
echo "StringHelper instances: " . \MyProject\Utils\StringHelper::getInstanceCount() . "\n"; // 3

// 关闭数据库连接
DB::disconnect();
echo "Database disconnected\n";

10. PHP超级全局变量

详细解释

超级全局变量是PHP预定义的全局数组,可以在脚本的任何作用域中访问。

主要超级全局变量:

  • $GLOBALS:引用全局作用域中可用的全部变量
  • $_SERVER:服务器和执行环境信息
  • $_GET:HTTP GET方法传递的变量
  • $_POST:HTTP POST方法传递的变量
  • $_FILES:HTTP文件上传变量
  • $_COOKIE:HTTP Cookies
  • $_SESSION:会话变量
  • $_REQUEST:HTTP请求变量(GET, POST, COOKIE)
  • $_ENV:环境变量

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php
// $GLOBALS
$globalVar = "I'm global";
function testGlobal() {
echo $GLOBALS['globalVar'] . "\n";
}
testGlobal();

// $_SERVER
echo "Server name: " . $_SERVER['SERVER_NAME'] . "\n";
echo "Request URI: " . $_SERVER['REQUEST_URI'] . "\n";
echo "User Agent: " . $_SERVER['HTTP_USER_AGENT'] . "\n";

// $_GET
// 假设URL为: example.com/test.php?name=Alice&age=25
echo "Name from GET: " . ($_GET['name'] ?? 'Not provided') . "\n";
echo "Age from GET: " . ($_GET['age'] ?? 'Not provided') . "\n";

// $_POST
// 假设表单提交了name和email字段
if ($_SERVER["REQUEST_METHOD"] == "POST") {
echo "Name from POST: " . ($_POST['name'] ?? 'Not provided') . "\n";
echo "Email from POST: " . ($_POST['email'] ?? 'Not provided') . "\n";
}

// $_COOKIE
// 设置Cookie
setcookie("username", "Alice", time() + 3600);
echo "Username Cookie: " . ($_COOKIE['username'] ?? 'Not set') . "\n";

// $_SESSION
session_start();
$_SESSION['user'] = "Alice";
echo "User in session: " . ($_SESSION['user'] ?? 'Not set') . "\n";

// $_REQUEST
echo "Name from REQUEST: " . ($_REQUEST['name'] ?? 'Not provided') . "\n";

// $_FILES
// 用于文件上传
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_FILES["file"])) {
$file = $_FILES["file"];
echo "Uploaded file: " . $file["name"] . "\n";
echo "File type: " . $file["type"] . "\n";
}

11. PHP Include 文件

详细解释

PHP提供文件包含机制,允许将一个PHP文件的内容包含到另一个PHP文件中。

主要文件包含函数:

  • include:包含文件,如果文件不存在,产生警告,脚本继续执行
  • require:包含文件,如果文件不存在,产生致命错误,脚本终止
  • include_once:与include相同,但确保文件只被包含一次
  • require_once:与require相同,但确保文件只被包含一次

文件包含特点:

  • 可以包含任意类型的文件(.php, .html, .txt等)
  • 包含的文件会执行其中的PHP代码
  • 被包含文件可以访问包含文件的变量(根据作用域规则)

11.1 基本文件包含

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php
// header.php
?>
<header>
<h1>My Website</h1>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</nav>
</header>

<?php
// footer.php
?>
<footer>
<p>&copy; 2023 My Website. All rights reserved.</p>
</footer>

<?php
// index.php
?>
<!DOCTYPE html>
<html>
<head>
<title>My Website</title>
</head>
<body>
<?php include 'header.php'; ?>

<main>
<h2>Welcome to My Website</h2>
<p>This is the main content of the page.</p>
</main>

<?php include 'footer.php'; ?>
</body>
</html>

11.2 文件包含高级用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?php
// config.php
$databaseConfig = [
'host' => 'localhost',
'username' => 'root',
'password' => 'password',
'database' => 'myapp'
];

// functions.php
function formatCurrency($amount) {
return '$' . number_format($amount, 2);
}

// 工具类
class FileHelper {
// 静态方法
public static function getFileExtension($filename) {
return pathinfo($filename, PATHINFO_EXTENSION);
}

public static function sanitizeFilename($filename) {
return preg_replace('/[^a-zA-Z0-9\.\-_]/', '', $filename);
}
}

// main.php
// 使用require_once确保配置只加载一次
require_once 'config.php';
require_once 'functions.php';

// 使用静态方法
$filename = "document.pdf";
$extension = FileHelper::getFileExtension($filename);
$safeName = FileHelper::sanitizeFilename("report/2023!.pdf");

// 使用配置
$dsn = "mysql:host={$databaseConfig['host']};dbname={$databaseConfig['database']}";
// ...数据库连接代码...

// 使用函数
echo "Price: " . formatCurrency(19.99) . "\n";
echo "File extension: " . $extension . "\n";
echo "Sanitized filename: " . $safeName . "\n";

// 动态包含
$page = $_GET['page'] ?? 'home';
$validPages = ['home', 'about', 'contact'];

if (in_array($page, $validPages)) {
include "$page.php";
} else {
include "404.php";
}

12. PHP 文件处理

详细解释

PHP提供了一套完整的文件操作函数,用于读取、写入、创建和删除文件。

主要文件操作函数:

  • fopen():打开文件
  • fclose():关闭文件
  • fread():读取文件
  • fwrite():写入文件
  • file_get_contents():读取整个文件到字符串
  • file_put_contents():将字符串写入文件
  • file():读取文件到数组
  • file_exists():检查文件是否存在
  • is_file():检查是否为文件
  • is_dir():检查是否为目录
  • mkdir():创建目录
  • rmdir():删除目录
  • unlink():删除文件
  • rename():重命名文件或目录

12.1 基本文件操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
// 创建和写入文件
$filename = "example.txt";
$content = "Hello, World!\nThis is a test file.\n";

// 使用fopen和fwrite
$handle = fopen($filename, "w");
fwrite($handle, $content);
fclose($handle);

// 使用file_put_contents(更简单)
file_put_contents($filename, $content);

// 读取文件
$contents = file_get_contents($filename);
echo "File contents:\n$contents\n";

// 逐行读取
$lines = file($filename);
echo "Lines:\n";
foreach ($lines as $line) {
echo $line;
}

// 检查文件是否存在
if (file_exists($filename)) {
echo "File exists.\n";
}

// 获取文件信息
echo "File size: " . filesize($filename) . " bytes\n";
echo "File last modified: " . date("Y-m-d H:i:s", filemtime($filename)) . "\n";

12.2 高级文件操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
<?php
// 创建目录
$dir = "uploads";
if (!file_exists($dir)) {
mkdir($dir, 0777, true);
echo "Directory created.\n";
}

// 递归读取目录
function listFiles($dir) {
$files = [];
if ($handle = opendir($dir)) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
$path = $dir . '/' . $entry;
if (is_dir($path)) {
$files = array_merge($files, listFiles($path));
} else {
$files[] = $path;
}
}
}
closedir($handle);
}
return $files;
}

$allFiles = listFiles(".");
echo "All files:\n";
foreach ($allFiles as $file) {
echo $file . "\n";
}

// 文件复制和移动
$source = "example.txt";
$destination = "backup/example.txt";

// 创建备份目录
if (!file_exists("backup")) {
mkdir("backup");
}

// 复制文件
if (copy($source, $destination)) {
echo "File copied successfully.\n";
}

// 重命名/移动文件
$renamed = "example_backup.txt";
if (rename($source, $renamed)) {
echo "File renamed successfully.\n";
}

// 删除文件
if (file_exists($renamed)) {
unlink($renamed);
echo "File deleted.\n";
}

// 创建静态文件处理器
class FileProcessor {
private static $instance = null;
private $logFile;

private function __construct($logFile = 'file_log.txt') {
$this->logFile = $logFile;
}

public static function getInstance($logFile = 'file_log.txt') {
if (self::$instance === null) {
self::$instance = new self($logFile);
}
return self::$instance;
}

public static function createFile($filename, $content = '') {
$instance = self::getInstance();
$result = file_put_contents($filename, $content);
$instance->log("Created file: $filename");
return $result !== false;
}

public static function readFile($filename) {
$instance = self::getInstance();
if (!file_exists($filename)) {
$instance->log("File not found: $filename");
return false;
}
$instance->log("Read file: $filename");
return file_get_contents($filename);
}

private function log($message) {
$timestamp = date('Y-m-d H:i:s');
$logEntry = "[$timestamp] $message\n";
file_put_contents($this->logFile, $logEntry, FILE_APPEND);
}

private function __clone() {}
}

// 使用静态方法
FileProcessor::createFile('test.txt', 'This is a test file.');
$content = FileProcessor::readFile('test.txt');
echo $content . "\n";

13. PHP获取文件属性

详细解释

PHP提供了一系列函数来获取文件的属性信息,如大小、类型、权限等。

主要文件属性函数:

  • file_exists():检查文件是否存在
  • is_file():检查是否为文件
  • is_dir():检查是否为目录
  • is_readable():检查文件是否可读
  • is_writable():检查文件是否可写
  • fileatime():获取文件上次访问时间
  • filemtime():获取文件上次修改时间
  • filectime():获取文件创建时间
  • filesize():获取文件大小
  • filetype():获取文件类型

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
<?php
$filename = "example.txt";

// 检查文件是否存在
if (file_exists($filename)) {
echo "File exists.\n";

// 检查文件类型
echo "Is file: " . (is_file($filename) ? "Yes" : "No") . "\n";
echo "Is directory: " . (is_dir($filename) ? "Yes" : "No") . "\n";

// 检查权限
echo "Is readable: " . (is_readable($filename) ? "Yes" : "No") . "\n";
echo "Is writable: " . (is_writable($filename) ? "Yes" : "No") . "\n";

// 获取时间信息
echo "Last accessed: " . date("Y-m-d H:i:s", fileatime($filename)) . "\n";
echo "Last modified: " . date("Y-m-d H:i:s", filemtime($filename)) . "\n";
echo "File creation: " . date("Y-m-d H:i:s", filectime($filename)) . "\n";

// 获取文件大小
echo "File size: " . filesize($filename) . " bytes\n";

// 获取文件类型
echo "File type: " . filetype($filename) . "\n";

// 获取文件权限
$permissions = fileperms($filename);
echo "File permissions: " . decoct($permissions & 0777) . "\n";
} else {
echo "File does not exist.\n";
}

// 创建文件信息工具
class FileInfo {
// 静态缓存
private static $cache = [];

// 静态方法
public static function getInfo($filename) {
// 检查缓存
if (isset(self::$cache[$filename])) {
return self::$cache[$filename];
}

if (!file_exists($filename)) {
return null;
}

$info = [
'name' => basename($filename),
'path' => realpath($filename),
'size' => filesize($filename),
'type' => filetype($filename),
'mime' => mime_content_type($filename),
'readable' => is_readable($filename),
'writable' => is_writable($filename),
'created' => date("Y-m-d H:i:s", filectime($filename)),
'modified' => date("Y-m-d H:i:s", filemtime($filename)),
'accessed' => date("Y-m-d H:i:s", fileatime($filename))
];

// 缓存结果
self::$cache[$filename] = $info;
return $info;
}

// 静态方法
public static function formatSize($bytes) {
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
$i = 0;
while ($bytes >= 1024 && $i < count($units) - 1) {
$bytes /= 1024;
$i++;
}
return round($bytes, 2) . ' ' . $units[$i];
}
}

// 使用静态方法
$info = FileInfo::getInfo("example.txt");
if ($info) {
echo "File: " . $info['name'] . "\n";
echo "Size: " . FileInfo::formatSize($info['size']) . "\n";
echo "Type: " . $info['type'] . "\n";
echo "MIME: " . $info['mime'] . "\n";
echo "Last modified: " . $info['modified'] . "\n";

// 从缓存获取
$cachedInfo = FileInfo::getInfo("example.txt");
echo "Retrieved from cache: " . ($info === $cachedInfo ? "Yes" : "No") . "\n";
}

14. PHP目录操作

详细解释

PHP提供了一套完整的目录操作函数,用于创建、读取和删除目录。

主要目录操作函数:

  • opendir():打开目录句柄
  • readdir():从目录句柄中读取条目
  • closedir():关闭目录句柄
  • scandir():列出目录中的所有文件和目录
  • mkdir():创建目录
  • rmdir():删除目录
  • chdir():改变当前目录
  • getcwd():获取当前工作目录

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
<?php
// 创建目录
$dir = "example_dir";
if (!file_exists($dir)) {
mkdir($dir, 0777, true);
echo "Directory '$dir' created.\n";
}

// 列出目录内容
$files = scandir($dir);
echo "Directory contents of '$dir':\n";
foreach ($files as $file) {
if ($file != "." && $file != "..") {
echo "- $file\n";
}
}

// 递归读取目录
function recursiveScan($dir) {
$result = [];
$cdir = scandir($dir);
foreach ($cdir as $key => $value) {
if (!in_array($value, [".", ".."])) {
if (is_dir($dir . DIRECTORY_SEPARATOR . $value)) {
$result[$value] = recursiveScan($dir . DIRECTORY_SEPARATOR . $value);
} else {
$result[] = $value;
}
}
}
return $result;
}

$dirStructure = recursiveScan(".");
echo "Directory structure:\n";
print_r($dirStructure);

// 删除目录
function deleteDir($dir) {
$files = array_diff(scandir($dir), ['.', '..']);
foreach ($files as $file) {
$path = $dir . '/' . $file;
is_dir($path) ? deleteDir($path) : unlink($path);
}
return rmdir($dir);
}

// 创建测试目录结构
$testDir = "test_dir";
mkdir($testDir);
file_put_contents("$testDir/file1.txt", "Content 1");
mkdir("$testDir/subdir");
file_put_contents("$testDir/subdir/file2.txt", "Content 2");

// 删除测试目录
if (file_exists($testDir)) {
deleteDir($testDir);
echo "Test directory deleted.\n";
}

// 目录操作工具类
class DirectoryManager {
// 静态缓存
private static $cache = [];

// 单例实例
private static $instance = null;

private function __construct() {}

public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}

// 静态方法
public static function listFiles($dir, $recursive = false) {
// 检查缓存
$cacheKey = $dir . ($recursive ? '_recursive' : '');
if (isset(self::$cache[$cacheKey])) {
return self::$cache[$cacheKey];
}

if (!is_dir($dir)) {
return [];
}

$files = [];
$iterator = $recursive ? new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)) : new DirectoryIterator($dir);

foreach ($iterator as $file) {
if ($file->isFile()) {
$files[] = $file->getPathname();
}
}

// 缓存结果
self::$cache[$cacheKey] = $files;
return $files;
}

// 静态方法
public static function createDirectory($dir, $recursive = true) {
if (!file_exists($dir)) {
return mkdir($dir, 0777, $recursive);
}
return true;
}

// 静态方法
public static function deleteDirectory($dir) {
if (!is_dir($dir)) {
return false;
}

$files = array_diff(scandir($dir), ['.', '..']);
foreach ($files as $file) {
$path = $dir . '/' . $file;
if (is_dir($path)) {
self::deleteDirectory($path);
} else {
unlink($path);
}
}

return rmdir($dir);
}

private function __clone() {}
}

// 使用静态方法
$dir = "temp_dir";
if (DirectoryManager::createDirectory($dir)) {
echo "Directory created successfully\n";

// 创建一些文件
file_put_contents("$dir/file1.txt", "Content 1");
file_put_contents("$dir/file2.txt", "Content 2");

// 列出文件
$files = DirectoryManager::listFiles($dir);
echo "Files in directory:\n";
foreach ($files as $file) {
echo "- " . basename($file) . "\n";
}

// 递归列出(即使只有一个层级)
$allFiles = DirectoryManager::listFiles($dir, true);
echo "All files (recursive):\n";
foreach ($allFiles as $file) {
echo "- " . basename($file) . "\n";
}

// 从缓存获取
$cachedFiles = DirectoryManager::listFiles($dir);
echo "Retrieved from cache: " . ($files === $cachedFiles ? "Yes" : "No") . "\n";

// 删除目录
DirectoryManager::deleteDirectory($dir);
echo "Directory deleted\n";
}

15. 命名空间

详细解释

命名空间是PHP 5.3+引入的特性,用于解决命名冲突问题。

命名空间特点:

  • 避免类、函数和常量名称冲突
  • 可以嵌套(子命名空间)
  • 使用namespace关键字定义
  • 使用use关键字引入命名空间

命名空间访问:

  • 完全限定名称\Namespace\Class
  • 相对名称Class(在当前命名空间内)
  • 限定名称SubNamespace\Class

静态方法在命名空间中的使用:

  • 可以在命名空间中定义静态类
  • 静态方法可以通过完全限定名称调用
  • 在不同命名空间中可以有同名的静态类和方法

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
<?php
// 定义命名空间
namespace MyProject\Utils;

// 类定义
class StringHelper {
// 静态成员变量
private static $instanceCount = 0;

// 构造函数
public function __construct() {
self::$instanceCount++;
}

// 静态方法
public static function reverse($string) {
self::$instanceCount++;
return strrev($string);
}

// 静态方法
public static function getInstanceCount() {
return self::$instanceCount;
}
}

// 函数定义
function formatTime($timestamp) {
return date("Y-m-d H:i:s", $timestamp);
}

// 常量定义
const MAX_LENGTH = 100;

// 静态工具类
class MathHelper {
// 静态常量
const PI = 3.14159;

// 静态方法
public static function add($a, $b) {
return $a + $b;
}

public static function multiply($a, $b) {
return $a * $b;
}

// 静态方法使用静态常量
public static function circleArea($radius) {
return self::PI * $radius * $radius;
}
}

// 子命名空间
namespace MyProject\Utils\Math;

// 静态工具类
class Calculator {
// 静态成员变量
private static $operationCount = 0;

// 静态方法
public static function add($a, $b) {
self::$operationCount++;
return $a + $b;
}

public static function subtract($a, $b) {
self::$operationCount++;
return $a - $b;
}

// 静态方法
public static function getOperationCount() {
return self::$operationCount;
}
}

// 使用命名空间
namespace Main;

// 导入命名空间
use MyProject\Utils\StringHelper;
use MyProject\Utils\MathHelper;
use MyProject\Utils\Math\Calculator as MathCalc;

// 使用导入的类
echo StringHelper::reverse("Hello") . "\n"; // olleH
echo "StringHelper instances: " . StringHelper::getInstanceCount() . "\n"; // 1

// 创建实例会增加计数
new StringHelper();
echo "StringHelper instances: " . StringHelper::getInstanceCount() . "\n"; // 2

// 使用静态方法
echo "5 + 3 = " . MathHelper::add(5, 3) . "\n"; // 8
echo "Circle area (radius=5): " . MathHelper::circleArea(5) . "\n";

// 使用别名
echo "10 - 3 = " . MathCalc::subtract(10, 3) . "\n"; // 7
echo "Operation count: " . MathCalc::getOperationCount() . "\n"; // 1

// 完全限定名称
echo \MyProject\Utils\formatTime(time()) . "\n";

// 使用use导入多个元素
use MyProject\Utils\{
StringHelper as Str,
formatTime,
MAX_LENGTH
};

echo Str::reverse("World") . "\n"; // dlroW
echo formatTime(time()) . "\n";
echo "Max length: " . MAX_LENGTH . "\n";

// 另一个命名空间中的同名类
namespace AnotherProject;

class StringHelper {
// 静态方法
public static function reverse($string) {
return strtoupper(strrev($string));
}
}

// 在Main命名空间中使用
namespace Main;

// 完全限定名称调用
echo \AnotherProject\StringHelper::reverse("Hello") . "\n"; // OLLEH

16. 正则表达式

详细解释

正则表达式是一种强大的文本处理工具,用于模式匹配、搜索和替换。

PHP正则表达式函数:

  • preg_match():执行正则表达式匹配
  • preg_match_all():执行全局正则表达式匹配
  • preg_replace():执行正则表达式搜索和替换
  • preg_split():通过正则表达式分割字符串
  • preg_quote():转义正则表达式字符

正则表达式元字符:

  • ^:匹配字符串开始
  • $:匹配字符串结束
  • .:匹配任意字符(除换行符外)
  • *:匹配前一个元素0次或多次
  • +:匹配前一个元素1次或多次
  • ?:匹配前一个元素0次或1次
  • {n,m}:匹配前一个元素n到m次
  • []:字符类,匹配其中任一字符
  • |:选择,匹配左边或右边的表达式
  • ():分组,将多个元素视为一个整体

16.1 基本正则表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
<?php
// ====================== 元字符详解与验证 ======================
echo "【元字符详解与验证】\n";

// 1. ^: 匹配字符串开始
$pattern_start = '/^Hello/';
echo preg_match($pattern_start, "Hello World") ? "[✓] ^匹配开头成功\n" : "[✗] ^匹配开头失败\n";
echo preg_match($pattern_start, "Say Hello") ? "[✗] ^匹配开头错误\n" : "[✓] ^匹配开头正确拒绝\n";

// 2. $: 匹配字符串结束
$pattern_end = '/World$/';
echo preg_match($pattern_end, "Hello World") ? "[✓] $匹配结尾成功\n" : "[✗] $匹配结尾失败\n";
echo preg_match($pattern_end, "World Tour") ? "[✗] $匹配结尾错误\n" : "[✓] $匹配结尾正确拒绝\n";

// 3. .: 匹配任意字符(除换行符)
$pattern_dot = '/a.b/';
echo preg_match($pattern_dot, "acb") ? "[✓] .匹配任意字符成功\n" : "[✗] .匹配失败\n";
echo preg_match($pattern_dot, "a\nb") ? "[✗] .匹配换行符错误\n" : "[✓] .正确跳过换行符\n"; // 默认不匹配换行符

// 4. *: 匹配前元素0次或多次
$pattern_star = '/ab*c/';
echo preg_match($pattern_star, "ac") ? "[✓] *匹配0次成功 (ac)\n" : "[✗] *匹配0次失败\n";
echo preg_match($pattern_star, "abbbc") ? "[✓] *匹配多次成功 (abbbc)\n" : "[✗] *匹配多次失败\n";
echo preg_match($pattern_star, "adc") ? "[✗] *错误匹配非b字符\n" : "[✓] *正确拒绝 (adc)\n";

// 5. +: 匹配前元素1次或多次
$pattern_plus = '/ab+c/';
echo preg_match($pattern_plus, "abc") ? "[✓] +匹配1次成功 (abc)\n" : "[✗] +匹配1次失败\n";
echo preg_match($pattern_plus, "ac") ? "[✗] +错误匹配0次 (ac)\n" : "[✓] +正确拒绝0次\n";

// 6. ?: 匹配前元素0次或1次
$pattern_question = '/colou?r/';
echo preg_match($pattern_question, "color") ? "[✓] ?匹配0次成功 (color)\n" : "[✗] ?匹配0次失败\n";
echo preg_match($pattern_question, "colour") ? "[✓] ?匹配1次成功 (colour)\n" : "[✗] ?匹配1次失败\n";
echo preg_match($pattern_question, "colouur") ? "[✗] ?错误匹配2次 (colouur)\n" : "[✓] ?正确拒绝2次\n";

// 7. {n,m}: 匹配前元素n到m次
$pattern_range = '/\d{3,5}/';
echo preg_match($pattern_range, "123") ? "[✓] {3,5}匹配3位成功 (123)\n" : "[✗] {3,5}匹配3位失败\n";
echo preg_match($pattern_range, "12345") ? "[✓] {3,5}匹配5位成功 (12345)\n" : "[✗] {3,5}匹配5位失败\n";
echo preg_match($pattern_range, "12") ? "[✗] {3,5}错误匹配2位 (12)\n" : "[✓] {3,5}正确拒绝2位\n";
echo preg_match($pattern_range, "123456") ? "[✗] {3,5}错误匹配6位 (123456)\n" : "[✓] {3,5}正确拒绝6位\n";

// 8. []: 字符类
$pattern_class = '/[aeiou]/';
echo preg_match($pattern_class, "apple") ? "[✓] []匹配元音成功 (apple)\n" : "[✗] []匹配失败\n";
echo preg_match($pattern_class, "why") ? "[✗] []错误匹配无元音 (why)\n" : "[✓] []正确拒绝\n";

// 9. |: 选择
$pattern_or = '/cat|dog/';
echo preg_match($pattern_or, "I have a cat") ? "[✓] |匹配cat成功\n" : "[✗] |匹配失败\n";
echo preg_match($pattern_or, "My dog is cute") ? "[✓] |匹配dog成功\n" : "[✗] |匹配失败\n";
echo preg_match($pattern_or, "I love birds") ? "[✗] |错误匹配无cat/dog\n" : "[✓] |正确拒绝\n";

// 10. (): 分组
$pattern_group = '/(abc){2}/';
echo preg_match($pattern_group, "abcabc") ? "[✓] ()分组重复成功\n" : "[✗] ()分组匹配失败\n";
echo preg_match($pattern_group, "abc") ? "[✗] ()错误匹配单次\n" : "[✓] ()正确拒绝单次\n";

// ====================== 核心函数实战 ======================
echo "\n【核心函数实战】\n";

// preg_match() - 基础验证
$valid_email = "user+name@sub.domain.co.uk";
$invalid_email = "user@.com";
$email_pattern = '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/i';

$result_valid = preg_match($email_pattern, $valid_email);
$result_invalid = preg_match($email_pattern, $invalid_email);
echo "[邮箱验证] 正例: " . ($result_valid ? "有效 ✓" : "无效 ✗") . "\n";
echo "[邮箱验证] 反例: " . ($result_invalid ? "有效 ✗" : "无效 ✓") . "\n";

// preg_match_all() - 数据提取
$html = '<a href="https://example.com">首页</a> | <a href="/contact">联系</a>';
$link_pattern = '/<a\s+href="([^"]+)">([^<]+)<\/a>/i';

preg_match_all($link_pattern, $html, $matches);
echo "\n[链接提取] 正例:\n";
print_r($matches[0]); // 完整匹配
echo "URLs: " . implode(', ', $matches[1]) . "\n";
echo "文本: " . implode(', ', $matches[2]) . "\n";

$no_links = "纯文本无链接";
$no_match = preg_match_all($link_pattern, $no_links, $empty);
echo "[链接提取] 反例: " . ($no_match === 0 ? "✓ 无匹配" : "✗ 错误匹配") . "\n";

// preg_replace() - 内容转换
$text = "价格: $19.99 | 优惠价: $9.50";
$currency_pattern = '/\$([\d.]+)/';

$formatted = preg_replace($currency_pattern, '¥\1元', $text);
echo "\n[货币转换] 正例:\n原始: $text\n转换: $formatted\n";

$no_currency = "免费内容";
$unchanged = preg_replace($currency_pattern, '¥\1元', $no_currency);
echo "[货币转换] 反例: " . ($unchanged === $no_currency ? "✓ 未修改" : "✗ 错误修改") . "\n";

// preg_split() - 高级分割
$csv = "苹果; 香蕉, 橙子 | 葡萄";
$split_pattern = '/[;,|]\s*/';

$fruits = preg_split($split_pattern, $csv, -1, PREG_SPLIT_NO_EMPTY);
echo "\n[智能分割] 正例:\n";
print_r($fruits); // Array ( [0] => 苹果 [1] => 香蕉 [2] => 橙子 [3] => 葡萄 )

$bad_pattern = '/[\d]/'; // 错误使用数字分割
$bad_result = preg_split($bad_pattern, $csv);
echo "[智能分割] 反例: 分割结果数量=" . count($bad_result) . " (错误模式)\n";

// preg_quote() - 安全转义
$user_input = "100$?+.*";
$unsafe_regex = "/$user_input/"; // 会导致正则错误
$safe_regex = "/" . preg_quote($user_input, '/') . "/";

$test_str = "产品价格100$?+.*特惠";
echo "\n[安全转义]\n";
echo "原始模式: " . @preg_match($unsafe_regex, $test_str) . " (会产生警告)\n";
echo "安全模式: " . preg_match($safe_regex, $test_str) . " ✓ 正确匹配\n";

// ====================== 综合应用案例 ======================
echo "\n【综合案例:日志分析与转换】\n";
$log_data = <<<LOG
192.168.1.105 - [09/Dec/2025:14:30:01 +0000] "GET /index.php?user=admin HTTP/1.1" 200 1234
10.0.0.5 - [09/Dec/2025:14:35:22 +0000] "POST /login.php HTTP/1.1" 401 567
172.16.0.22 - [09/Dec/2025:14:40:15 +0000] "GET /image.png HTTP/1.1" 404 321
LOG;

// 1. 使用preg_match_all提取日志数据
$log_pattern = '/^([\d.]+) - \[(.*?)\] "(GET|POST) ([^"]+)" (\d+) (\d+)$/m';
preg_match_all($log_pattern, $log_data, $log_matches, PREG_SET_ORDER);

// 2. 分析结果
echo "检测到 " . count($log_matches) . " 条有效日志\n";
foreach ($log_matches as $match) {
[$full, $ip, $time, $method, $path, $status, $size] = $match;

// 3. 使用preg_replace转换路径格式
$clean_path = preg_replace('/\?.*$/', '', $path); // 移除查询参数

// 4. 使用元字符验证状态码
$status_desc = preg_match('/^2\d{2}$/', $status) ? "成功" :
(preg_match('/^4\d{2}$/', $status) ? "客户端错误" : "其他");

echo sprintf("[%-15s] %s %s → %s (%s | %s字节)\n",
$ip, $method, $clean_path, $status_desc, $status, $size);
}

// 5. 使用preg_split按状态码分组
$grouped = preg_split('/^(.*?)$/m', $log_data, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
echo "\n[状态码分组] 4xx错误日志:\n";
foreach ($grouped as $line) {
if (preg_match('/" (4\d{2}) /', $line)) {
echo "⚠️ " . trim($line) . "\n";
}
}

// 6. 安全处理用户输入的搜索关键词
$search_term = "admin?404";
$safe_term = preg_quote($search_term, '/');
$matched_logs = preg_grep("/$safe_term/", explode("\n", $log_data));
echo "\n[安全搜索] 包含 '{$search_term}' 的日志:\n";
if (!empty($matched_logs)) {
foreach ($matched_logs as $log) echo "🔍 $log\n";
} else {
echo "✓ 未找到匹配日志\n";
}

16.2 高级正则表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
<?php
/**
* 高级正则表达式详解
* 本示例覆盖PHP正则表达式的高级特性,包括:
* - 零宽断言(前瞻/后顾)
* - 命名捕获组
* - 模式修饰符详解
* - Unicode支持
* - 回溯控制
* - 正则表达式性能优化
* - 完整的错误处理
*/

// 1. 零宽断言(前瞻/后顾) - 验证密码强度
echo "【1. 零宽断言(前瞻/后顾)】\n";

/**
* 密码规则:
* - 至少8个字符
* - 必须包含至少一个大写字母(前瞻)
* - 必须包含至少一个小写字母(前瞻)
* - 必须包含至少一个数字(前瞻)
* - 不能以数字开头(后顾)
*/
$password_pattern = '/^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?<!^\d).{8,}$/';

$passwords = [
"ValidPass123", // 有效: 满足所有条件
"invalidpass123", // 无效: 缺少大写字母
"VALIDPASS123", // 无效: 缺少小写字母
"ValidPassword", // 无效: 缺少数字
"1InvalidPass", // 无效: 以数字开头
"Sh0rt", // 无效: 长度不足
"Valid1Pass" // 有效: 满足所有条件
];

foreach ($passwords as $pwd) {
$result = preg_match($password_pattern, $pwd);
echo sprintf("[%-12s] %s\n",
$pwd,
$result ? "✓ 强密码" : "✗ 弱密码 - 不符合复杂度要求"
);
}

// 2. 命名捕获组 - 解析日期
echo "\n【2. 命名捕获组】\n";

/**
* 日期格式: YYYY-MM-DD 或 DD/MM/YYYY
* 使用命名捕获组提取年、月、日
*/
$date_pattern = '/(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})|(?P<day2>\d{2})\/(?P<month2>\d{2})\/(?P<year2>\d{4})/';

$dates = [
"2023-12-25",
"31/12/2023",
"12-25-2023" // 无效格式
];

foreach ($dates as $date) {
if (preg_match($date_pattern, $date, $matches)) {
// 处理不同格式的日期
if (!empty($matches['year'])) {
$year = $matches['year'];
$month = $matches['month'];
$day = $matches['day'];
} else {
$year = $matches['year2'];
$month = $matches['month2'];
$day = $matches['day2'];
}
echo "[$date] ✓ 有效日期: {$year}{$month}{$day}日\n";
} else {
echo "[$date] ✗ 无效日期格式\n";
}
}

// 3. 模式修饰符详解
echo "\n【3. 模式修饰符详解】\n";

/**
* 常用修饰符:
* i - 不区分大小写
* m - 多行模式(^和$匹配每行开头结尾)
* s - 使.匹配包括换行符在内的所有字符
* u - UTF-8模式(支持Unicode)
* x - 扩展模式(忽略空格和注释)
*/

// 示例1: 多行模式(m)和Unicode(u)结合
$text_multiline = "苹果\nBanana\n樱桃\nDate";
$pattern_multiline = '/^[\p{L}]{3,}$/mu'; // 匹配每行中至少3个字母的单词(包含Unicode字符)

echo "多行文本:\n$text_multiline\n";
preg_match_all($pattern_multiline, $text_multiline, $matches_multiline);
echo "匹配结果(多行+Unicode): " . implode(", ", $matches_multiline[0]) . "\n";

// 示例2: 扩展模式(x) - 提高可读性
$pattern_verbose = '
/ # 分隔符
\b # 单词边界
(?<word> # 命名捕获组
\w+ # 一个或多个单词字符
)
\s+ # 一个或多个空白字符
\k<word> # 重复前面捕获的相同单词
\b # 单词边界
/x # 扩展模式
';

$text_repeat = "the the quick brown fox fox jumps over the lazy dog dog";
if (preg_match_all($pattern_verbose, $text_repeat, $matches_repeat)) {
echo "重复单词检测: " . implode(", ", $matches_repeat[0]) . "\n";
}

// 4. Unicode属性支持
echo "\n【4. Unicode属性支持】\n";

$international_text = "Hello 你好 123 こんにちは 456";
$pattern_unicode = '/[\p{L}\p{N}]+/u'; // 匹配所有字母和数字(包括非ASCII字符)

preg_match_all($pattern_unicode, $international_text, $matches_unicode);
echo "原始文本: $international_text\n";
echo "Unicode匹配结果: " . implode(", ", $matches_unicode[0]) . "\n";

// 5. 回溯控制 - 防止正则表达式灾难性回溯
echo "\n【5. 回溯控制】\n";

/**
* 问题: 当遇到恶意构造的输入时, 正则表达式可能会陷入灾难性回溯
* 解决方案: 使用原子组(?>...)或占有优先量词*+、++、?+、{n,m}+限制回溯
*/

// 危险模式示例(可能导致回溯爆炸)
$dangerous_pattern = '/^(a+)+$/';
$safe_pattern = '/^(?>a+)+$/'; // 使用原子组防止回溯

$test_string = str_repeat('a', 25) . 'b'; // 长字符串+不匹配字符

$start = microtime(true);
$result_dangerous = @preg_match($dangerous_pattern, $test_string, $matches, 0, 1000000); // 1秒超时
$time_dangerous = microtime(true) - $start;

$start = microtime(true);
$result_safe = preg_match($safe_pattern, $test_string);
$time_safe = microtime(true) - $start;

echo "回溯控制测试:\n";
echo "危险模式执行时间: " . sprintf('%.6f', $time_dangerous) . "s, 结果: " . ($result_dangerous === false ? "超时/错误" : $result_dangerous) . "\n";
echo "安全模式执行时间: " . sprintf('%.6f', $time_safe) . "s, 结果: $result_safe\n";

// 6. 高级URL解析
echo "\n【6. 高级URL解析】\n";

$url_parser = '/
^ # 字符串开始
(?:
(?<scheme>[a-z]+) # 协议(命名捕获)
:\/\/ # ://
)? # 协议部分是可选的
(?:
(?<auth>[^@]+)@ # 认证信息 username:password@
)? # 认证信息是可选的
(?<host> # 主机名(命名捕获)
(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+ # 子域名
[a-z]{2,63} # 顶级域名
| # 或者
\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} # IPv4地址
)
(?::(?<port>\d+))? # 端口(命名捕获,可选)
(?<path>\/[^\?]*)? # 路径(命名捕获,可选)
(?:\?(?<query>[^#]*))? # 查询参数(命名捕获,可选)
(?:#(?<fragment>.*))? # 片段(命名捕获,可选)
$ # 字符串结束
/ix'; // 不区分大小写+扩展模式

$urls = [
"https://user:pass@example.com:8080/path/to/file?query=1#fragment",
"http://sub.domain.co.uk",
"ftp://192.168.1.1/file.txt",
"example.com/path",
"invalid_url"
];

foreach ($urls as $url) {
echo "\n分析URL: $url\n";
if (preg_match($url_parser, $url, $matches)) {
// 清理匹配结果,只保留命名捕获
$result = [];
foreach ($matches as $key => $value) {
if (!is_int($key) && $value !== '') {
$result[$key] = $value;
}
}
echo "✓ 有效URL\n";
foreach ($result as $name => $value) {
echo " $name: $value\n";
}
} else {
echo "✗ 无效URL格式\n";
}
}

// 7. 正则表达式工具类(增强版)
echo "\n【7. 增强版正则表达式工具类】\n";

class AdvancedRegexHelper {
// 静态常量 - 优化的正则表达式
const EMAIL_PATTERN = '/^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/i';
const URL_PATTERN = '/^(?:https?:\/\/)?(?:[a-z0-9-]+\.)+[a-z]{2,6}(?:\/[\w\-\.?%&=]*)?$/i';
const PHONE_PATTERN = '/^\+?1?[-. (]*(\d{3})[-. )]*(\d{3})[-. ]*(\d{4})$/';
const CREDIT_CARD_PATTERN = '/^(?<visa>4\d{12}(?:\d{3})?)|(?<mastercard>5[1-5]\d{14})|(?<amex>3[47]\d{13})$/';
const HTML_TAG_PATTERN = '/<([a-z]+)([^<]*)>(.*?)<\/\1>/is';

// 验证方法
public static function validateEmail($email) {
return self::safeRegexMatch(self::EMAIL_PATTERN, $email);
}

public static function validateUrl($url) {
return self::safeRegexMatch(self::URL_PATTERN, $url);
}

public static function validatePhone($phone) {
return self::safeRegexMatch(self::PHONE_PATTERN, $phone);
}

public static function validateCreditCard($cardNumber) {
$cleanCard = preg_replace('/\s+/', '', $cardNumber);
return self::safeRegexMatch(self::CREDIT_CARD_PATTERN, $cleanCard);
}

// 提取方法
public static function extractEmails($text) {
return self::safeRegexMatchAll(self::EMAIL_PATTERN, $text);
}

public static function extractUrls($text) {
return self::safeRegexMatchAll(self::URL_PATTERN, $text);
}

public static function extractPhoneNumbers($text) {
return self::safeRegexMatchAll(self::PHONE_PATTERN, $text);
}

// 转换方法
public static function maskCreditCard($cardNumber) {
$cleanCard = preg_replace('/\D/', '', $cardNumber);
if (!self::validateCreditCard($cleanCard)) {
return "无效的信用卡号";
}

$last4 = substr($cleanCard, -4);
$masked = str_repeat('*', strlen($cleanCard) - 4) . $last4;
return preg_replace('/(\*{4})(?=\*{4})/', '$1 ', $masked);
}

public static function sanitizeHtml($html) {
// 仅保留安全的HTML标签
$allowedTags = ['b', 'i', 'u', 'em', 'strong', 'p', 'br', 'a'];
return preg_replace_callback(
self::HTML_TAG_PATTERN,
function($matches) use ($allowedTags) {
$tag = strtolower($matches[1]);
if (in_array($tag, $allowedTags)) {
// 仅对a标签特殊处理,清理href属性
if ($tag === 'a') {
$href = preg_match('/href\s*=\s*"([^"]*)"/i', $matches[2], $hrefMatches)
? $hrefMatches[1] : '';
if (preg_match('/^(https?:\/\/|mailto:)/i', $href)) {
return "<a href=\"$href\">" . self::sanitizeHtml($matches[3]) . "</a>";
}
}
return "<$tag>" . self::sanitizeHtml($matches[3]) . "</$tag>";
}
return self::sanitizeHtml($matches[3]); // 移除不允许的标签,但保留内容
},
$html
);
}

// 替换方法
public static function makeClickableLinks($text) {
$pattern = '/(?<![\w\/])(https?:\/\/|www\.)([\w\-\.]+\.[a-zA-Z]{2,}(?:\/[\w\.\/\?\&\=\-]*)?)/i';
return preg_replace_callback($pattern, function($matches) {
$url = $matches[0];
$display = (strlen($url) > 30) ? substr($url, 0, 27) . '...' : $url;
if (strpos($url, 'www.') === 0) {
$url = 'http://' . $url;
}
return "<a href=\"$url\" target=\"_blank\">$display</a>";
}, $text);
}

// 工具方法
private static function safeRegexMatch($pattern, $subject, $flags = 0) {
set_error_handler(function() {}); // 临时忽略错误
$result = preg_match($pattern, $subject, $matches, $flags);
restore_error_handler();

if ($result === false) {
$error = preg_last_error();
$errorMsg = self::getPregError($error);
trigger_error("正则表达式错误: $errorMsg", E_USER_WARNING);
return false;
}

return $result === 1;
}

private static function safeRegexMatchAll($pattern, $subject, $flags = PREG_PATTERN_ORDER) {
set_error_handler(function() {});
$result = preg_match_all($pattern, $subject, $matches, $flags);
restore_error_handler();

if ($result === false) {
$error = preg_last_error();
$errorMsg = self::getPregError($error);
trigger_error("正则表达式错误: $errorMsg", E_USER_WARNING);
return [];
}

return $matches[0] ?? [];
}

private static function getPregError($code) {
switch ($code) {
case PREG_NO_ERROR: return "无错误";
case PREG_INTERNAL_ERROR: return "内部错误";
case PREG_BACKTRACK_LIMIT_ERROR: return "回溯限制超出";
case PREG_RECURSION_LIMIT_ERROR: return "递归限制超出";
case PREG_BAD_UTF8_ERROR: return "无效的UTF-8数据";
case PREG_BAD_UTF8_OFFSET_ERROR: return "无效的UTF-8偏移量";
default: return "未知错误 ($code)";
}
}
}

// 8. 综合应用案例:文本内容分析器
echo "\n【8. 综合应用:智能文本内容分析器】\n";

class ContentAnalyzer {
private $text;
private $analysis;

public function __construct($text) {
$this->text = $text;
$this->analysis = [];
}

public function analyze() {
$this->analyzeSentences();
$this->analyzeKeywords();
$this->detectEntities();
$this->identifySensitiveContent();
return $this->analysis;
}

private function analyzeSentences() {
// 智能分割句子(处理缩写、引号等情况)
$sentencePattern = '/
(?<= # 后顾断言
[.!?] # 句号、问号、感叹号
[\]\])\'"]* # 可能跟随引号或括号
\s+ # 后跟空白
)
(?=[A-Z]) # 前瞻断言: 下一个字符是大写字母
| # 或者
(?<= # 处理缩写
\b(?:Mr|Mrs|Dr|Prof|Inc|Ltd|Jr|Sr|vs)\.
\s+
)
(?=[A-Z])/x';

$sentences = preg_split($sentencePattern, $this->text, -1, PREG_SPLIT_NO_EMPTY);
$this->analysis['sentences'] = $sentences;
$this->analysis['sentence_count'] = count($sentences);
}

private function analyzeKeywords() {
// 提取关键词(排除停用词)
$wordPattern = '/\b(?!(?:the|and|or|in|on|at|to|for|with|a|an|of|is|are|was|were|be|been|being)\b)[a-zA-Z]{3,}\b/';
preg_match_all($wordPattern, strtolower($this->text), $matches);

$words = array_count_values($matches[0]);
arsort($words);
$this->analysis['top_keywords'] = array_slice($words, 0, 5, true);
}

private function detectEntities() {
// 检测URL、邮箱、电话
$this->analysis['urls'] = AdvancedRegexHelper::extractUrls($this->text);
$this->analysis['emails'] = AdvancedRegexHelper::extractEmails($this->text);
$this->analysis['phones'] = AdvancedRegexHelper::extractPhoneNumbers($this->text);
}

private function identifySensitiveContent() {
// 识别潜在敏感内容
$patterns = [
'credit_cards' => '/\b(?:\d[ -]*?){13,16}\b/',
'ssn' => '/\b\d{3}[- ]?\d{2}[- ]?\d{4}\b/',
'password_like' => '/\b(password|pass|pwd)\s*[:=]\s*[\'"]?[\w@#$%^&*!]{5,}[\'"]?\b/i'
];

foreach ($patterns as $type => $pattern) {
preg_match_all($pattern, $this->text, $matches);
if (!empty($matches[0])) {
$this->analysis['sensitive'][$type] = count($matches[0]);
}
}
}

public function getReport() {
$analysis = $this->analyze();
$report = "===== 内容分析报告 =====\n";
$report .= "句子数量: {$analysis['sentence_count']}\n\n";

$report .= "【关键词频率】\n";
foreach ($analysis['top_keywords'] as $word => $count) {
$report .= "- $word: $count 次\n";
}

$report .= "\n【检测到的实体】\n";
$report .= "- 链接: " . (empty($analysis['urls']) ? "无" : implode(", ", $analysis['urls'])) . "\n";
$report .= "- 邮箱: " . (empty($analysis['emails']) ? "无" : implode(", ", $analysis['emails'])) . "\n";
$report .= "- 电话: " . (empty($analysis['phones']) ? "无" : implode(", ", $analysis['phones'])) . "\n";

if (!empty($analysis['sensitive'])) {
$report .= "\n【警告: 检测到敏感内容】\n";
foreach ($analysis['sensitive'] as $type => $count) {
$report .= "- $type: $count 处\n";
}
$report .= "请检查内容是否包含不应公开的个人信息!\n";
}

return $report;
}
}

// 9. 演示工具类用法
echo "\n【9. 高级工具类应用演示】\n";

// 验证示例
$emails = ["user@example.com", "invalid-email@", "name+tag@sub.domain.co.uk"];
foreach ($emails as $email) {
echo sprintf("邮箱 '%s': %s\n",
$email,
AdvancedRegexHelper::validateEmail($email) ? "✓ 有效" : "✗ 无效"
);
}

// 信用卡掩码
$cards = [
"4111 1111 1111 1111", // Visa
"5500 0000 0000 0004", // Mastercard
"3400 0000 0000 009" // Amex
];
foreach ($cards as $card) {
echo "信用卡: $card → " . AdvancedRegexHelper::maskCreditCard($card) . "\n";
}

// HTML清理
$html_content = '<p>安全内容 <b>加粗</b> 和 <a href="https://example.com" onclick="alert(1)">链接</a></p>
<script>alert("XSS攻击")</script>
合法<a href="http://example.com/path">内部链接</a>和<a href="javascript:alert(\'bad\')">危险链接</a>';

echo "\n原始HTML:\n$html_content\n";
echo "\n清理后的HTML:\n" . AdvancedRegexHelper::sanitizeHtml($html_content) . "\n";

// 10. 综合案例演示
echo "\n【10. 综合案例:内容安全分析】\n";

$sample_text = <<<TEXT
这是一份测试文档。其中包含一个有效的URL: https://www.example.com/path?query=1#section1
同时还有测试邮箱: contact@example.com 和 support.team@example.co.uk

请注意,我的信用卡号是 4111 1111 1111 1111,社会保险号 123-45-6789。
密码设置为: password=SecurePass123

联系我: (123) 456-7890 或 987-654-3210
更多信息请访问 www.our-company.com 或联系 admin@company.com
TEXT;

$analyzer = new ContentAnalyzer($sample_text);
echo $analyzer->getReport();

// 11. 正则表达式性能优化技巧
echo "\n【11. 正则表达式性能优化技巧】\n";

$large_text = str_repeat("Lorem ipsum dolor sit amet, consectetur adipiscing elit. ", 1000);
$search_word = "dolor";

// 非优化版本
$pattern_unoptimized = '/\b' . preg_quote($search_word, '/') . '\b/';

// 优化版本
$pattern_optimized = '/\b' . preg_quote($search_word, '/') . '\b/S'; // S修饰符表示研究正则表达式并优化

$iterations = 10;
$time_unoptimized = 0;
$time_optimized = 0;

for ($i = 0; $i < $iterations; $i++) {
$start = microtime(true);
preg_match_all($pattern_unoptimized, $large_text, $matches);
$time_unoptimized += microtime(true) - $start;

$start = microtime(true);
preg_match_all($pattern_optimized, $large_text, $matches);
$time_optimized += microtime(true) - $start;
}

echo "性能测试 (平均时间):\n";
echo "非优化模式: " . sprintf('%.6f', $time_unoptimized / $iterations) . " 秒\n";
echo "优化模式(S修饰符): " . sprintf('%.6f', $time_optimized / $iterations) . " 秒\n";
echo "性能提升: " . sprintf('%.1f', ($time_unoptimized / $time_optimized) * 100) . "%\n";

17. PHP与MySQL

详细解释

PHP提供了多种方式与MySQL数据库交互,主要包括:

  • MySQLi(MySQL Improved):面向对象和过程式接口
  • PDO(PHP Data Objects):数据访问抽象层,支持多种数据库

连接数据库步骤:

  1. 创建数据库连接
  2. 执行SQL查询
  3. 处理结果集
  4. 关闭连接

重要概念:

  • 预处理语句:防止SQL注入,提高性能
  • 事务:确保多个操作的原子性
  • 错误处理:捕获和处理数据库错误
  • 静态方法:用于创建单例模式或工具类

17.1 使用MySQLi(面向对象)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
<?php
// 数据库连接参数
$host = "localhost";
$username = "root";
$password = "password";
$database = "test_db";

// 数据库工具类
class Database {
// 静态实例(单例模式)
private static $instance = null;
private $connection;

// 私有构造函数
private function __construct($host, $username, $password, $database) {
$this->connection = new mysqli($host, $username, $password, $database);
if ($this->connection->connect_error) {
die("Connection failed: " . $this->connection->connect_error);
}
}

// 获取单例实例
public static function getInstance($host = 'localhost', $username = 'root', $password = '', $database = 'test_db') {
if (self::$instance === null) {
self::$instance = new self($host, $username, $password, $database);
}
return self::$instance;
}

// 获取连接
public function getConnection() {
return $this->connection;
}

// 静态方法:执行查询
public static function query($sql, $params = []) {
$instance = self::getInstance();
$stmt = $instance->connection->prepare($sql);
if ($params) {
$types = str_repeat('s', count($params));
$stmt->bind_param($types, ...$params);
}
$stmt->execute();
return $stmt->get_result();
}

// 静态方法:插入数据
public static function insert($table, $data) {
$instance = self::getInstance();
$keys = array_keys($data);
$values = array_values($data);

$placeholders = implode(',', array_fill(0, count($keys), '?'));
$columns = implode(',', $keys);

$sql = "INSERT INTO $table ($columns) VALUES ($placeholders)";
$stmt = $instance->connection->prepare($sql);

$types = str_repeat('s', count($values));
$stmt->bind_param($types, ...$values);
$stmt->execute();

return $instance->connection->insert_id;
}

private function __clone() {}
}

// 创建连接
$conn = Database::getInstance($host, $username, $password, $database)->getConnection();
echo "Connected successfully\n";

// 创建表
$createTable = "CREATE TABLE IF NOT EXISTS users (
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)";
if ($conn->query($createTable) === TRUE) {
echo "Table 'users' created successfully\n";
} else {
echo "Error creating table: " . $conn->error . "\n";
}

// 插入数据(普通查询)
$insert = "INSERT INTO users (name, email) VALUES ('John Doe', 'john@example.com')";
if ($conn->query($insert) === TRUE) {
echo "New record created successfully\n";
} else {
echo "Error: " . $insert . "\n" . $conn->error . "\n";
}

// 插入数据(预处理语句)
$name = "Jane Smith";
$email = "jane@example.com";
$stmt = $conn->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
$stmt->bind_param("ss", $name, $email);
if ($stmt->execute()) {
echo "New record created using prepared statement\n";
} else {
echo "Error: " . $stmt->error . "\n";
}

// 使用静态方法插入数据
$userId = Database::insert('users', [
'name' => 'Static User',
'email' => 'static@example.com'
]);
echo "User created with ID: $userId\n";

// 查询数据
$result = $conn->query("SELECT id, name, email FROM users");
if ($result->num_rows > 0) {
echo "Users:\n";
while ($row = $result->fetch_assoc()) {
echo "ID: " . $row["id"] . " - Name: " . $row["name"] . " - Email: " . $row["email"] . "\n";
}
} else {
echo "No users found\n";
}

// 使用静态方法查询数据
$users = Database::query("SELECT id, name, email FROM users WHERE name = ?", ["John Doe"]);
if ($users->num_rows > 0) {
echo "Found users:\n";
while ($row = $users->fetch_assoc()) {
echo "ID: " . $row["id"] . " - Name: " . $row["name"] . " - Email: " . $row["email"] . "\n";
}
} else {
echo "No users found with that name\n";
}

// 更新数据
$update = "UPDATE users SET email='newemail@example.com' WHERE name='John Doe'";
if ($conn->query($update) === TRUE) {
echo "Record updated successfully\n";
} else {
echo "Error updating record: " . $conn->error . "\n";
}

// 删除数据
$delete = "DELETE FROM users WHERE name='Jane Smith'";
if ($conn->query($delete) === TRUE) {
echo "Record deleted successfully\n";
} else {
echo "Error deleting record: " . $conn->error . "\n";
}

// 事务示例
$conn->begin_transaction();
try {
$conn->query("INSERT INTO users (name, email) VALUES ('Transaction User', 'transaction@example.com')");
$conn->query("INSERT INTO users (name, email) VALUES ('Another User', 'another@example.com')");

// 模拟错误
// $conn->query("INVALID SQL");

$conn->commit();
echo "Transaction completed successfully\n";
} catch (Exception $e) {
$conn->rollback();
echo "Transaction failed: " . $e->getMessage() . "\n";
}

// 关闭连接
$conn->close();

17.2 使用PDO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
<?php
// 数据库连接参数
$host = "localhost";
$username = "root";
$password = "password";
$database = "test_db";

// PDO数据库类
class PDODatabase {
// 静态实例(单例模式)
private static $instance = null;
private $pdo;

// 私有构造函数
private function __construct($host, $username, $password, $database) {
try {
$dsn = "mysql:host=$host;dbname=$database;charset=utf8";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
$this->pdo = new PDO($dsn, $username, $password, $options);
} catch (PDOException $e) {
die("Connection failed: " . $e->getMessage());
}
}

// 获取单例实例
public static function getInstance($host = 'localhost', $username = 'root', $password = '', $database = 'test_db') {
if (self::$instance === null) {
self::$instance = new self($host, $username, $password, $database);
}
return self::$instance;
}

// 获取连接
public function getConnection() {
return $this->pdo;
}

// 静态方法:执行查询
public static function query($sql, $params = []) {
$instance = self::getInstance();
$stmt = $instance->pdo->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll();
}

// 静态方法:插入数据
public static function insert($table, $data) {
$instance = self::getInstance();
$keys = array_keys($data);
$placeholders = array_map(function($key) { return ":$key"; }, $keys);

$sql = "INSERT INTO $table (" . implode(',', $keys) . ") VALUES (" . implode(',', $placeholders) . ")";
$stmt = $instance->pdo->prepare($sql);

foreach ($data as $key => $value) {
$stmt->bindValue(":$key", $value);
}

$stmt->execute();
return $instance->pdo->lastInsertId();
}

// 静态方法:开始事务
public static function beginTransaction() {
$instance = self::getInstance();
return $instance->pdo->beginTransaction();
}

// 静态方法:提交事务
public static function commit() {
$instance = self::getInstance();
return $instance->pdo->commit();
}

// 静态方法:回滚事务
public static function rollBack() {
$instance = self::getInstance();
return $instance->pdo->rollBack();
}

private function __clone() {}
}

try {
// 创建连接
$pdo = PDODatabase::getInstance($host, $username, $password, $database)->getConnection();
echo "Connected to database using PDO\n";

// 创建表
$createTable = "CREATE TABLE IF NOT EXISTS users (
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)";
$pdo->exec($createTable);
echo "Table 'users' created successfully\n";

// 插入数据(预处理语句)
$name = "Alice Johnson";
$email = "alice@example.com";
$stmt = $pdo->prepare("INSERT INTO users (name, email) VALUES (:name, :email)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':email', $email);
$stmt->execute();
echo "New record created using prepared statement\n";

// 使用静态方法插入数据
$userId = PDODatabase::insert('users', [
'name' => 'PDO Static User',
'email' => 'pdo_static@example.com'
]);
echo "User created with ID: $userId\n";

// 查询数据
$stmt = $pdo->query("SELECT id, name, email FROM users");
$users = $stmt->fetchAll();

if (count($users) > 0) {
echo "Users:\n";
foreach ($users as $user) {
echo "ID: " . $user['id'] . " - Name: " . $user['name'] . " - Email: " . $user['email'] . "\n";
}
} else {
echo "No users found\n";
}

// 使用静态方法查询
$johnUsers = PDODatabase::query("SELECT id, name, email FROM users WHERE name = :name", [':name' => 'John Doe']);
if (count($johnUsers) > 0) {
echo "Found John users:\n";
foreach ($johnUsers as $user) {
echo "ID: " . $user['id'] . " - Name: " . $user['name'] . " - Email: " . $user['email'] . "\n";
}
} else {
echo "No users named John found\n";
}

// 更新数据
$email = "updated@example.com";
$name = "Alice Johnson";
$stmt = $pdo->prepare("UPDATE users SET email = :email WHERE name = :name");
$stmt->bindParam(':email', $email);
$stmt->bindParam(':name', $name);
$stmt->execute();
echo "Record updated successfully\n";

// 事务示例
PDODatabase::beginTransaction();
try {
PDODatabase::insert('users', [
'name' => 'Transaction User',
'email' => 'pdo_transaction@example.com'
]);

PDODatabase::insert('users', [
'name' => 'Another User',
'email' => 'pdo_another@example.com'
]);

// 模拟错误
// PDODatabase::query("INVALID SQL");

PDODatabase::commit();
echo "Transaction completed successfully\n";
} catch (PDOException $e) {
PDODatabase::rollBack();
echo "Transaction failed: " . $e->getMessage() . "\n";
}

// 关闭连接
$pdo = null;
} catch (PDOException $e) {
die("Connection failed: " . $e->getMessage());
}

综合大例子:博客系统

以下是一个综合性的Web应用示例,包含所有前面介绍的知识点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
<?php
// 1. 命名空间和引入
namespace BlogApp;

use DateTime;
use Exception;
use PDO;
use PDOException;

// 2. 配置
define("DB_HOST", "localhost");
define("DB_NAME", "blog_db");
define("DB_USER", "root");
define("DB_PASS", "password");
define("MAX_POSTS_PER_PAGE", 5);

// 3. 工具类
class Utils {
// 静态缓存
private static $cache = [];

// 静态方法:清理输入
public static function sanitizeInput($data) {
return htmlspecialchars(trim($data), ENT_QUOTES, 'UTF-8');
}

// 静态方法:重定向
public static function redirect($url) {
header("Location: $url");
exit();
}

// 静态方法:获取当前URL
public static function getCurrentUrl() {
$protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http';
$host = $_SERVER['HTTP_HOST'];
$uri = $_SERVER['REQUEST_URI'];
return "$protocol://$host$uri";
}

// 静态方法:缓存结果
public static function cached($key, $callback, $ttl = 3600) {
if (isset(self::$cache[$key])) {
return self::$cache[$key];
}

$result = $callback();
self::$cache[$key] = $result;
return $result;
}
}

// 4. 数据库连接类(单例模式)
class Database {
// 静态实例
private static $instance = null;
private $pdo;

// 私有构造函数
private function __construct() {
try {
$dsn = "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_PERSISTENT => true
];
$this->pdo = new PDO($dsn, DB_USER, DB_PASS, $options);
} catch (PDOException $e) {
die("Database connection failed: " . $e->getMessage());
}
}

// 获取单例实例
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}

// 获取连接
public function getConnection() {
return $this->pdo;
}

// 静态方法:执行查询
public static function query($sql, $params = []) {
$instance = self::getInstance();
$stmt = $instance->pdo->prepare($sql);
$stmt->execute($params);
return $stmt;
}

// 静态方法:获取所有结果
public static function fetchAll($sql, $params = []) {
$stmt = self::query($sql, $params);
return $stmt->fetchAll();
}

// 静态方法:获取单行结果
public static function fetchOne($sql, $params = []) {
$stmt = self::query($sql, $params);
return $stmt->fetch();
}

// 静态方法:插入数据
public static function insert($table, $data) {
$columns = implode(',', array_keys($data));
$placeholders = ':' . implode(',:', array_keys($data));

$sql = "INSERT INTO $table ($columns) VALUES ($placeholders)";
$stmt = self::query($sql, $data);

$instance = self::getInstance();
return $instance->pdo->lastInsertId();
}

private function __clone() {}
}

// 5. 用户类
class User {
// 静态缓存
private static $userCache = [];

private $id;
private $name;
private $email;
private $password;

public function __construct($name, $email, $password) {
$this->name = $name;
$this->email = $email;
$this->password = password_hash($password, PASSWORD_DEFAULT);
}

public function save() {
$userId = Database::insert('users', [
'name' => $this->name,
'email' => $this->email,
'password' => $this->password
]);
$this->id = $userId;
return true;
}

// 静态方法:用户认证
public static function authenticate($email, $password) {
$sql = "SELECT * FROM users WHERE email = :email";
$user = Database::fetchOne($sql, [':email' => $email]);

if ($user && password_verify($password, $user['password'])) {
return $user;
}
return false;
}

// 静态方法:获取用户
public static function getById($id) {
// 检查缓存
if (isset(self::$userCache[$id])) {
return self::$userCache[$id];
}

$sql = "SELECT * FROM users WHERE id = :id";
$user = Database::fetchOne($sql, [':id' => $id]);

// 缓存结果
if ($user) {
self::$userCache[$id] = $user;
}

return $user;
}

// 静态方法:获取所有用户
public static function getAll() {
return Database::fetchAll("SELECT * FROM users");
}
}

// 6. 博客文章类
class Post {
private $id;
private $title;
private $content;
private $authorId;
private $createdAt;

public function __construct($title, $content, $authorId) {
$this->title = $title;
$this->content = $content;
$this->authorId = $authorId;
$this->createdAt = new DateTime();
}

public function save() {
$postId = Database::insert('posts', [
'title' => $this->title,
'content' => $this->content,
'author_id' => $this->authorId,
'created_at' => $this->createdAt->format('Y-m-d H:i:s')
]);
$this->id = $postId;
return true;
}

// 静态方法:获取所有文章
public static function getAll($page = 1, $limit = MAX_POSTS_PER_PAGE) {
$offset = ($page - 1) * $limit;
$sql = "SELECT p.*, u.name as author_name
FROM posts p
JOIN users u ON p.author_id = u.id
ORDER BY p.created_at DESC
LIMIT :limit OFFSET :offset";

$stmt = Database::getInstance()->getConnection()->prepare($sql);
$stmt->bindValue(':limit', (int)$limit, PDO::PARAM_INT);
$stmt->bindValue(':offset', (int)$offset, PDO::PARAM_INT);
$stmt->execute();

return $stmt->fetchAll();
}

// 静态方法:获取文章总数
public static function getCount() {
return Database::fetchOne("SELECT COUNT(*) as count FROM posts")['count'];
}

// 静态方法:获取单篇文章
public static function getById($id) {
$sql = "SELECT p.*, u.name as author_name
FROM posts p
JOIN users u ON p.author_id = u.id
WHERE p.id = :id";
return Database::fetchOne($sql, [':id' => $id]);
}

// 静态方法:按作者获取文章
public static function getByAuthor($authorId) {
$sql = "SELECT * FROM posts WHERE author_id = :author_id ORDER BY created_at DESC";
return Database::fetchAll($sql, [':author_id' => $authorId]);
}

// 静态方法:搜索文章
public static function search($query) {
$sql = "SELECT p.*, u.name as author_name
FROM posts p
JOIN users u ON p.author_id = u.id
WHERE p.title LIKE :query OR p.content LIKE :query
ORDER BY p.created_at DESC";
return Database::fetchAll($sql, [':query' => "%$query%"]);
}
}

// 7. 路由处理
function handleRequest() {
$path = $_SERVER['REQUEST_URI'];
$method = $_SERVER['REQUEST_METHOD'];

// 静态文件处理
if (preg_match('/\.(css|js|png|jpg|jpeg|gif)$/', $path)) {
return;
}

// 路由
if ($path === '/' || $path === '/index.php') {
showHome();
} elseif ($path === '/login' && $method === 'GET') {
showLoginForm();
} elseif ($path === '/login' && $method === 'POST') {
processLogin();
} elseif ($path === '/register' && $method === 'GET') {
showRegistrationForm();
} elseif ($path === '/register' && $method === 'POST') {
processRegistration();
} elseif (preg_match('/^\/post\/(\d+)$/', $path, $matches)) {
showPost($matches[1]);
} elseif ($path === '/create' && $method === 'GET') {
showCreateForm();
} elseif ($path === '/create' && $method === 'POST') {
processCreatePost();
} elseif ($path === '/search' && $method === 'GET') {
showSearchResults();
} elseif ($path === '/logout') {
processLogout();
} else {
show404();
}
}

// 8. 视图函数
function render($template, $data = []) {
extract($data);
include "views/$template.php";
}

function showHome() {
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$posts = Post::getAll($page);
$totalPosts = Post::getCount();
$totalPages = ceil($totalPosts / MAX_POSTS_PER_PAGE);

render('home', [
'title' => 'My Blog',
'posts' => $posts,
'currentPage' => $page,
'totalPages' => $totalPages,
'hasNextPage' => $page < $totalPages,
'hasPrevPage' => $page > 1
]);
}

function showLoginForm() {
$error = $_SESSION['login_error'] ?? null;
unset($_SESSION['login_error']);

render('login', [
'title' => 'Login',
'error' => $error
]);
}

function processLogin() {
$email = Utils::sanitizeInput($_POST['email'] ?? '');
$password = $_POST['password'] ?? '';

$user = User::authenticate($email, $password);

if ($user) {
session_start();
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['name'];
Utils::redirect('/');
} else {
session_start();
$_SESSION['login_error'] = "Invalid email or password";
Utils::redirect('/login');
}
}

function showRegistrationForm() {
$errors = $_SESSION['registration_errors'] ?? [];
$formData = $_SESSION['form_data'] ?? [];
unset($_SESSION['registration_errors'], $_SESSION['form_data']);

render('register', [
'title' => 'Register',
'errors' => $errors,
'formData' => $formData
]);
}

function processRegistration() {
$name = Utils::sanitizeInput($_POST['name'] ?? '');
$email = Utils::sanitizeInput($_POST['email'] ?? '');
$password = $_POST['password'] ?? '';
$confirmPassword = $_POST['confirm_password'] ?? '';

$errors = [];
$formData = [
'name' => $name,
'email' => $email
];

if (empty($name)) {
$errors[] = "Name is required";
}

if (empty($email)) {
$errors[] = "Email is required";
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = "Invalid email format";
}

if (empty($password)) {
$errors[] = "Password is required";
} elseif (strlen($password) < 8) {
$errors[] = "Password must be at least 8 characters";
}

if ($password !== $confirmPassword) {
$errors[] = "Passwords do not match";
}

if (empty($errors)) {
try {
$user = new User($name, $email, $password);
$user->save();
Utils::redirect('/login');
} catch (Exception $e) {
$errors[] = "Registration failed: " . $e->getMessage();
}
}

session_start();
$_SESSION['registration_errors'] = $errors;
$_SESSION['form_data'] = $formData;
Utils::redirect('/register');
}

function showPost($id) {
$post = Post::getById($id);

if (!$post) {
show404();
return;
}

// 使用静态缓存获取作者
$author = Utils::cached("user_{$post['author_id']}", function() use ($post) {
return User::getById($post['author_id']);
});

render('post', [
'title' => $post['title'],
'post' => $post,
'author' => $author
]);
}

function showCreateForm() {
session_start();

if (!isset($_SESSION['user_id'])) {
Utils::redirect('/login');
return;
}

$errors = $_SESSION['post_errors'] ?? [];
$formData = $_SESSION['post_data'] ?? [];
unset($_SESSION['post_errors'], $_SESSION['post_data']);

render('create', [
'title' => 'Create New Post',
'errors' => $errors,
'formData' => $formData
]);
}

function processCreatePost() {
session_start();

if (!isset($_SESSION['user_id'])) {
Utils::redirect('/login');
return;
}

$title = Utils::sanitizeInput($_POST['title'] ?? '');
$content = $_POST['content'] ?? '';

$errors = [];
$formData = [
'title' => $title,
'content' => $content
];

if (empty($title)) {
$errors[] = "Title is required";
}

if (empty($content)) {
$errors[] = "Content is required";
}

if (empty($errors)) {
try {
$post = new Post($title, $content, $_SESSION['user_id']);
$post->save();
Utils::redirect('/');
} catch (Exception $e) {
$errors[] = "Error creating post: " . $e->getMessage();
}
}

$_SESSION['post_errors'] = $errors;
$_SESSION['post_data'] = $formData;
Utils::redirect('/create');
}

function showSearchResults() {
$query = Utils::sanitizeInput($_GET['q'] ?? '');

if (empty($query)) {
Utils::redirect('/');
return;
}

// 缓存搜索结果
$searchResults = Utils::cached("search_$query", function() use ($query) {
return Post::search($query);
});

render('search', [
'title' => "Search Results for '$query'",
'query' => $query,
'results' => $searchResults
]);
}

function processLogout() {
session_start();
session_destroy();
Utils::redirect('/');
}

function show404() {
http_response_code(404);
render('404', ['title' => 'Page Not Found']);
}

// 9. 初始化
session_start();

// 10. 创建数据库表(如果不存在)
function initializeDatabase() {
$db = Database::getInstance()->getConnection();

// 创建用户表
$createUsersTable = "CREATE TABLE IF NOT EXISTS users (
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)";
$db->exec($createUsersTable);

// 创建文章表
$createPostsTable = "CREATE TABLE IF NOT EXISTS posts (
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
author_id INT(6) UNSIGNED NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (author_id) REFERENCES users(id) ON DELETE CASCADE
)";
$db->exec($createPostsTable);
}

// 11. 启动应用
initializeDatabase();
handleRequest();

这个综合示例展示了:

  • 命名空间和类组织:使用命名空间组织代码,提高可维护性
  • 静态方法和成员:使用静态方法实现工具类、单例模式和缓存
  • 数据库连接和操作:使用PDO实现安全的数据库操作
  • 用户认证和会话管理:实现登录、注册和会话管理
  • 表单处理和验证:验证用户输入,处理表单错误
  • 路由和控制器逻辑:基于URL和HTTP方法处理请求
  • 视图渲染:分离业务逻辑和展示逻辑
  • 错误处理:捕获和处理异常,提供友好的错误页面
  • 安全措施:输入清理、密码哈希、防止SQL注入
  • 缓存机制:使用静态属性实现简单的缓存
  • 分页功能:实现文章分页显示
  • 搜索功能:实现全文搜索
  • 单例模式:使用静态实例确保数据库连接唯一性
  • 静态工具类:提供各种工具方法,如输入清理、重定向等
  • 对象关系映射:将数据库记录映射为对象
  • 事务处理:确保数据一致性
  • 代码复用:使用静态方法减少代码重复

1. 概述

JavaScript是一种解释型基于对象动态类型的脚本语言,主要用于增强网页的交互性。它与Java没有关系,只是在诞生初期为了借助Java的热度而取了类似的名字。

  • 解释型:不需要编译,由浏览器直接解释执行
  • 基于对象:支持面向对象编程,但没有类的概念(ES6之前)
  • 动态类型:变量类型在运行时确定,无需声明类型

JavaScript主要运行在客户端浏览器中,但随着Node.js的发展,现在也可以在服务器端运行。

为什么需要JavaScript?

  1. 交互性:创建动态网页效果(如表单验证、动画效果)
  2. 异步通信:通过AJAX实现与服务器的异步通信
  3. 操作DOM:动态修改网页内容和结构
  4. 操作BOM:控制浏览器行为(如窗口、历史记录等)

示例

1
2
3
4
5
6
7
8
9
10
11
12
// 简单的JavaScript代码示例
console.log("Hello, JavaScript!");

// 表单验证示例
function validateForm() {
const username = document.getElementById('username').value;
if (username.length < 5) {
alert("用户名至少需要5个字符");
return false;
}
return true;
}

2. 嵌入方法

2.1 内嵌式

详细解释:

  • 将JavaScript代码直接写在HTML文档的<script>标签中
  • 通常放在<head><body>底部
  • 优点:无需额外文件请求,代码与页面紧密结合
  • 缺点:代码难以复用,HTML与JS混合导致维护困难

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>内嵌式示例</title>
<!-- 推荐写法:将脚本放在head中 -->
<script>
// 使用type属性明确指定类型(现代浏览器可省略)
function greet() {
alert("欢迎来到内嵌式JavaScript示例");
}

// 页面加载完成后执行
window.onload = function() {
console.log("页面已加载");
};
</script>
</head>
<body>
<button onclick="greet()">点击我</button>

<!-- 也可以放在body底部 -->
<script>
// 在body底部执行,确保DOM已加载
document.write("这是在body底部添加的内容");
</script>
</body>
</html>

2.2 外链式

详细解释:

  • 将JavaScript代码保存在单独的.js文件中
  • 通过<script src="路径">标签引入
  • 优点:代码复用性高,HTML与JS分离,便于维护
  • 缺点:增加HTTP请求,可能影响页面加载速度

示例:

  1. 创建script.js文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// script.js
function sayHello(name) {
console.log(`你好,${name}!`);
}

// 模块化示例
const Calculator = {
add: function(a, b) {
return a + b;
},
subtract: function(a, b) {
return a - b;
}
};

// 使用立即执行函数表达式(IIFE)避免全局污染
(function() {
const privateVar = "我是私有变量";

function privateFunction() {
console.log("这是私有函数");
}

// 暴露公共接口
window.PublicAPI = {
publicMethod: function() {
console.log("调用公共方法");
privateFunction();
}
};
})();
  1. 在HTML中引入:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>外链式示例</title>
<!-- 引入外部JS文件 -->
<script src="script.js"></script>
<!-- 可以引入多个JS文件 -->
<script src="another-script.js"></script>
</head>
<body>
<button onclick="sayHello('张三')">打招呼</button>
<button onclick="PublicAPI.publicMethod()">调用公共方法</button>

<script>
// 也可以在引入外部文件后继续写内嵌代码
document.addEventListener('DOMContentLoaded', function() {
console.log("DOM已加载");
});
</script>
</body>
</html>

2.3 行内式

详细解释:

  • 直接将JavaScript代码写在HTML元素的事件属性中
  • 通常用于简单的事件处理
  • 优点:简单直接
  • 缺点:代码难以维护,HTML与JS高度耦合

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>行内式示例</title>
</head>
<body>
<!-- 简单的行内事件 -->
<button onclick="alert('你好,世界!')">点击我</button>

<!-- 复杂一点的行内事件 -->
<input type="text" id="username" placeholder="请输入用户名">
<button onclick="
var name = document.getElementById('username').value;
if (name) {
alert('欢迎,' + name + '!');
} else {
alert('请输入用户名');
}
">提交</button>

<!-- 使用事件属性的其他示例 -->
<div onmouseover="this.style.backgroundColor='yellow'"
onmouseout="this.style.backgroundColor='white'"
style="padding: 20px; border: 1px solid #ccc;">
将鼠标移入此区域
</div>

<!-- 不推荐:复杂逻辑不应放在行内 -->
<button onclick="
function calculateSum() {
var a = parseInt(prompt('请输入第一个数字'));
var b = parseInt(prompt('请输入第二个数字'));
if (!isNaN(a) && !isNaN(b)) {
alert('和为: ' + (a + b));
} else {
alert('请输入有效数字');
}
}
calculateSum();
">计算和</button>
</body>
</html>

3. 语句

详细解释

  • JavaScript语句:由值、运算符、表达式、关键词和注释组成的编程指令
  • 执行顺序:从上到下,从左到右
  • 分号:用于分隔JavaScript语句,虽然在大多数情况下可以省略(自动分号插入机制),但强烈建议显式添加

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 基本语句示例
var x = 5; // 声明变量并赋值
var y = 10; // 声明变量并赋值
var z = x + y; // 表达式语句

// 多条语句可以写在同一行(不推荐)
var a = 1, b = 2, c = 3;

// 复合语句(代码块)
{
var message = "Hello";
console.log(message);
}

// 条件语句
if (z > 10) {
console.log("z大于10");
} else {
console.log("z不大于10");
}

// 循环语句
for (var i = 0; i < 5; i++) {
console.log("循环次数: " + i);
}

// 函数声明
function greet(name) {
return "你好," + name + "!";
}

// 函数调用
var greeting = greet("李四");
console.log(greeting);

// 表达式语句
3 + 4; // 有效,但没有实际效果
"Hello"; // 有效,但没有实际效果

// 空语句(分号单独一行)
;

4. 注释

详细解释

  • 单行注释:以//开头,直到行末
  • 多行注释:以/*开头,以*/结尾,可以跨多行
  • 作用:解释代码、临时禁用代码、文档生成
  • 最佳实践:保持注释简洁、准确,与代码同步更新

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// 单行注释示例
// 计算两个数的和
function add(a, b) {
return a + b; // 返回a和b的和
}

// 多行注释示例
/*
* 函数:calculateAverage
* 用途:计算数组中所有元素的平均值
* 参数:
* numbers - 数字数组
* 返回值:
* 平均值(如果数组为空,返回0)
*/
function calculateAverage(numbers) {
if (numbers.length === 0) {
return 0;
}

var sum = 0;
for (var i = 0; i < numbers.length; i++) {
sum += numbers[i];
}

return sum / numbers.length;
}

// 临时禁用代码
function exampleFunction() {
console.log("这段代码会执行");

/*
console.log("这段代码被注释了,不会执行");
var temp = "临时变量";
console.log(temp);
*/

// 也可以用单行注释禁用单行代码
// console.log("这行也被禁用了");
}

// 文档注释(JSDoc风格)
/**
* 创建一个用户对象
* @param {string} name - 用户名
* @param {number} age - 用户年龄
* @returns {object} 包含用户信息的对象
*/
function createUser(name, age) {
return {
name: name,
age: age,
greet: function() {
console.log("你好," + this.name);
}
};
}

// 注意:多行注释不能嵌套
/*
这是外层注释
/*
这是内层注释 - 会导致语法错误
*/
*/

5. 变量

详细解释

  • 变量:用于存储信息的”容器”
  • 命名规则
    • 只能包含字母、数字、下划线和美元符号
    • 不能以数字开头
    • 区分大小写
    • 不能使用JavaScript保留关键字
  • 声明方式
    • var:ES5及之前,函数作用域
    • let:ES6,块级作用域,可重新赋值
    • const:ES6,块级作用域,不可重新赋值

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// var 声明(函数作用域)
var globalVar = "全局变量";
function testVar() {
var functionVar = "函数内变量";
if (true) {
var blockVar = "块级变量";
}
console.log(blockVar); // 可以访问,因为var没有块级作用域
}
testVar();
console.log(globalVar); // 可以访问
// console.log(functionVar); // 错误:functionVar is not defined

// let 声明(块级作用域)
function testLet() {
let functionLet = "函数内变量";
if (true) {
let blockLet = "块级变量";
console.log(blockLet); // 可以访问
}
// console.log(blockLet); // 错误:blockLet is not defined
}
testLet();

// const 声明(常量)
const PI = 3.14159;
const USER = {
name: "张三",
age: 25
};

// 基本数据类型不可变
// PI = 3.14; // 错误:Assignment to constant variable

// 对象属性可以修改
USER.age = 26;
console.log(USER); // { name: "张三", age: 26 }

// 声明变量并赋值
var a = 10;
let b = "Hello";
const c = true;

// 多变量声明
var x = 1, y = 2, z = 3;
let m = 4, n = 5;
const p = 6, q = 7;

// 未初始化的变量
var uninitialized;
console.log(uninitialized); // undefined

// 变量提升示例
console.log(hoistedVar); // undefined(变量提升,但未初始化)
var hoistedVar = "我被提升了";

// console.log(notHoistedLet); // 错误:Cannot access 'notHoistedLet' before initialization
let notHoistedLet = "我不会被提升";

6. JavaScript保留关键字

详细解释

  • 保留关键字:JavaScript中保留的特殊单词,不能用作变量名、函数名或标签名
  • 原因:这些关键字可能在当前或未来版本中具有特殊含义
  • 重要性:使用保留关键字会导致语法错误

常见保留关键字

1
2
3
4
5
6
abstract, arguments, boolean, break, byte, case, catch, char, class, const, continue, 
debugger, default, delete, do, double, else, enum, eval, export, extends, false, final,
finally, float, for, function, goto, if, implements, import, in, instanceof, int, interface,
let, long, native, new, null, package, private, protected, public, return, short, static,
super, switch, synchronized, this, throw, throws, transient, true, try, typeof, var, void,
volatile, while, with, yield

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 错误示例:使用保留关键字作为变量名
// var function = "test"; // 语法错误
// var class = "math"; // 语法错误
// var const = 10; // 语法错误

// 正确示例:避免使用保留关键字
var funcName = "test";
var className = "math";
var constantValue = 10;

// 使用保留关键字作为对象属性(ES6+允许)
var obj = {
function: "test",
class: "math",
const: 10
};
console.log(obj.function); // "test"

// 保留关键字在特定上下文中可用
function example() {
var arguments = "local"; // 不推荐,会覆盖函数的arguments对象
console.log(arguments); // "local" 而不是参数对象
}
example("test");

// 未来保留关键字(可能在将来版本中使用)
// var let = 5; // 在ES6+中是语法错误
// var yield = 10; // 在ES6+中是语法错误

7. JavaScript作用域

7.1 局部变量

详细解释:

  • 定义:在函数内部声明的变量
  • 作用域:仅在声明它的函数内部可访问
  • 生命周期:函数调用开始时创建,函数执行结束时销毁
  • 特点:每次函数调用都会创建新的局部变量

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
function calculate() {
// 局部变量
var result = 0;
let sum = 0;
const PI = 3.14;

for (let i = 0; i < 10; i++) {
// i也是局部变量(块级作用域)
sum += i;
}

result = sum * PI;

console.log("i:", i); // 错误:i is not defined(i只在for循环块内有效)
console.log("sum:", sum); // 45
console.log("result:", result); // 141.3

return result;
}

calculate();
// console.log(result); // 错误:result is not defined
// console.log(sum); // 错误:sum is not defined
// console.log(PI); // 错误:PI is not defined

// 局部变量与全局变量同名
var message = "全局消息";

function showMessage() {
var message = "局部消息";
console.log(message); // "局部消息"
}

showMessage();
console.log(message); // "全局消息"

// 函数参数也是局部变量
function greet(name) {
console.log("你好," + name + "!");
name = "修改后的" + name;
console.log("修改后:" + name);
}

greet("张三");
// console.log(name); // 错误:name is not defined

7.2 全局变量

详细解释:

  • 定义:在函数外部声明的变量,或未使用var/let/const声明的变量
  • 作用域:在整个程序中可访问
  • 生命周期:从声明开始直到页面关闭
  • 特点:容易造成命名冲突,应谨慎使用

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// 全局变量声明
var globalVar = "全局变量";
let globalLet = "全局let变量";
const GLOBAL_CONST = "全局常量";

function testScope() {
console.log(globalVar); // "全局变量"
console.log(globalLet); // "全局let变量"
console.log(GLOBAL_CONST); // "全局常量"

// 修改全局变量
globalVar = "修改后的全局变量";
globalLet = "修改后的全局let变量";
// GLOBAL_CONST = "修改"; // 错误:Assignment to constant variable
}

testScope();
console.log(globalVar); // "修改后的全局变量"
console.log(globalLet); // "修改后的全局let变量"

// 未声明的变量会成为全局变量(不推荐)
function createGlobal() {
undeclaredVar = "我是全局变量";
}

createGlobal();
console.log(undeclaredVar); // "我是全局变量"

// 全局对象属性
window.myGlobal = "通过window对象创建的全局变量";
console.log(myGlobal); // "通过window对象创建的全局变量"

// 全局变量与局部变量同名
var conflict = "全局";

function conflictExample() {
var conflict = "局部";
console.log(conflict); // "局部"
}

conflictExample();
console.log(conflict); // "全局"

// 避免全局变量污染的IIFE模式
(function() {
var privateVar = "私有变量";

function privateFunc() {
console.log("私有函数");
}

// 暴露公共接口
window.PublicAPI = {
publicMethod: function() {
console.log("公共方法");
privateFunc();
}
};
})();

// console.log(privateVar); // 错误:privateVar is not defined
PublicAPI.publicMethod(); // "公共方法" + "私有函数"

8. 数据类型

8.1 基本数据类型

8.1.1 数值型(Number)

详细解释:

  • 所有数字都是number类型,不分整数和浮点数
  • 支持十进制、八进制、十六进制表示法
  • 特殊值:NaN(非数字)、Infinity(无穷大)
  • 最大安全整数:Number.MAX_SAFE_INTEGER(2^53 - 1)
  • 最小安全整数:Number.MIN_SAFE_INTEGER(-(2^53 - 1))

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// 十进制
var decimal = 42;
console.log(typeof decimal); // "number"

// 浮点数
var float = 3.14159;
console.log(typeof float); // "number"

// 科学计数法
var scientific = 1.23e5; // 123000
console.log(scientific); // 123000

// 八进制(以0开头,ES5严格模式下无效)
var octal = 0755; // 493
console.log(octal); // 493

// 十六进制(以0x开头)
var hex = 0xFF; // 255
console.log(hex); // 255

// 二进制(ES6+,以0b开头)
var binary = 0b1010; // 10
console.log(binary); // 10

// 特殊值
console.log(0 / 0); // NaN
console.log(1 / 0); // Infinity
console.log(-1 / 0); // -Infinity

// 检测NaN
console.log(isNaN(NaN)); // true
console.log(isNaN("abc")); // true
console.log(isNaN(123)); // false

// 检测有限数
console.log(isFinite(123)); // true
console.log(isFinite(Infinity)); // false

// 转换为数字
console.log(parseInt("123")); // 123
console.log(parseInt("123.45")); // 123
console.log(parseInt("abc123")); // NaN
console.log(parseInt("123abc")); // 123

console.log(parseFloat("123.45")); // 123.45
console.log(parseFloat("123")); // 123

// 数字方法
var num = 123.456;
console.log(num.toFixed(2)); // "123.46"(保留2位小数)
console.log(num.toPrecision(4)); // "123.5"(保留4位有效数字)
console.log(num.toString()); // "123.456"
console.log(num.toString(16)); // "7b.74bc6a7ef9db2"(十六进制表示)

8.1.2 字符串型(String)

详细解释:

  • 用单引号或双引号包裹的文本
  • 字符串是不可变的(修改会创建新字符串)
  • 支持转义字符(如\n\t
  • 模板字符串(ES6+):使用反引号(`)创建,支持多行和变量插值

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// 单引号和双引号
var single = '单引号字符串';
var double = "双引号字符串";
console.log(typeof single); // "string"
console.log(typeof double); // "string"

// 转义字符
var escaped = "第一行\n第二行\t制表符";
console.log(escaped);

// 模板字符串(ES6+)
var name = "张三";
var age = 25;
var template = `你好,${name}!你今年${age}岁。`;
console.log(template); // "你好,张三!你今年25岁。"

// 多行字符串
var multiLine = `这是第一行
这是第二行
这是第三行`;
console.log(multiLine);

// 字符串方法
var str = "Hello, JavaScript!";

console.log(str.length); // 17
console.log(str.charAt(0)); // "H"
console.log(str.charCodeAt(0)); // 72(Unicode编码)
console.log(str.concat(", World!")); // "Hello, JavaScript!, World!"

console.log(str.indexOf("Java")); // 7
console.log(str.lastIndexOf("a")); // 14

console.log(str.substring(7, 13)); // "JavaSc"
console.log(str.slice(7, 13)); // "JavaSc"
console.log(str.slice(-6)); // "ript!"

console.log(str.toLowerCase()); // "hello, javascript!"
console.log(str.toUpperCase()); // "HELLO, JAVASCRIPT!"

console.log(str.trim()); // 移除两端空白
console.log(" Hello ".trimLeft()); // "Hello "
console.log(" Hello ".trimRight()); // " Hello"

console.log(str.split(" ")); // ["Hello,", "JavaScript!"]

// 正则表达式相关方法
console.log(str.search(/Java/)); // 7
console.log(str.match(/[a-z]+/g)); // ["ello", "ava", "cript"]
console.log(str.replace(/JavaScript/, "World")); // "Hello, World!"

// 包含检查(ES6+)
console.log(str.includes("Java")); // true
console.log(str.startsWith("Hello")); // true
console.log(str.endsWith("!")); // true

// 重复字符串(ES6+)
console.log("x".repeat(3)); // "xxx"

8.1.3 布尔型(Boolean)

详细解释:

  • 只有两个值:truefalse
  • 用于条件判断和逻辑运算
  • 在条件语句中,其他类型会隐式转换为布尔值

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// 布尔值
var isTrue = true;
var isFalse = false;
console.log(typeof isTrue); // "boolean"

// 比较运算
console.log(5 > 3); // true
console.log(5 < 3); // false
console.log(5 == 5); // true
console.log(5 != 3); // true

// 严格相等(值和类型都相等)
console.log(5 === 5); // true
console.log(5 === "5"); // false
console.log(5 !== "5"); // true

// 逻辑运算
console.log(true && true); // true
console.log(true && false); // false
console.log(true || false); // true
console.log(false || false); // false
console.log(!true); // false

// 短路求值
function logMessage() {
console.log("函数被调用");
return true;
}

// 第二个表达式不会执行
true || logMessage(); // 只输出"函数被调用"
false && logMessage(); // 只输出"函数被调用"

// 隐式类型转换
console.log(Boolean(0)); // false
console.log(Boolean(1)); // true
console.log(Boolean("")); // false
console.log(Boolean("Hello")); // true
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean({})); // true
console.log(Boolean([])); // true

// 在条件语句中的应用
var value = 0;
if (value) {
console.log("value为真");
} else {
console.log("value为假"); // 输出
}

// 三元运算符
var result = (5 > 3) ? "大于" : "小于";
console.log(result); // "大于"

8.1.4 null(空值)

详细解释:

  • 表示”无”或”空”的特殊值
  • 通常用于表示对象引用为空
  • typeof null返回"object"(历史遗留问题)

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// null的使用
var empty = null;
console.log(empty); // null
console.log(typeof empty); // "object"(历史遗留问题)

// 表示对象引用为空
var user = {
name: "张三",
address: null // 表示地址信息为空
};

// 检查null
console.log(empty === null); // true
console.log(empty == null); // true

// null与undefined的区别
console.log(null == undefined); // true(宽松相等)
console.log(null === undefined); // false(严格相等)

// 使用场景
function findUser(id) {
// 模拟查找用户
if (id === 1) {
return { id: 1, name: "张三" };
} else {
return null; // 表示未找到用户
}
}

var user1 = findUser(1);
var user2 = findUser(2);

console.log(user1); // { id: 1, name: "张三" }
console.log(user2); // null

if (user2 === null) {
console.log("用户未找到");
}

8.1.5 undefined(未定义)

详细解释:

  • 表示变量已声明但未赋值
  • 函数没有返回值时的默认返回值
  • 未定义的属性或方法
  • typeof undefined返回"undefined"

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// 未初始化的变量
var uninitialized;
console.log(uninitialized); // undefined
console.log(typeof uninitialized); // "undefined"

// 函数没有返回值
function noReturn() {
// 没有return语句
}
var result = noReturn();
console.log(result); // undefined

// 未定义的属性
var obj = {};
console.log(obj.property); // undefined

// 检查undefined
console.log(typeof uninitialized === "undefined"); // true
console.log(uninitialized === undefined); // true
console.log(uninitialized == undefined); // true

// 与null的区别
console.log(null == undefined); // true
console.log(null === undefined); // false

// 使用场景
function getUser(id) {
if (id === 1) {
return { id: 1, name: "张三" };
}
// 没有return,返回undefined
}

var user1 = getUser(1);
var user2 = getUser(2);

console.log(user1); // { id: 1, name: "张三" }
console.log(user2); // undefined

if (user2 === undefined) {
console.log("用户未找到");
}

// 作为函数参数的默认值
function greet(name = "访客") {
console.log("你好," + name + "!");
}

greet(); // "你好,访客!"
greet("张三"); // "你好,张三!"

8.2 复合数据类型

8.2.1 对象(Object)

详细解释:

  • 用于存储键值对的集合
  • 无序的数据结构
  • 通过属性和方法组织数据
  • 所有非基本类型都是对象(包括数组、函数等)

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// 创建对象的多种方式
var obj1 = {}; // 对象字面量

var obj2 = {
name: "张三",
age: 25,
sayHello: function() {
console.log("你好," + this.name);
}
};

var obj3 = new Object();
obj3.name = "李四";
obj3.age = 30;
obj3.sayHello = function() {
console.log("你好," + this.name);
};

// 访问属性
console.log(obj2.name); // "张三"
console.log(obj2["age"]); // 25

// 修改属性
obj2.age = 26;
obj2["name"] = "王五";

// 添加新属性
obj2.gender = "男";
obj2["city"] = "北京";

// 删除属性
delete obj2.city;

// 对象方法
obj2.sayHello(); // "你好,王五!"

// 检查属性是否存在
console.log("name" in obj2); // true
console.log(obj2.hasOwnProperty("age")); // true

// 遍历对象属性
for (var key in obj2) {
if (obj2.hasOwnProperty(key)) {
console.log(key + ": " + obj2[key]);
}
}

// 对象方法
var person = {
firstName: "张",
lastName: "三",
getFullName: function() {
return this.firstName + this.lastName;
},
setFullName: function(fullName) {
var names = fullName.split("");
this.firstName = names[0];
this.lastName = names.slice(1).join("");
}
};

console.log(person.getFullName()); // "张三"
person.setFullName("李四");
console.log(person.getFullName()); // "李四"

// 对象拷贝
var original = { a: 1, b: 2 };
var shallowCopy = Object.assign({}, original);
var deepCopy = JSON.parse(JSON.stringify(original));

8.2.2 数组(Array)

详细解释:

  • 用于存储有序的元素集合
  • 元素可以是任意数据类型
  • 通过索引访问元素(从0开始)
  • 动态大小,可以随时添加或删除元素

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// 创建数组的多种方式
var arr1 = []; // 空数组
var arr2 = [1, "Hello", true, { name: "张三" }, [1, 2, 3]];
var arr3 = new Array(); // 空数组
var arr4 = new Array(1, 2, 3); // [1, 2, 3]
var arr5 = new Array(5); // 长度为5的空数组

// 访问元素
console.log(arr2[0]); // 1
console.log(arr2[1]); // "Hello"
console.log(arr2[arr2.length - 1]); // [1, 2, 3]

// 修改元素
arr2[0] = 10;
arr2[4][0] = 100;

// 添加元素
arr2.push("新元素"); // 末尾添加
arr2.unshift("开头元素"); // 开头添加

// 删除元素
var last = arr2.pop(); // 删除末尾元素
var first = arr2.shift(); // 删除开头元素

// 查找元素
console.log(arr2.indexOf("Hello")); // 1
console.log(arr2.includes("Hello")); // true

// 遍历数组
for (var i = 0; i < arr2.length; i++) {
console.log(arr2[i]);
}

arr2.forEach(function(item, index) {
console.log(index + ": " + item);
});

// 数组方法
var numbers = [1, 2, 3, 4, 5];

console.log(numbers.length); // 5

// 添加/删除元素
numbers.push(6); // [1,2,3,4,5,6]
numbers.pop(); // [1,2,3,4,5]
numbers.unshift(0); // [0,1,2,3,4,5]
numbers.shift(); // [1,2,3,4,5]

// 插入/替换/删除元素
numbers.splice(2, 0, 2.5); // 在索引2处插入2.5
numbers.splice(2, 1, 2.6); // 替换索引2处的元素
numbers.splice(2, 1); // 删除索引2处的元素

// 切片
var slice = numbers.slice(1, 3); // [2,3]

// 排序
var unsorted = [3, 1, 4, 2];
unsorted.sort(function(a, b) {
return a - b;
});
console.log(unsorted); // [1,2,3,4]

// 连接数组
var combined = numbers.concat([6, 7, 8]);

// 转换为字符串
console.log(numbers.join(", ")); // "1, 2, 3, 4, 5"

// 高阶函数
var doubled = numbers.map(function(num) {
return num * 2;
});

var even = numbers.filter(function(num) {
return num % 2 === 0;
});

var sum = numbers.reduce(function(acc, num) {
return acc + num;
}, 0);

9. 函数

9.1 函数定义与调用

详细解释:

  • 函数声明:使用function关键字定义
  • 函数表达式:将函数赋值给变量
  • 调用:使用函数名加括号,可传递参数
  • 返回值:使用return语句,未返回则默认返回undefined

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 函数声明
function add(a, b) {
return a + b;
}

// 函数表达式
var subtract = function(a, b) {
return a - b;
};

// 调用函数
console.log(add(5, 3)); // 8
console.log(subtract(5, 3)); // 2

// 带默认参数的函数(ES6+)
function multiply(a, b = 1) {
return a * b;
}
console.log(multiply(5)); // 5
console.log(multiply(5, 2)); // 10

// 剩余参数(ES6+)
function sum(...numbers) {
return numbers.reduce((acc, num) => acc + num, 0);
}
console.log(sum(1, 2, 3, 4)); // 10

// 展开运算符(ES6+)
var nums = [1, 2, 3, 4];
console.log(sum(...nums)); // 10

// 函数作为参数
function operate(a, b, operation) {
return operation(a, b);
}
console.log(operate(5, 3, add)); // 8
console.log(operate(5, 3, subtract)); // 2

// 自调用函数表达式(IIFE)
(function() {
console.log("这个函数立即执行");
})();

// 带参数的IIFE
(function(name) {
console.log("你好," + name + "!");
})("张三");

9.2 匿名函数

详细解释:

  • 没有函数名的函数
  • 通常作为回调函数使用
  • 用于创建立即执行函数表达式(IIFE)

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 作为回调函数
document.getElementById("btn").addEventListener("click", function() {
alert("按钮被点击");
});

// 作为定时器回调
setTimeout(function() {
console.log("2秒后执行");
}, 2000);

// 作为数组方法的参数
var numbers = [1, 2, 3, 4];
var doubled = numbers.map(function(num) {
return num * 2;
});

// 匿名函数赋值给变量
var greet = function(name) {
console.log("你好," + name + "!");
};
greet("李四");

// IIFE(立即执行函数表达式)
(function() {
var privateVar = "私有变量";
console.log("IIFE执行");
})();

// 带参数的IIFE
(function(name) {
console.log("你好," + name);
})("王五");

// 作为返回值
function createMultiplier(factor) {
return function(number) {
return number * factor;
};
}
var double = createMultiplier(2);
var triple = createMultiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15

10. 字典(对象作为字典使用)

详细解释:

  • JavaScript中没有专门的”字典”类型
  • 通常使用对象来模拟字典(键值对存储)
  • 键必须是字符串或Symbol类型
  • 通过属性访问或Object.keys()等方法遍历

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// 创建字典
var dictionary = {
"apple": "苹果",
"banana": "香蕉",
"orange": "橙子"
};

// 访问值
console.log(dictionary.apple); // "苹果"
console.log(dictionary["banana"]); // "香蕉"

// 添加新项
dictionary.grape = "葡萄";
dictionary["mango"] = "芒果";

// 修改值
dictionary.apple = "红苹果";

// 删除项
delete dictionary.orange;
// 或
delete dictionary["banana"];

// 检查键是否存在
console.log("apple" in dictionary); // true
console.log(dictionary.hasOwnProperty("banana")); // false

// 遍历字典
for (var key in dictionary) {
if (dictionary.hasOwnProperty(key)) {
console.log(key + ": " + dictionary[key]);
}
}

// 获取所有键
var keys = Object.keys(dictionary);
console.log(keys); // ["grape", "mango", "apple"]

// 获取所有值
var values = Object.values(dictionary);
console.log(values); // ["葡萄", "芒果", "红苹果"]

// 获取键值对数组
var entries = Object.entries(dictionary);
console.log(entries); // [["grape", "葡萄"], ["mango", "芒果"], ["apple", "红苹果"]]

// 使用Map(ES6+,更强大的字典结构)
var map = new Map();
map.set("apple", "苹果");
map.set("banana", "香蕉");

console.log(map.get("apple")); // "苹果"
console.log(map.has("banana")); // true
map.delete("banana");
console.log(map.size); // 1

// 遍历Map
map.forEach(function(value, key) {
console.log(key + ": " + value);
});

for (var [key, value] of map) {
console.log(key + ": " + value);
}

11. JavaScript序列化与反序列化

详细解释:

  • 序列化:将JavaScript对象转换为字符串
  • 反序列化:将字符串转换回JavaScript对象
  • 主要使用JSON对象的stringifyparse方法
  • JSON(JavaScript Object Notation)是一种轻量级数据交换格式

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// 创建对象
var user = {
name: "张三",
age: 25,
address: {
city: "北京",
street: "中关村"
},
hobbies: ["编程", "阅读", "运动"]
};

// 序列化为JSON字符串
var jsonString = JSON.stringify(user);
console.log(jsonString);
// {"name":"张三","age":25,"address":{"city":"北京","street":"中关村"},"hobbies":["编程","阅读","运动"]}

// 序列化时格式化输出
var formattedJson = JSON.stringify(user, null, 2);
console.log(formattedJson);
/*
{
"name": "张三",
"age": 25,
"address": {
"city": "北京",
"street": "中关村"
},
"hobbies": [
"编程",
"阅读",
"运动"
]
}
*/

// 序列化时过滤属性
var filteredJson = JSON.stringify(user, ["name", "age"]);
console.log(filteredJson); // {"name":"张三","age":25}

// 自定义序列化
var customJson = JSON.stringify(user, function(key, value) {
if (key === "age") {
return value + "岁";
}
return value;
});
console.log(customJson); // {"name":"张三","age":"25岁",...}

// 反序列化
var parsedUser = JSON.parse(jsonString);
console.log(parsedUser.name); // "张三"
console.log(parsedUser.address.city); // "北京"

// 反序列化时转换值
var transformedUser = JSON.parse(jsonString, function(key, value) {
if (key === "age") {
return value + "岁";
}
return value;
});
console.log(transformedUser.age); // "25岁"

// 序列化函数
var objWithFunction = {
name: "测试",
func: function() { return "Hello"; }
};

console.log(JSON.stringify(objWithFunction));
// {"name":"测试"} - 函数被忽略

// 序列化日期对象
var objWithDate = {
date: new Date()
};

console.log(JSON.stringify(objWithDate));
// {"date":"2023-10-15T08:30:00.000Z"}

// 自定义日期序列化
var customDateJson = JSON.stringify(objWithDate, function(key, value) {
if (value instanceof Date) {
return value.toISOString().split('T')[0];
}
return value;
});
console.log(customDateJson); // {"date":"2023-10-15"}

12. 转义与编码

详细解释:

  • 转义:将特殊字符转换为安全表示形式
  • URL编码:将URL中的特殊字符转换为%xx格式
  • 常用方法:
    • encodeURI():编码整个URI
    • encodeURIComponent():编码URI的组件
    • decodeURI():解码URI
    • decodeURIComponent():解码URI组件

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// URI编码
var uri = "https://example.com/search?q=JavaScript 基础";
console.log(encodeURI(uri));
// "https://example.com/search?q=JavaScript%20%E5%9F%BA%E7%A1%80"

var component = "JavaScript 基础";
console.log(encodeURIComponent(component));
// "JavaScript%20%E5%9F%BA%E7%A1%80"

// URI解码
var encodedUri = "https://example.com/search?q=JavaScript%20%E5%9F%BA%E7%A1%80";
console.log(decodeURI(encodedUri));
// "https://example.com/search?q=JavaScript 基础"

var encodedComponent = "JavaScript%20%E5%9F%BA%E7%A1%80";
console.log(decodeURIComponent(encodedComponent));
// "JavaScript 基础"

// 转义HTML特殊字符
function escapeHtml(str) {
return str.replace(/[&<>"']/g, function(match) {
var escapeMap = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;'
};
return escapeMap[match];
});
}

console.log(escapeHtml('<div class="test">Hello & World</div>'));
// "&lt;div class=&quot;test&quot;&gt;Hello &amp; World&lt;/div&gt;"

// 反转义HTML特殊字符
function unescapeHtml(str) {
var htmlEntities = {
'&amp;': '&',
'&lt;': '<',
'&gt;': '>',
'&quot;': '"',
'&#39;': "'"
};
return str.replace(/&(#?)(\w+);/g, function(match, hash, name) {
return htmlEntities[match] || match;
});
}

console.log(unescapeHtml("&lt;div class=&quot;test&quot;&gt;Hello &amp; World&lt;/div&gt;"));
// "<div class="test">Hello & World</div>"

// Base64编码与解码
var str = "Hello, JavaScript!";
var base64 = btoa(str);
console.log(base64); // "SGVsbG8sIEphdmFTY3JpcHQh"
var decoded = atob(base64);
console.log(decoded); // "Hello, JavaScript!"

// URL安全的Base64编码
function urlSafeBase64(str) {
return btoa(str)
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');
}

function urlSafeBase64Decode(str) {
str = str.replace(/-/g, '+').replace(/_/g, '/');
while (str.length % 4) str += '=';
return atob(str);
}

var safeBase64 = urlSafeBase64("Hello, JavaScript!");
console.log(safeBase64); // "SGVsbG8sIEphdmFTY3JpcHQh"
console.log(urlSafeBase64Decode(safeBase64)); // "Hello, JavaScript!"

13. eval

详细解释:

  • eval():执行传入的字符串作为JavaScript代码
  • 风险:可能执行恶意代码,造成安全漏洞
  • 替代方案:尽可能使用更安全的方法(如JSON.parse)

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// 基本用法
eval("var x = 10;");
console.log(x); // 10

var result = eval("2 + 3 * 4");
console.log(result); // 14

// 执行函数
eval("function greet(name) { return 'Hello, ' + name; }");
console.log(greet("张三")); // "Hello, 张三"

// 执行JSON字符串(不安全,应使用JSON.parse)
var jsonStr = '{"name": "张三", "age": 25}';
var obj = eval("(" + jsonStr + ")");
console.log(obj.name); // "张三"

// 作用域示例
function testEval() {
eval("var y = 20;");
console.log(y); // 20
}
testEval();
// console.log(y); // 错误:y is not defined

// 安全风险示例(不要在实际代码中使用)
function unsafeFunction(input) {
// 如果input是"alert('XSS攻击')",将执行恶意代码
eval(input);
}

// 安全替代方案
function safeFunction(jsonStr) {
try {
return JSON.parse(jsonStr);
} catch (e) {
console.error("无效的JSON");
return null;
}
}

// 动态创建函数(比eval更安全)
var func = new Function("a", "b", "return a + b;");
console.log(func(5, 3)); // 8

// 使用Function构造函数的注意事项
var userInput = "alert('XSS')";
var safeFunc = new Function("input", "console.log(input);");
safeFunc(userInput); // 安全地输出字符串,不会执行代码

14. 日期与时间

详细解释:

  • Date对象:用于处理日期和时间
  • 支持多种创建方式:当前时间、指定时间、时间戳
  • 提供丰富的方法获取和设置日期时间组件
  • 时区处理:默认使用本地时区

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// 创建Date对象
var now = new Date(); // 当前日期时间
console.log(now); // 例如:Sun Oct 15 2023 14:30:00 GMT+0800 (中国标准时间)

var specificDate = new Date(2023, 9, 15, 14, 30, 0); // 2023-10-15 14:30:00
// 注意:月份从0开始(0=1月,9=10月)

var timestamp = new Date(1697323800000); // 从时间戳创建
console.log(timestamp);

var dateString = new Date("2023-10-15T14:30:00"); // 从ISO 8601字符串创建
console.log(dateString);

// 获取日期时间组件
console.log(now.getFullYear()); // 年份(4位)
console.log(now.getMonth() + 1); // 月份(0-11,需+1)
console.log(now.getDate()); // 日期(1-31)
console.log(now.getDay()); // 星期(0-6,0=星期日)
console.log(now.getHours()); // 小时(0-23)
console.log(now.getMinutes()); // 分钟(0-59)
console.log(now.getSeconds()); // 秒(0-59)
console.log(now.getMilliseconds()); // 毫秒(0-999)
console.log(now.getTime()); // 时间戳(从1970-01-01 00:00:00 UTC)

// 设置日期时间组件
var date = new Date();
date.setFullYear(2024);
date.setMonth(0); // 1月
date.setDate(1);
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
console.log(date); // 2024-01-01 00:00:00

// 日期计算
var today = new Date();
var tomorrow = new Date(today);
tomorrow.setDate(tomorrow.getDate() + 1);
console.log("明天:", tomorrow);

var nextWeek = new Date(today);
nextWeek.setDate(nextWeek.getDate() + 7);
console.log("下周:", nextWeek);

// 日期格式化
function formatDate(date) {
var year = date.getFullYear();
var month = (date.getMonth() + 1).toString().padStart(2, '0');
var day = date.getDate().toString().padStart(2, '0');
return `${year}-${month}-${day}`;
}

console.log(formatDate(new Date())); // 例如:2023-10-15

// 时间差计算
var start = new Date();
// 模拟一些操作
for (var i = 0; i < 1000000; i++) {
// 空操作
}
var end = new Date();
var duration = end - start;
console.log(`操作耗时: ${duration} 毫秒`);

// 时区处理
console.log(now.toISOString()); // ISO 8601格式(UTC时间)
console.log(now.toLocaleString()); // 本地化格式
console.log(now.toLocaleDateString()); // 本地化日期
console.log(now.toLocaleTimeString()); // 本地化时间

15. 面向对象编程

15.1 构造函数模式

详细解释:

  • 使用函数作为构造函数
  • 通过new关键字创建实例
  • this指向新创建的对象
  • 通过原型添加共享方法

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// 构造函数
function Person(name, age) {
// 属性
this.name = name;
this.age = age;

// 方法(不推荐,每个实例都有独立副本)
this.greet = function() {
console.log(`你好,${this.name}!`);
};
}

// 创建实例
var person1 = new Person("张三", 25);
var person2 = new Person("李四", 30);

person1.greet(); // 你好,张三!
person2.greet(); // 你好,李四!

// 问题:greet方法在每个实例中都有独立副本
console.log(person1.greet === person2.greet); // false

// 通过原型添加共享方法
Person.prototype.sayAge = function() {
console.log(`${this.name}的年龄是${this.age}岁`);
};

person1.sayAge(); // 张三的年龄是25岁
person2.sayAge(); // 李四的年龄是30岁

// 检查方法是否共享
console.log(person1.sayAge === person2.sayAge); // true

// 继承示例
function Student(name, age, studentId) {
// 调用父构造函数
Person.call(this, name, age);
this.studentId = studentId;
}

// 设置原型链
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;

// 添加学生特有方法
Student.prototype.study = function() {
console.log(`${this.name}正在学习`);
};

var student1 = new Student("王五", 20, "S12345");
student1.greet(); // 你好,王五!
student1.sayAge(); // 王五的年龄是20岁
student1.study(); // 王五正在学习

// 检查继承关系
console.log(student1 instanceof Student); // true
console.log(student1 instanceof Person); // true
console.log(student1 instanceof Object); // true

15.2 ES6类语法

详细解释:

  • 使用class关键字定义类
  • 更简洁的语法,但底层仍是原型继承
  • 支持构造函数、方法、静态方法、继承
  • 语法糖,与构造函数模式本质相同

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// 类定义
class Person {
// 构造函数
constructor(name, age) {
this.name = name;
this.age = age;
}

// 实例方法
greet() {
console.log(`你好,${this.name}!`);
}

// 获取器
get ageInMonths() {
return this.age * 12;
}

// 设置器
set nickname(value) {
this._nickname = value;
}

get nickname() {
return this._nickname || this.name;
}

// 静态方法
static createAnonymous() {
return new Person("匿名用户", 0);
}
}

// 创建实例
var person1 = new Person("张三", 25);
person1.greet(); // 你好,张三!
console.log(person1.ageInMonths); // 300
person1.nickname = "小张";
console.log(person1.nickname); // "小张"

// 静态方法调用
var anonymous = Person.createAnonymous();
anonymous.greet(); // 你好,匿名用户!

// 继承
class Student extends Person {
constructor(name, age, studentId) {
super(name, age);
this.studentId = studentId;
}

study() {
console.log(`${this.name}正在学习,学号:${this.studentId}`);
}

// 重写父类方法
greet() {
super.greet();
console.log(`我是学生,学号:${this.studentId}`);
}
}

var student1 = new Student("李四", 20, "S12345");
student1.greet();
// 你好,李四!
// 我是学生,学号:S12345
student1.study(); // 李四正在学习,学号:S12345

// 检查继承关系
console.log(student1 instanceof Student); // true
console.log(student1 instanceof Person); // true

// 类表达式
var Animal = class {
constructor(name) {
this.name = name;
}

speak() {
console.log(`${this.name}发出声音`);
}
};

var dog = new Animal("狗");
dog.speak(); // 狗发出声音

16. 原型

16.1 原型的基本概念

详细解释:

  • 原型:JavaScript中实现继承的机制
  • 每个函数都有prototype属性,指向原型对象
  • 每个对象都有__proto__属性,指向其构造函数的原型
  • 当访问对象属性时,如果对象本身没有,会沿着原型链查找
  • 原型链最终指向Object.prototype,再往上是null

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 原型基本概念
function Person(name) {
this.name = name;
}

// 添加原型方法
Person.prototype.greet = function() {
console.log(`你好,${this.name}!`);
};

// 创建实例
var person1 = new Person("张三");
var person2 = new Person("李四");

// 检查原型
console.log(person1.__proto__ === Person.prototype); // true
console.log(Person.prototype.constructor === Person); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true

// 使用原型方法
person1.greet(); // 你好,张三!
person2.greet(); // 你好,李四!

// 检查方法是否共享
console.log(person1.greet === person2.greet); // true

16.2 原型与类的联系

16.2.1 类与原型的基本关系

详细解释:

  • ES6的class只是原型继承的语法糖,它让开发者可以用更熟悉、更面向对象的方式编写代码,但底层仍然基于原型链实现。
  • 类中定义的方法会被添加到构造函数的原型对象上,所有实例共享这些方法。
  • 类的prototype属性指向原型对象,与构造函数的prototype相同。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// ES6 class写法
class Person {
constructor(name) {
this.name = name;
}

greet() {
console.log(`Hello, ${this.name}!`);
}

static createAnonymous() {
return new Person("匿名用户");
}
}

// 等价于ES5原型写法
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, ${this.name}!`);
};
Person.createAnonymous = function() {
return new Person("匿名用户");
};

// 验证方法在原型上
const p = new Person("张三");
console.log(p.greet === Person.prototype.greet); // true
console.log(p.__proto__ === Person.prototype); // true
console.log(Object.getPrototypeOf(p) === Person.prototype); // true

// 所有实例共享同一方法
const p1 = new Person("张三");
const p2 = new Person("李四");
console.log(p1.greet === p2.greet); // true

16.2.2 类方法在原型上的体现

详细解释:

  • 实例方法:类中定义的普通方法会被添加到原型对象上,所有实例共享。
  • 静态方法:被添加到类本身,而不是原型上。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Person {
constructor(name) {
this.name = name;
}

greet() {
console.log(`Hello, ${this.name}!`);
}

static staticMethod() {
console.log("这是静态方法");
}
}

// 验证方法在原型上
console.log(Person.prototype.greet); // [Function: greet]
console.log(Person.prototype.constructor === Person); // true

// 所有实例共享同一方法
const p1 = new Person("张三");
const p2 = new Person("李四");
console.log(p1.greet === p2.greet); // true

// 静态方法在构造函数上,不在原型上
console.log(Person.staticMethod); // [Function: staticMethod]
console.log(Person.prototype.staticMethod); // undefined

16.2.3 继承与原型链

详细解释:

  • extends关键字实现的继承,实际上是设置子类的prototype指向父类的prototype,建立原型链。
  • super关键字在方法中指向父类的原型,在构造函数中指向父类构造函数。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Animal {
constructor(name) {
this.name = name;
}

speak() {
console.log(`${this.name} 发出声音`);
}
}

class Dog extends Animal {
constructor(name) {
super(name);
}

speak() {
super.speak(); // 相当于 Animal.prototype.speak.call(this)
console.log(`${this.name} 汪汪叫`);
}
}

// 验证原型链
const dog = new Dog("小黑");

console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true
console.log(dog instanceof Object); // true

// 原型链关系
console.log(Object.getPrototypeOf(dog) === Dog.prototype); // true
console.log(Object.getPrototypeOf(Dog.prototype) === Animal.prototype); // true
console.log(Object.getPrototypeOf(Animal.prototype) === Object.prototype); // true

16.2.4 类中访问和操作原型

详细解释:

  • 类本身也有prototype属性,可以直接操作。
  • 可以通过实例的__proto__Object.getPrototypeOf()访问原型。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Person {
constructor(name) {
this.name = name;
}

greet() {
console.log(`Hello, ${this.name}!`);
}
}

// 动态添加方法到原型
Person.prototype.sayHello = function() {
console.log(`Hello, ${this.name}!`);
};

const p = new Person("张三");
p.sayHello(); // "Hello, 张三!"

// 修改已有的原型方法
const originalGreet = Person.prototype.greet;
Person.prototype.greet = function() {
console.log("Before greet");
originalGreet.call(this);
console.log("After greet");
};

p.greet();
// Before greet
// Hello, 张三!
// After greet

16.2.5 类与原型的高级应用

详细解释:

  • 可以使用Object.setPrototypeOf()动态改变类的原型链。
  • 类的继承机制底层使用Object.create()

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Animal {
speak() {
console.log("动物发出声音");
}
}

class Dog {
bark() {
console.log("汪汪");
}
}

// 动态设置Dog的原型为Animal
Object.setPrototypeOf(Dog.prototype, Animal.prototype);

const dog = new Dog();
dog.speak(); // "动物发出声音"
dog.bark(); // "汪汪"

console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true

// 手动实现继承
class Animal {
constructor(name) {
this.name = name;
}
}

class Dog {
constructor(name) {
this.name = name;
}
}

// 手动实现继承
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

// 等价于 class Dog extends Animal

const dog = new Dog("小黑");
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true

17. 运算符

17.1 算术运算符

详细解释:

  • 用于执行数学计算
  • 包括加、减、乘、除、取模、递增、递减等
  • +运算符也用于字符串拼接

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 基本算术
console.log(5 + 3); // 8
console.log(5 - 3); // 2
console.log(5 * 3); // 15
console.log(5 / 3); // 1.6666666666666667
console.log(5 % 3); // 2(取模)

// 递增递减
var a = 5;
console.log(a++); // 5(后递增)
console.log(a); // 6
console.log(++a); // 7(先递增)

var b = 5;
console.log(b--); // 5
console.log(b); // 4
console.log(--b); // 3

// 字符串拼接
console.log("Hello" + " " + "World"); // "Hello World"
console.log("5" + 3); // "53"(字符串拼接)
console.log(5 + "3"); // "53"(字符串拼接)
console.log("5" - 3); // 2(自动转换为数字)

// 一元加号转换为数字
console.log(+"5"); // 5
console.log(+"5.5"); // 5.5
console.log(+"abc"); // NaN

// 指数运算符(ES2016+)
console.log(2 ** 3); // 8(2的3次方)
console.log(4 ** 0.5); // 2(平方根)

// 位运算符
console.log(5 & 3); // 1(按位与)
console.log(5 | 3); // 7(按位或)
console.log(5 ^ 3); // 6(按位异或)
console.log(~5); // -6(按位取反)
console.log(5 << 1); // 10(左移)
console.log(5 >> 1); // 2(有符号右移)
console.log(5 >>> 1); // 2(无符号右移)

17.2 比较运算符

详细解释:

  • 用于比较两个值
  • 返回布尔值(true或false)
  • 包括相等、不等、大于、小于等
  • 有宽松相等(==)和严格相等(===)之分

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 相等比较
console.log(5 == "5"); // true(宽松相等,类型转换)
console.log(5 === "5"); // false(严格相等,不转换类型)
console.log(5 != "5"); // false
console.log(5 !== "5"); // true

// 大小比较
console.log(5 > 3); // true
console.log(5 < 3); // false
console.log(5 >= 5); // true
console.log(5 <= 3); // false

// 特殊值比较
console.log(null == undefined); // true
console.log(null === undefined); // false
console.log(NaN == NaN); // false
console.log(NaN === NaN); // false

// 使用Object.is比较(ES6+)
console.log(Object.is(NaN, NaN)); // true
console.log(Object.is(-0, +0)); // false
console.log(Object.is(-0, -0)); // true

// 比较对象
var obj1 = { value: 5 };
var obj2 = { value: 5 };
console.log(obj1 == obj2); // false(比较引用)
console.log(obj1.value == obj2.value); // true(比较值)

// 比较字符串
console.log("apple" < "banana"); // true(按字典序)
console.log("apple" < "Apple"); // false(大写字母在小写字母前)
console.log("apple".localeCompare("banana")); // -1(-1,0,1)

// 比较日期
var date1 = new Date(2023, 9, 15);
var date2 = new Date(2023, 9, 16);
console.log(date1 < date2); // true

17.3 赋值运算符

详细解释:

  • 用于给变量赋值
  • 包括简单赋值和复合赋值
  • 复合赋值是运算和赋值的简写形式

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 简单赋值
var x = 10;

// 复合赋值
x += 5; // x = x + 5
console.log(x); // 15

x -= 3; // x = x - 3
console.log(x); // 12

x *= 2; // x = x * 2
console.log(x); // 24

x /= 4; // x = x / 4
console.log(x); // 6

x %= 4; // x = x % 4
console.log(x); // 2

// 其他复合赋值
x **= 3; // x = x ** 3
console.log(x); // 8

// 链式赋值
var a, b, c;
a = b = c = 10;
console.log(a, b, c); // 10 10 10

// 注意:赋值表达式返回赋值后的值
var y = (x = 5);
console.log(y); // 5

// 解构赋值(ES6+)
var [first, second] = [1, 2];
console.log(first, second); // 1 2

var { name, age } = { name: "张三", age: 25 };
console.log(name, age); // 张三 25

// 默认值
var { city = "北京" } = {};
console.log(city); // "北京"

17.4 逻辑运算符

详细解释:

  • 用于布尔值的逻辑运算
  • 包括逻辑与(&&)、逻辑或(||)、逻辑非(!)
  • 支持短路求值
  • 可用于条件判断和默认值设置

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// 逻辑与(&&)
console.log(true && true); // true
console.log(true && false); // false
console.log(false && true); // false
console.log(false && false); // false

// 短路求值
function logMessage() {
console.log("函数被调用");
return true;
}

console.log(true && logMessage()); // 输出"函数被调用",返回true
console.log(false && logMessage()); // 不调用函数,返回false

// 逻辑或(||)
console.log(true || true); // true
console.log(true || false); // true
console.log(false || true); // true
console.log(false || false); // false

console.log(false || logMessage()); // 输出"函数被调用",返回true
console.log(true || logMessage()); // 不调用函数,返回true

// 逻辑非(!)
console.log(!true); // false
console.log(!false); // true
console.log(!!"Hello"); // true(转换为布尔值)

// 默认值设置
var name = null;
var displayName = name || "匿名用户";
console.log(displayName); // "匿名用户"

var value = 0;
var displayValue = value || "无值";
console.log(displayValue); // "无值"(0被视为假值)

// 空值合并运算符(ES2020+)
var nullable = null;
var result = nullable ?? "默认值";
console.log(result); // "默认值"

var zero = 0;
var result2 = zero ?? "默认值";
console.log(result2); // 0(0不是null或undefined)

// 逻辑赋值运算符(ES2021+)
var a = null;
a ??= "默认值";
console.log(a); // "默认值"

var b = "已存在";
b ??= "默认值";
console.log(b); // "已存在"

17.5 三元运算符

详细解释:

  • 条件表达式的简写形式
  • 语法:条件 ? 表达式1 : 表达式2
  • 如果条件为真,返回表达式1;否则返回表达式2
  • 可嵌套使用,但应避免过度嵌套

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 基本用法
var age = 25;
var status = (age >= 18) ? "成年人" : "未成年人";
console.log(status); // "成年人"

// 嵌套三元运算符
var score = 85;
var grade = (score >= 90) ? "A" :
(score >= 80) ? "B" :
(score >= 70) ? "C" : "D";
console.log(grade); // "B"

// 与逻辑运算符结合
var name = "张三";
var greeting = name ? `你好,${name}!` : "你好,访客!";
console.log(greeting); // "你好,张三!"

// 用于默认值
var input = null;
var value = input !== null && input !== undefined ? input : "默认值";
// 等价于
var value2 = input ?? "默认值";

// 用于简单条件赋值
var isDarkMode = true;
document.body.style.backgroundColor = isDarkMode ? "#333" : "#fff";

// 作为函数返回值
function getGreeting(time) {
return (time < 12) ? "上午好" :
(time < 18) ? "下午好" : "晚上好";
}
console.log(getGreeting(10)); // "上午好"
console.log(getGreeting(15)); // "下午好"
console.log(getGreeting(20)); // "晚上好"

// 注意:避免过度嵌套
// 不推荐
var result = condition1 ? value1 :
condition2 ? value2 :
condition3 ? value3 : value4;

// 推荐使用if-else或switch

18. 流程控制语句

18.1 if语句

详细解释:

  • 根据条件执行代码块
  • 语法:if (条件) { 代码块 }
  • 条件为真时执行代码块

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var score = 85;

if (score >= 90) {
console.log("优秀");
}

// 多行语句不需要大括号(不推荐)
if (score >= 90)
console.log("优秀");

// 布尔转换
var name = "张三";
if (name) {
console.log("名字存在");
}

var empty = "";
if (!empty) {
console.log("字符串为空");
}

// 复杂条件
var age = 25;
var hasLicense = true;
if (age >= 18 && hasLicense) {
console.log("可以开车");
}

18.2 if-else语句

详细解释:

  • 提供条件为假时的备选代码块
  • 语法:if (条件) { 代码块1 } else { 代码块2 }

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
var score = 75;

if (score >= 60) {
console.log("及格");
} else {
console.log("不及格");
}

// 嵌套if-else
var age = 25;
if (age < 18) {
console.log("未成年人");
} else {
if (age < 60) {
console.log("成年人");
} else {
console.log("老年人");
}
}

// 三元运算符替代
var message = (score >= 60) ? "及格" : "不及格";
console.log(message);

// 多条件判断
var num = 10;
if (num > 0) {
console.log("正数");
} else if (num < 0) {
console.log("负数");
} else {
console.log("零");
}

18.3 if…else if…else语句

详细解释:

  • 用于多条件分支判断
  • 语法:if (条件1) { ... } else if (条件2) { ... } else { ... }
  • 按顺序检查条件,执行第一个为真的条件对应的代码块

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
var score = 85;

if (score >= 90) {
console.log("优秀");
} else if (score >= 80) {
console.log("良好");
} else if (score >= 70) {
console.log("中等");
} else if (score >= 60) {
console.log("及格");
} else {
console.log("不及格");
}

// 日期判断
var day = new Date().getDay();
if (day === 0) {
console.log("星期日");
} else if (day === 1) {
console.log("星期一");
} else if (day === 2) {
console.log("星期二");
} else if (day === 3) {
console.log("星期三");
} else if (day === 4) {
console.log("星期四");
} else if (day === 5) {
console.log("星期五");
} else {
console.log("星期六");
}

// 优先级示例
var value = 10;
if (value > 5) {
console.log("大于5");
} else if (value > 8) {
console.log("大于8"); // 永远不会执行
} else {
console.log("小于等于5");
}

18.4 switch语句

详细解释:

  • 用于多分支选择
  • 语法:switch (表达式) { case 值: ... break; ... default: ... }
  • 比较表达式与case值的严格相等(===)
  • 使用break防止穿透

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
var day = new Date().getDay();
switch (day) {
case 0:
console.log("星期日");
break;
case 1:
console.log("星期一");
break;
case 2:
console.log("星期二");
break;
case 3:
console.log("星期三");
break;
case 4:
console.log("星期四");
break;
case 5:
console.log("星期五");
break;
case 6:
console.log("星期六");
break;
default:
console.log("无效的日期");
}

// 不使用break的穿透效果
var fruit = "apple";
switch (fruit) {
case "apple":
case "banana":
case "orange":
console.log("这是水果");
break;
case "carrot":
case "broccoli":
console.log("这是蔬菜");
break;
default:
console.log("未知类型");
}

// 多重case
var num = 2;
switch (num) {
case 1:
case 2:
case 3:
console.log("1-3之间");
break;
default:
console.log("其他");
}

// 使用表达式
var a = 5, b = 10;
switch (true) {
case a > b:
console.log("a大于b");
break;
case a < b:
console.log("a小于b");
break;
default:
console.log("a等于b");
}

// 字符串匹配
var color = "red";
switch (color) {
case "red":
console.log("红色");
break;
case "green":
console.log("绿色");
break;
case "blue":
console.log("蓝色");
break;
default:
console.log("其他颜色");
}

18.5 循环结构

18.5.1 while循环

详细解释:

  • 先判断条件,条件为真时执行循环体
  • 语法:while (条件) { 循环体 }
  • 可能一次都不执行

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
var i = 0;
while (i < 5) {
console.log("当前值: " + i);
i++;
}

// 计算1到100的和
var sum = 0;
var num = 1;
while (num <= 100) {
sum += num;
num++;
}
console.log("1到100的和: " + sum); // 5050

// 读取用户输入
var input;
while ((input = prompt("请输入'quit'退出")) !== "quit") {
console.log("你输入了: " + input);
}

// 避免无限循环
var counter = 0;
while (counter < 5) {
console.log(counter);
counter++; // 必须有递增/递减
}

// 处理数组
var arr = [1, 2, 3, 4, 5];
var index = 0;
while (index < arr.length) {
console.log(arr[index]);
index++;
}

18.5.2 do…while循环

详细解释:

  • 先执行循环体,再判断条件
  • 语法:do { 循环体 } while (条件);
  • 至少执行一次

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var i = 0;
do {
console.log("当前值: " + i);
i++;
} while (i < 5);

// 用户验证
var password;
do {
password = prompt("请输入密码(至少6位)");
} while (password && password.length < 6);

// 处理可能为空的情况
var data = [];
var index = 0;
do {
if (index < data.length) {
console.log(data[index]);
}
index++;
} while (index < data.length);

// 生成随机数直到满足条件
var random;
do {
random = Math.random();
console.log(random);
} while (random < 0.5);

18.5.3 for循环

详细解释:

  • 三部分:初始化、条件、迭代
  • 语法:for (初始化; 条件; 迭代) { 循环体 }
  • 最常用的循环结构

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 基本for循环
for (var i = 0; i < 5; i++) {
console.log("当前值: " + i);
}

// 计算阶乘
var n = 5;
var factorial = 1;
for (var i = 1; i <= n; i++) {
factorial *= i;
}
console.log(n + "! = " + factorial); // 120

// 遍历数组
var arr = [1, 2, 3, 4, 5];
for (var i = 0; i < arr.length; i++) {
console.log(arr[i]);
}

// 遍历字符串
var str = "Hello";
for (var i = 0; i < str.length; i++) {
console.log(str[i]);
}

// 嵌套循环
for (var i = 1; i <= 3; i++) {
for (var j = 1; j <= 3; j++) {
console.log(i + "," + j);
}
}

// 多变量初始化
for (var i = 0, j = 10; i < j; i++, j--) {
console.log(i + "," + j);
}

// 无限循环(谨慎使用)
// for (;;) {
// console.log("无限循环");
// }

18.5.4 for…in循环

详细解释:

  • 遍历对象的可枚举属性
  • 语法:for (var key in object) { ... }
  • 包括继承的属性,通常需要hasOwnProperty检查
  • 不保证顺序

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 遍历对象属性
var person = {
name: "张三",
age: 25,
city: "北京"
};

for (var key in person) {
if (person.hasOwnProperty(key)) {
console.log(key + ": " + person[key]);
}
}

// 遍历数组(不推荐,应使用for...of)
var arr = [1, 2, 3];
for (var index in arr) {
console.log(index + ": " + arr[index]);
}

// 包含继承属性
function Person(name) {
this.name = name;
}
Person.prototype.age = 30;

var p = new Person("李四");
for (var key in p) {
console.log(key + ": " + p[key]);
// name: 李四
// age: 30
}

// 使用hasOwnProperty过滤
for (var key in p) {
if (p.hasOwnProperty(key)) {
console.log("自有属性: " + key);
} else {
console.log("继承属性: " + key);
}
}

18.5.5 for…of循环(ES6+)

详细解释:

  • 遍历可迭代对象(数组、字符串、Map、Set等)
  • 语法:for (var item of iterable) { ... }
  • 不遍历对象属性
  • 保证顺序

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 遍历数组
var arr = [1, 2, 3, 4, 5];
for (var num of arr) {
console.log(num);
}

// 遍历字符串
var str = "Hello";
for (var char of str) {
console.log(char);
}

// 遍历Map
var map = new Map();
map.set("name", "张三");
map.set("age", 25);
for (var [key, value] of map) {
console.log(key + ": " + value);
}

// 遍历Set
var set = new Set([1, 2, 3, 2, 1]);
for (var item of set) {
console.log(item); // 1, 2, 3
}

// 与for...in对比
var obj = { a: 1, b: 2, c: 3 };
// for...in遍历对象属性
for (var key in obj) {
console.log(key); // a, b, c
}
// for...of不能直接遍历对象
// for (var value of obj) { } // 错误

// 使用Object.entries遍历对象
for (var [key, value] of Object.entries(obj)) {
console.log(key + ": " + value);
}

18.6 break与continue

详细解释:

  • break:立即终止循环
  • continue:跳过当前迭代,继续下一次迭代
  • 可用于所有循环结构

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// break示例
for (var i = 0; i < 10; i++) {
if (i === 5) {
break;
}
console.log(i); // 0,1,2,3,4
}

// continue示例
for (var i = 0; i < 5; i++) {
if (i === 2) {
continue;
}
console.log(i); // 0,1,3,4
}

// 嵌套循环中的break
outer: for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (i === 1 && j === 1) {
break outer;
}
console.log(i + "," + j);
}
}
// 输出: 0,0 0,1 0,2 1,0

// 嵌套循环中的continue
outer: for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (i === 1 && j === 1) {
continue outer;
}
console.log(i + "," + j);
}
}
// 输出: 0,0 0,1 0,2 1,0 2,0 2,1 2,2

19. JS操作DOM

19.1 什么是DOM?

详细解释:

  • DOM(Document Object Model):文档对象模型
  • 将HTML/XML文档表示为树形结构
  • 允许JavaScript动态访问和修改文档内容
  • 由W3C标准化,所有现代浏览器都支持
  • DOM树由节点组成:元素节点、属性节点、文本节点等

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// DOM结构示例
/*
<html>
<head>
<title>示例页面</title>
</head>
<body>
<h1>标题</h1>
<p>段落文本</p>
</body>
</html>
*/

// 对应的DOM树
/*
Document
└── html
├── head
│ └── title
│ └── #text "示例页面"
└── body
├── h1
│ └── #text "标题"
└── p
└── #text "段落文本"
*/

19.2 DOM查找元素

19.2.1 直接查找

详细解释:

  • 通过ID、标签名、类名等查找元素
  • 返回单个元素或元素集合

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 通过ID获取元素(返回单个元素)
var header = document.getElementById("header");
console.log(header);

// 通过标签名获取元素(返回HTMLCollection)
var paragraphs = document.getElementsByTagName("p");
console.log(paragraphs);
console.log(paragraphs[0]); // 第一个p元素

// 通过类名获取元素(返回HTMLCollection)
var items = document.getElementsByClassName("item");
console.log(items);

// 通过名称获取元素(返回NodeList,常用于表单元素)
var radios = document.getElementsByName("option");
console.log(radios);

// 通过CSS选择器获取单个元素(返回第一个匹配的元素)
var firstItem = document.querySelector(".item");
console.log(firstItem);

// 通过CSS选择器获取所有元素(返回NodeList)
var allItems = document.querySelectorAll(".item");
console.log(allItems);

// 示例:获取特定元素
var mainContent = document.getElementById("main");
var links = document.querySelectorAll("a.external");
var activeItems = document.querySelectorAll(".item.active");

19.2.2 间接查找

详细解释:

  • 通过已获取的元素查找其子元素、父元素或兄弟元素
  • 常用属性:parentNodechildNodeschildrenfirstChildlastChildnextSiblingpreviousSibling

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 获取父元素
var child = document.getElementById("child");
var parent = child.parentNode;
console.log(parent);

// 获取子元素
var parent = document.getElementById("parent");
var children = parent.childNodes; // 包含文本节点
console.log(children);

var elementChildren = parent.children; // 只包含元素节点
console.log(elementChildren);

// 获取第一个/最后一个子元素
var firstChild = parent.firstElementChild;
var lastChild = parent.lastElementChild;
console.log(firstChild, lastChild);

// 获取兄弟元素
var element = document.getElementById("element");
var nextSibling = element.nextElementSibling;
var prevSibling = element.previousElementSibling;
console.log(nextSibling, prevSibling);

// 示例:遍历所有子元素
var container = document.getElementById("container");
for (var i = 0; i < container.children.length; i++) {
console.log(container.children[i]);
}

// 查找特定类型的子元素
var list = document.getElementById("list");
var items = list.querySelectorAll("li");
console.log(items);

19.3 文件内容操作

19.3.1 内容操作

详细解释:

  • innerText:获取或设置元素的文本内容(不包括HTML标签)
  • innerHTML:获取或设置元素的HTML内容(包括HTML标签)
  • textContent:类似innerText,但更标准,保留所有空白

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 获取内容
var div = document.getElementById("content");
console.log(div.innerText); // 仅文本内容
console.log(div.innerHTML); // 包含HTML的完整内容

// 设置内容
div.innerText = "新的文本内容"; // 会转义HTML
div.innerHTML = "<strong>新的HTML内容</strong>"; // 会解析HTML

// 使用textContent(更安全)
div.textContent = "安全的内容,<script>不会执行</script>";

// 示例:动态更新内容
function updateContent() {
var message = "当前时间: " + new Date().toLocaleTimeString();
document.getElementById("time").innerText = message;
}
setInterval(updateContent, 1000);

// 示例:创建HTML内容
var list = document.getElementById("list");
list.innerHTML = `
<li>项目1</li>
<li>项目2</li>
<li>项目3</li>
`;

// 使用innerText和innerHTML的差异
var div = document.createElement("div");
div.innerHTML = "<p>Hello</p><script>alert('XSS');</script>";
console.log(div.innerText); // "Hello"
console.log(div.innerHTML); // "<p>Hello</p><script>alert('XSS');</script>"

19.3.2 表单元素操作

详细解释:

  • value:获取或设置输入框的值
  • selectedIndex:获取或设置下拉菜单的选中索引
  • checked:获取或设置复选框/单选按钮的选中状态

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 输入框
var input = document.getElementById("username");
console.log(input.value); // 获取当前值
input.value = "新值"; // 设置新值

// 文本区域
var textarea = document.getElementById("message");
console.log(textarea.value);

// 下拉菜单
var select = document.getElementById("country");
console.log(select.value); // 获取选中值
console.log(select.selectedIndex); // 获取选中索引
select.selectedIndex = 1; // 设置选中项
select.value = "cn"; // 通过值设置选中项

// 复选框
var checkbox = document.getElementById("subscribe");
console.log(checkbox.checked); // 检查是否选中
checkbox.checked = true; // 设置为选中

// 单选按钮组
var radios = document.getElementsByName("gender");
for (var i = 0; i < radios.length; i++) {
if (radios[i].checked) {
console.log("选中值: " + radios[i].value);
break;
}
}

// 示例:表单验证
function validateForm() {
var username = document.getElementById("username").value;
if (username.length < 5) {
alert("用户名至少需要5个字符");
return false;
}
return true;
}

19.4 样式操作

19.4.1 样式操作

详细解释:

  • className:获取或设置元素的class属性(字符串)
  • classList:元素的类列表(DOMTokenList对象)
  • style:元素的行内样式对象

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// className操作
var element = document.getElementById("box");
element.className = "highlight active"; // 设置整个class
console.log(element.className); // "highlight active"

// classList操作
console.log(element.classList); // DOMTokenList
console.log(element.classList.length); // 2
console.log(element.classList[0]); // "highlight"

// 添加类
element.classList.add("new-class");
console.log(element.classList.contains("new-class")); // true

// 移除类
element.classList.remove("highlight");
console.log(element.classList.contains("highlight")); // false

// 切换类
element.classList.toggle("active");
console.log(element.classList.contains("active")); // false

// 替换类
element.classList.replace("new-class", "updated-class");

// style操作
element.style.color = "red";
element.style.backgroundColor = "yellow";
element.style.fontSize = "16px";
element.style.padding = "10px";
element.style.borderRadius = "5px";

// 获取计算样式
var computedStyle = window.getComputedStyle(element);
console.log(computedStyle.color);
console.log(computedStyle.fontSize);

// 示例:动态切换主题
function toggleTheme() {
var body = document.body;
if (body.classList.contains("dark")) {
body.classList.remove("dark");
body.classList.add("light");
} else {
body.classList.remove("light");
body.classList.add("dark");
}
}

// 示例:悬停效果
var buttons = document.querySelectorAll(".button");
buttons.forEach(function(button) {
button.addEventListener("mouseover", function() {
this.style.backgroundColor = "#0066cc";
this.style.color = "white";
});
button.addEventListener("mouseout", function() {
this.style.backgroundColor = "";
this.style.color = "";
});
});

19.5 属性操作

19.5.1 属性操作

详细解释:

  • getAttribute():获取元素属性值
  • setAttribute():设置元素属性值
  • removeAttribute():移除元素属性
  • hasAttribute():检查元素是否有指定属性

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
var link = document.getElementById("myLink");

// 获取属性
var href = link.getAttribute("href");
var target = link.getAttribute("target");
console.log(href, target);

// 设置属性
link.setAttribute("href", "https://example.com");
link.setAttribute("target", "_blank");
link.setAttribute("title", "示例链接");

// 移除属性
link.removeAttribute("target");

// 检查属性
if (link.hasAttribute("title")) {
console.log("链接有title属性");
}

// 自定义属性(data-*)
var dataValue = link.getAttribute("data-id");
link.setAttribute("data-id", "123");
console.log(dataValue);

// 示例:动态修改图片
var img = document.getElementById("myImage");
img.setAttribute("src", "new-image.jpg");
img.setAttribute("alt", "新图片");

// 示例:添加aria属性提高可访问性
var button = document.getElementById("myButton");
button.setAttribute("aria-label", "关闭窗口");

19.6 创建和添加元素

19.6.1 创建标签并添加到HTML

详细解释:

  • 两种主要方式:字符串方式和对象方式
  • 字符串方式:使用insertAdjacentHTML()
  • 对象方式:使用document.createElement()appendChild()

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// 字符串方式
var container = document.getElementById("container");
container.insertAdjacentHTML("beforeEnd", "<p>新段落</p>");

// insertAdjacentHTML的位置参数
// 'beforeBegin': 在元素开始前插入
// 'afterBegin': 在元素开始标记后插入
// 'beforeEnd': 在元素结束标记前插入
// 'afterEnd': 在元素结束标记后插入

// 示例:在不同位置插入
container.insertAdjacentHTML("beforeBegin", "<div>在容器前</div>");
container.insertAdjacentHTML("afterBegin", "<div>在容器内开头</div>");
container.insertAdjacentHTML("beforeEnd", "<div>在容器内结尾</div>");
container.insertAdjacentHTML("afterEnd", "<div>在容器后</div>");

// 对象方式
var newDiv = document.createElement("div");
newDiv.className = "box";
newDiv.style.backgroundColor = "lightblue";
newDiv.textContent = "新创建的div";

var newParagraph = document.createElement("p");
newParagraph.textContent = "这是段落内容";

// 添加子元素
newDiv.appendChild(newParagraph);

// 添加到文档
document.body.appendChild(newDiv);

// 创建更复杂的结构
function createCard(title, content) {
var card = document.createElement("div");
card.className = "card";

var cardTitle = document.createElement("h2");
cardTitle.textContent = title;

var cardContent = document.createElement("p");
cardContent.textContent = content;

card.appendChild(cardTitle);
card.appendChild(cardContent);

return card;
}

var card = createCard("示例卡片", "这是卡片内容");
document.getElementById("cards-container").appendChild(card);

19.7 表单操作

详细解释:

  • 任何表单元素都可以通过DOM提交
  • 使用submit()方法提交表单
  • 可以阻止默认提交行为进行验证

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// 通过DOM提交表单
function submitForm() {
document.getElementById("myForm").submit();
}

// 阻止默认提交行为
document.getElementById("myForm").addEventListener("submit", function(event) {
event.preventDefault(); // 阻止默认提交

// 执行验证
var username = this.username.value;
if (username.length < 5) {
alert("用户名至少需要5个字符");
return;
}

// 验证通过后提交
this.submit();
});

// 任何元素都可以触发提交
document.getElementById("customSubmit").addEventListener("click", function() {
document.getElementById("myForm").submit();
});

// 示例:表单重置
function resetForm() {
document.getElementById("myForm").reset();
}

// 示例:动态创建表单
function createForm() {
var form = document.createElement("form");
form.id = "dynamicForm";
form.action = "/submit";
form.method = "post";

var input = document.createElement("input");
input.type = "text";
input.name = "username";

var submit = document.createElement("input");
submit.type = "submit";
submit.value = "提交";

form.appendChild(input);
form.appendChild(submit);

document.body.appendChild(form);
}

19.8 其他DOM操作

19.8.1 控制台输出

详细解释:

  • console.log():普通日志
  • console.error():错误日志
  • console.warn():警告日志
  • console.info():信息日志
  • console.debug():调试日志
  • console.table():表格形式显示数据

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
console.log("普通日志");
console.error("错误信息");
console.warn("警告信息");
console.info("信息提示");
console.debug("调试信息");

var user = { name: "张三", age: 25, city: "北京" };
console.log(user);
console.table(user);

var users = [
{ name: "张三", age: 25 },
{ name: "李四", age: 30 }
];
console.table(users);

19.8.2 弹窗

详细解释:

  • alert():显示消息框
  • confirm():显示确认框,返回布尔值
  • prompt():显示输入框,返回用户输入

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// alert
alert("欢迎访问本网站!");

// confirm
var result = confirm("确定要删除吗?");
if (result) {
console.log("用户确认删除");
} else {
console.log("用户取消删除");
}

// prompt
var name = prompt("请输入您的名字", "张三");
if (name) {
console.log("欢迎," + name);
} else {
console.log("用户未输入名字");
}

// 示例:表单验证
function validateForm() {
var username = document.getElementById("username").value;
if (username.length < 5) {
alert("用户名至少需要5个字符");
return false;
}
return true;
}

19.8.3 URL和刷新

详细解释:

  • location.href:获取或设置当前URL
  • location.reload():重新加载页面
  • history.back():返回上一页
  • history.forward():前进到下一页

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 获取当前URL
console.log(location.href);

// 重定向
function redirect() {
location.href = "https://example.com";
}

// 重新加载页面
function refreshPage() {
location.reload();
}

// 通过历史记录导航
function goBack() {
history.back();
}

function goForward() {
history.forward();
}

// 替换当前URL(不创建新历史记录)
function replaceUrl() {
location.replace("https://example.com");
}

// 示例:定时重定向
setTimeout(function() {
location.href = "https://example.com";
}, 5000);

19.8.4 定时器

详细解释:

  • setInterval():重复执行函数
  • clearInterval():清除重复执行的定时器
  • setTimeout():延迟执行函数
  • clearTimeout():清除延迟执行的定时器

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// setInterval
var intervalId = setInterval(function() {
var time = new Date().toLocaleTimeString();
document.getElementById("clock").value = time;
}, 1000);

// 停止定时器
function stopClock() {
clearInterval(intervalId);
}

// setTimeout
function showNotification() {
document.getElementById("notification").innerText = "操作成功!";
setTimeout(function() {
document.getElementById("notification").innerText = "";
}, 3000);
}

// 递归setTimeout(比setInterval更精确)
function animate() {
// 动画逻辑
console.log("动画帧");

// 递归调用
setTimeout(animate, 1000/60); // 60fps
}
animate();

// 清除定时器
var timerId;
function startTimer() {
timerId = setTimeout(function() {
console.log("定时器触发");
}, 2000);
}

function cancelTimer() {
clearTimeout(timerId);
}

// 示例:倒计时
var countdown = 10;
var countdownId = setInterval(function() {
document.getElementById("countdown").innerText = countdown;
countdown--;

if (countdown < 0) {
clearInterval(countdownId);
document.getElementById("countdown").innerText = "时间到!";
}
}, 1000);

19.9 事件处理

19.9.1 事件绑定

详细解释:

  • 行内绑定:直接在HTML标签中添加事件属性
  • 脚本绑定:通过JavaScript代码绑定事件

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// 行内绑定(在HTML中)
// <button onclick="handleClick()">点击我</button>

// 脚本绑定
var button = document.getElementById("myButton");
button.onclick = function() {
alert("按钮被点击");
};

// 使用addEventListener(推荐)
button.addEventListener("click", function() {
alert("使用addEventListener绑定");
});

// 示例:多种事件
var input = document.getElementById("myInput");
input.addEventListener("focus", function() {
this.style.borderColor = "blue";
});

input.addEventListener("blur", function() {
this.style.borderColor = "";
});

input.addEventListener("keyup", function(event) {
console.log("按键: " + event.key);
});

// 示例:事件委托
document.getElementById("list").addEventListener("click", function(event) {
if (event.target.tagName === "LI") {
console.log("点击了列表项: " + event.target.textContent);
}
});

// 示例:移除事件监听器
function handleClick() {
console.log("按钮被点击");
}

button.addEventListener("click", handleClick);
// 之后可以移除
button.removeEventListener("click", handleClick);

// 示例:事件对象
document.addEventListener("keydown", function(event) {
console.log("按键代码: " + event.keyCode);
console.log("按键字符: " + event.key);

if (event.key === "Enter") {
console.log("按下了回车键");
}

// 阻止默认行为
if (event.key === " ") {
event.preventDefault();
}
});

综合大例子

以下是一个包含所有知识点的综合性示例,展示如何将JavaScript基础知识应用于实际项目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JavaScript综合示例</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Microsoft YaHei", sans-serif;
}

body {
background: linear-gradient(to right, #f5f7fa, #e4edf5);
color: #333;
line-height: 1.6;
padding: 20px;
}

.container {
max-width: 1200px;
margin: 0 auto;
}

header {
background: #2c3e50;
color: white;
padding: 20px 0;
text-align: center;
margin-bottom: 30px;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}

h1 {
font-size: 2.5rem;
margin-bottom: 10px;
}

.description {
font-size: 1.2rem;
max-width: 800px;
margin: 0 auto;
opacity: 0.9;
}

.card {
background: white;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
padding: 25px;
margin-bottom: 30px;
transition: transform 0.3s ease;
}

.card:hover {
transform: translateY(-5px);
}

h2 {
color: #2c3e50;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
}

.form-group {
margin-bottom: 20px;
}

label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}

input, select, textarea {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px;
}

button {
background: #3498db;
color: white;
border: none;
padding: 10px 15px;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
transition: background 0.3s;
}

button:hover {
background: #2980b9;
}

.button-group {
display: flex;
gap: 10px;
margin-top: 15px;
}

.output {
margin-top: 20px;
padding: 15px;
background: #f8f9fa;
border: 1px solid #eee;
border-radius: 4px;
min-height: 50px;
}

.user-card {
display: flex;
align-items: center;
padding: 15px;
border: 1px solid #eee;
border-radius: 8px;
margin-top: 15px;
background: #f8f9fa;
}

.user-avatar {
width: 50px;
height: 50px;
background: #3498db;
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
margin-right: 15px;
}

.timer-display {
font-size: 2rem;
text-align: center;
margin: 20px 0;
color: #2c3e50;
}

.notification {
position: fixed;
top: 20px;
right: 20px;
background: #27ae60;
color: white;
padding: 15px 25px;
border-radius: 4px;
box-shadow: 0 2px 10px rgba(0,0,0,0.2);
transform: translateX(120%);
transition: transform 0.3s ease;
z-index: 1000;
}

.notification.show {
transform: translateX(0);
}

.code-block {
background: #2d2d2d;
color: #f8f8f2;
padding: 15px;
border-radius: 4px;
font-family: monospace;
overflow-x: auto;
margin: 15px 0;
}

.highlight {
background: #fffde7;
padding: 2px 5px;
border-radius: 2px;
}

footer {
text-align: center;
margin-top: 50px;
padding: 20px;
color: #7f8c8d;
border-top: 1px solid #eee;
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>JavaScript综合示例</h1>
<p class="description">本示例展示了JavaScript基础知识点的应用,包括变量、函数、DOM操作、事件处理等</p>
</header>

<div class="card">
<h2>1. 用户信息表单</h2>
<form id="userForm">
<div class="form-group">
<label for="username">用户名 (5-20个字符)</label>
<input type="text" id="username" name="username" required>
</div>

<div class="form-group">
<label for="email">邮箱</label>
<input type="email" id="email" name="email" required>
</div>

<div class="form-group">
<label for="age">年龄</label>
<input type="number" id="age" name="age" min="18" max="100" required>
</div>

<div class="form-group">
<label for="country">国家</label>
<select id="country" name="country">
<option value="cn">中国</option>
<option value="us">美国</option>
<option value="jp">日本</option>
<option value="kr">韩国</option>
</select>
</div>

<div class="form-group">
<label for="bio">个人简介</label>
<textarea id="bio" name="bio" rows="4"></textarea>
</div>

<div class="button-group">
<button type="submit" id="submitBtn">提交</button>
<button type="button" id="resetBtn">重置</button>
</div>
</form>

<div id="userOutput" class="output"></div>
</div>

<div class="card">
<h2>2. 动态内容操作</h2>
<div class="form-group">
<label for="contentInput">输入内容</label>
<input type="text" id="contentInput" placeholder="输入要添加的内容">
</div>

<div class="button-group">
<button id="addContentBtn">添加内容</button>
<button id="clearContentBtn">清空内容</button>
</div>

<div id="contentArea" class="output">
<p>初始内容</p>
</div>
</div>

<div class="card">
<h2>3. 时钟与通知</h2>
<div class="timer-display" id="clock">00:00:00</div>

<div class="button-group">
<button id="startTimerBtn">开始计时</button>
<button id="stopTimerBtn">停止计时</button>
<button id="resetTimerBtn">重置</button>
</div>

<div class="button-group" style="margin-top: 15px;">
<button id="showNotificationBtn">显示通知</button>
</div>
</div>

<div class="card">
<h2>4. 数据处理</h2>
<div class="form-group">
<label for="jsonData">JSON数据</label>
<textarea id="jsonData" rows="4" style="font-family: monospace;">{
"name": "张三",
"age": 25,
"city": "北京",
"hobbies": ["编程", "阅读", "运动"]
}</textarea>
</div>

<div class="button-group">
<button id="parseJsonBtn">解析JSON</button>
<button id="formatJsonBtn">格式化JSON</button>
</div>

<div id="jsonOutput" class="output"></div>
</div>

<div class="card">
<h2>5. 事件委托示例</h2>
<p>点击列表项查看效果:</p>

<ul id="eventList" style="list-style: none; padding-left: 0;">
<li style="padding: 10px; border: 1px solid #eee; margin: 5px 0; border-radius: 4px;">列表项 1</li>
<li style="padding: 10px; border: 1px solid #eee; margin: 5px 0; border-radius: 4px;">列表项 2</li>
<li style="padding: 10px; border: 1px solid #eee; margin: 5px 0; border-radius: 4px;">列表项 3</li>
<li style="padding: 10px; border: 1px solid #eee; margin: 5px 0; border-radius: 4px;">列表项 4</li>
</ul>

<div id="eventOutput" class="output"></div>
</div>

<div class="notification" id="notification">
操作成功!
</div>

<footer>
<p>JavaScript基础综合示例 &copy; 2023 | 所有知识点已应用</p>
</footer>
</div>

<script>
// 1. 变量和作用域
let currentUser = null;
let timerId = null;
let startTime = null;
let elapsedTime = 0;

// 2. 函数定义
function showNotification(message = "操作成功!", duration = 3000) {
const notification = document.getElementById('notification');
notification.textContent = message;
notification.classList.add('show');

setTimeout(() => {
notification.classList.remove('show');
}, duration);
}

// 3. DOM操作 - 表单处理
document.getElementById('userForm').addEventListener('submit', function(e) {
e.preventDefault();

// 4. 获取表单值
const username = document.getElementById('username').value;
const email = document.getElementById('email').value;
const age = parseInt(document.getElementById('age').value);
const country = document.getElementById('country').value;
const bio = document.getElementById('bio').value;

// 5. 表单验证
if (username.length < 5 || username.length > 20) {
showNotification('用户名必须在5-20个字符之间', 5000);
return;
}

if (!/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/.test(email)) {
showNotification('请输入有效的邮箱地址', 5000);
return;
}

// 6. 创建用户对象
currentUser = {
id: Date.now(),
username: username,
email: email,
age: age,
country: country,
bio: bio,
createdAt: new Date()
};

// 7. 显示用户信息
displayUser(currentUser);
showNotification('用户信息已保存');

// 8. 重置表单
this.reset();
});

// 9. 重置表单
document.getElementById('resetBtn').addEventListener('click', function() {
document.getElementById('userForm').reset();
document.getElementById('userOutput').innerHTML = '';
currentUser = null;
showNotification('表单已重置');
});

// 10. 显示用户信息
function displayUser(user) {
const output = document.getElementById('userOutput');
output.innerHTML = `
<div class="user-card">
<div class="user-avatar">${user.username.charAt(0).toUpperCase()}</div>
<div>
<h3>${user.username}</h3>
<p>邮箱: ${user.email}</p>
<p>年龄: ${user.age}岁</p>
<p>国家: ${getCountryName(user.country)}</p>
${user.bio ? `<p>简介: ${user.bio}</p>` : ''}
</div>
</div>
`;
}

// 11. 辅助函数
function getCountryName(code) {
const countries = {
'cn': '中国',
'us': '美国',
'jp': '日本',
'kr': '韩国'
};
return countries[code] || code;
}

// 12. 动态内容操作
document.getElementById('addContentBtn').addEventListener('click', function() {
const content = document.getElementById('contentInput').value;
if (content.trim() === '') {
showNotification('请输入内容', 3000);
return;
}

const contentArea = document.getElementById('contentArea');
const newParagraph = document.createElement('p');
newParagraph.textContent = content;

// 13. 添加样式
newParagraph.classList.add('highlight');
newParagraph.style.transition = 'all 0.3s';
newParagraph.style.opacity = '0';

contentArea.appendChild(newParagraph);

// 14. 动画效果
setTimeout(() => {
newParagraph.style.opacity = '1';
}, 10);

document.getElementById('contentInput').value = '';
showNotification('内容已添加');
});

// 15. 清空内容
document.getElementById('clearContentBtn').addEventListener('click', function() {
document.getElementById('contentArea').innerHTML = '';
showNotification('内容已清空');
});

// 16. 时钟功能
function updateClock() {
const now = new Date();
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');

document.getElementById('clock').textContent = `${hours}:${minutes}:${seconds}`;
}

// 17. 计时器功能
document.getElementById('startTimerBtn').addEventListener('click', function() {
if (timerId) return;

startTime = Date.now() - elapsedTime;
timerId = setInterval(updateTimer, 10);
showNotification('计时器已开始');
});

document.getElementById('stopTimerBtn').addEventListener('click', function() {
if (timerId) {
clearInterval(timerId);
timerId = null;
elapsedTime = Date.now() - startTime;
showNotification('计时器已停止');
}
});

document.getElementById('resetTimerBtn').addEventListener('click', function() {
clearInterval(timerId);
timerId = null;
elapsedTime = 0;
document.getElementById('clock').textContent = '00:00:00';
showNotification('计时器已重置');
});

function updateTimer() {
const now = Date.now();
elapsedTime = now - startTime;

const hours = Math.floor(elapsedTime / 3600000);
const minutes = Math.floor((elapsedTime % 3600000) / 60000);
const seconds = Math.floor((elapsedTime % 60000) / 1000);
const milliseconds = Math.floor((elapsedTime % 1000) / 10);

document.getElementById('clock').textContent =
`${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}.${String(milliseconds).padStart(2, '0')}`;
}

// 18. 显示通知
document.getElementById('showNotificationBtn').addEventListener('click', function() {
showNotification();
});

// 19. JSON处理
document.getElementById('parseJsonBtn').addEventListener('click', function() {
const jsonData = document.getElementById('jsonData').value;
try {
const parsed = JSON.parse(jsonData);
document.getElementById('jsonOutput').innerHTML = `
<p><strong>姓名:</strong> ${parsed.name}</p>
<p><strong>年龄:</strong> ${parsed.age}</p>
<p><strong>城市:</strong> ${parsed.city}</p>
<p><strong>爱好:</strong> ${parsed.hobbies.join(', ')}</p>
`;
showNotification('JSON解析成功');
} catch (e) {
document.getElementById('jsonOutput').innerHTML =
`<p style="color: red;">JSON解析错误: ${e.message}</p>`;
showNotification('JSON解析失败', 5000);
}
});

document.getElementById('formatJsonBtn').addEventListener('click', function() {
const jsonData = document.getElementById('jsonData').value;
try {
const parsed = JSON.parse(jsonData);
const formatted = JSON.stringify(parsed, null, 2);
document.getElementById('jsonData').value = formatted;
showNotification('JSON已格式化');
} catch (e) {
showNotification('JSON格式化失败', 5000);
}
});

// 20. 事件委托
document.getElementById('eventList').addEventListener('click', function(e) {
if (e.target.tagName === 'LI') {
const index = Array.from(e.target.parentNode.children).indexOf(e.target);
document.getElementById('eventOutput').innerHTML =
`点击了列表项 ${index + 1}: ${e.target.textContent}`;

// 21. 添加动画效果
e.target.style.transform = 'scale(1.05)';
e.target.style.transition = 'transform 0.2s';

setTimeout(() => {
e.target.style.transform = 'scale(1)';
}, 200);
}
});

// 22. 初始化
function init() {
// 23. 设置初始时钟
updateClock();
setInterval(updateClock, 1000);

// 24. 添加示例列表项
const eventList = document.getElementById('eventList');
for (let i = 5; i <= 7; i++) {
const li = document.createElement('li');
li.textContent = `列表项 ${i}`;
li.style.padding = '10px';
li.style.border = '1px solid #eee';
li.style.margin = '5px 0';
li.style.borderRadius = '4px';
eventList.appendChild(li);
}

// 25. 显示欢迎通知
setTimeout(() => {
showNotification('欢迎使用JavaScript综合示例', 5000);
}, 500);
}

// 26. 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', init);

// 27. 键盘事件处理
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
document.getElementById('userOutput').innerHTML = '';
document.getElementById('jsonOutput').innerHTML = '';
document.getElementById('eventOutput').innerHTML = '';
showNotification('所有输出已清空');
}
});

// 28. 拖拽功能示例
const notification = document.getElementById('notification');
let isDragging = false;
let offsetX, offsetY;

notification.addEventListener('mousedown', function(e) {
isDragging = true;
offsetX = e.clientX - notification.getBoundingClientRect().left;
offsetY = e.clientY - notification.getBoundingClientRect().top;
});

document.addEventListener('mousemove', function(e) {
if (isDragging) {
notification.style.position = 'absolute';
notification.style.left = (e.clientX - offsetX) + 'px';
notification.style.top = (e.clientY - offsetY) + 'px';
}
});

document.addEventListener('mouseup', function() {
isDragging = false;
});

// 29. 使用ES6+特性
const formatDateTime = (date) => {
const options = {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
};
return new Date(date).toLocaleString('zh-CN', options);
};

// 30. 添加当前时间戳
document.getElementById('jsonData').value = `{
"name": "示例用户",
"timestamp": "${Date.now()}",
"formattedTime": "${formatDateTime(Date.now())}"
}`;
</script>
</body>
</html>

总结

这个JavaScript综合示例展示了以下知识点:

  1. 变量与作用域:使用letconst声明变量,理解局部和全局作用域
  2. 函数:定义和调用函数,包括箭头函数
  3. 数据类型:处理字符串、数字、布尔值、对象和数组
  4. DOM操作
    • 查找元素(getElementById, querySelector)
    • 修改内容(innerText, innerHTML)
    • 操作样式(classList, style)
    • 创建和添加元素(createElement, appendChild)
  5. 事件处理
    • 事件绑定(addEventListener)
    • 事件委托
    • 阻止默认行为
  6. 表单处理
    • 获取表单值
    • 表单验证
    • 动态更新
  7. 定时器
    • setInterval和setTimeout
    • 清除定时器
  8. JSON处理
    • JSON.parse和JSON.stringify
    • 错误处理
  9. ES6+特性
    • 模板字符串
    • 箭头函数
    • 对象解构
    • Promise(隐式使用)
  10. 错误处理
    • try/catch
    • 输入验证
  11. 交互效果
    • 动画
    • 拖拽
    • 通知系统

1. DIV和CSS样式

详细解释:

  • DIV 是HTML中的一个块级元素,用于将文档分割为独立的区块。它本身没有特定的语义,主要作为容器使用,通过CSS来定义其外观和布局。
  • CSS(层叠样式表)是一种描述HTML或XML文档外观和格式的样式表语言。CSS的核心理念是将内容与表现分离,使网页结构更清晰、更易于维护。

为什么使用DIV+CSS:

  • 与传统的表格布局相比,DIV+CSS布局更加灵活、代码更简洁
  • 提高网页加载速度(减少冗余HTML标签)
  • 更好的SEO优化(搜索引擎更容易抓取内容)
  • 便于后期维护和修改

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<!DOCTYPE html>
<html>
<head>
<title>DIV+CSS示例</title>
<style>
.container {
width: 80%;
margin: 0 auto;
border: 1px solid #ccc;
}
.header {
background-color: #333;
color: white;
padding: 20px;
text-align: center;
}
.content {
padding: 20px;
display: flex;
}
.sidebar {
width: 25%;
background-color: #f0f0f0;
padding: 15px;
}
.main {
width: 75%;
padding: 15px;
}
.footer {
background-color: #333;
color: white;
text-align: center;
padding: 10px;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>我的网站</h1>
</div>
<div class="content">
<div class="sidebar">
<h2>导航栏</h2>
<ul>
<li><a href="#">首页</a></li>
<li><a href="#">关于</a></li>
<li><a href="#">服务</a></li>
</ul>
</div>
<div class="main">
<h2>主要内容区域</h2>
<p>这里是网站的主要内容...</p>
</div>
</div>
<div class="footer">
<p>© 2023 我的网站. 保留所有权利.</p>
</div>
</div>
</body>
</html>

2. 样式表类型

2.1 嵌入样式表

详细解释:

  • 在HTML文档的<head>部分使用<style>标签定义CSS样式
  • 适用于单页应用或小型网站
  • 优点:样式与内容在同一文件,无需额外HTTP请求
  • 缺点:无法跨页面共享样式,不利于大型项目维护

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>嵌入样式表示例</title>
<style>
/* 全局样式 */
body {
font-family: "Microsoft YaHei", sans-serif;
line-height: 1.6;
color: #333;
}

/* 类选择器 */
.highlight {
background-color: #ffffcc;
padding: 5px;
border-radius: 3px;
}

/* ID选择器 */
#main-title {
color: #0066cc;
text-align: center;
margin-bottom: 20px;
}

/* 伪类选择器 */
a:hover {
text-decoration: underline;
color: #ff6600;
}
</style>
</head>
<body>
<h1 id="main-title">嵌入样式表示例</h1>
<p class="highlight">这是一个使用嵌入样式表的示例。</p>
<a href="#">悬停查看效果</a>
</body>
</html>

2.2 外部样式表

详细解释:

  • 将CSS代码保存在单独的.css文件中,通过<link>标签或@import语句引入
  • 优点:样式与内容分离,便于维护;样式可跨页面共享;浏览器可缓存CSS文件
  • 最佳实践:将CSS文件放在<head>中,避免”无样式内容闪烁”(FOUC)

示例:

  1. 创建styles.css文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/* 全局重置 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

/* 布局样式 */
.container {
width: 90%;
max-width: 1200px;
margin: 0 auto;
}

/* 导航栏样式 */
.navbar {
background: #222;
color: white;
padding: 10px 0;
}

.navbar ul {
display: flex;
list-style: none;
}

.navbar li {
margin-right: 20px;
}

.navbar a {
color: white;
text-decoration: none;
}

/* 卡片样式 */
.card {
border: 1px solid #ddd;
border-radius: 5px;
padding: 15px;
margin: 15px 0;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
  1. 在HTML中引入:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>外部样式表示例</title>
<!-- 推荐方式:使用link标签 -->
<link rel="stylesheet" href="styles.css">

<!-- 不推荐但可行的方式:使用@import -->
<!-- <style>
@import url("styles.css");
</style> -->
</head>
<body>
<div class="container">
<nav class="navbar">
<ul>
<li><a href="#">首页</a></li>
<li><a href="#">产品</a></li>
<li><a href="#">服务</a></li>
<li><a href="#">联系我们</a></li>
</ul>
</nav>

<div class="card">
<h2>欢迎访问</h2>
<p>这是一个使用外部样式表的示例。</p>
</div>
</div>
</body>
</html>

2.3 内联样式

详细解释:

  • 直接在HTML元素的style属性中定义CSS样式
  • 优先级最高,但最不推荐使用
  • 仅适用于特殊场景(如动态生成的样式、邮件HTML等)
  • 严重违反内容与表现分离原则

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>内联样式示例</title>
</head>
<body>
<div style="width: 300px; height: 200px; background-color: #4CAF50;
border: 2px solid #333; border-radius: 5px;
padding: 15px; color: white; text-align: center;">
<h3 style="margin-top: 0;">内联样式示例</h3>
<p style="line-height: 1.5;">这是直接在元素中定义的样式。<br>
优先级高于外部和嵌入样式表。</p>
<button style="background: #fff; color: #4CAF50; border: none;
padding: 8px 15px; border-radius: 3px;
cursor: pointer;">点击我</button>
</div>

<p>注意:内联样式会使HTML代码变得混乱,难以维护,<span style="color: red; font-weight: bold;">不建议在实际项目中使用</span></p>
</body>
</html>

3. 注释

详细解释:

  • CSS注释使用/* 注释内容 */语法
  • 注释可以跨多行
  • 用于解释代码、临时禁用样式、团队协作等
  • 不会被浏览器解析和渲染

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/* 
全局样式重置
作者:张三
日期:2023-10-15
*/
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

/* 主标题样式 - 重要:不要修改此样式 */
#main-title {
color: #0066cc;
/* font-size: 24px; 临时禁用字体大小设置 */
text-align: center;
margin-bottom: 20px;
}

/*
导航栏样式
包含水平导航和响应式设计
*/
.navbar {
background: #222;
color: white;
padding: 10px 0;
/* 以下样式用于响应式设计
@media (max-width: 768px) {
display: none;
}
*/
}

4. 样式选择器

4.1 元素选择器

详细解释:

  • 选择所有指定类型的HTML元素
  • 语法:元素名 { 属性: 值; }
  • 适用于需要统一设置某类元素样式的场景

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 选择所有段落元素 */
p {
font-size: 16px;
line-height: 1.5;
color: #333;
}

/* 选择所有h1-h6标题元素 */
h1, h2, h3, h4, h5, h6 {
font-family: "Microsoft YaHei", sans-serif;
color: #0066cc;
margin-bottom: 15px;
}

/* 选择所有无序列表和有序列表 */
ul, ol {
margin-left: 20px;
list-style-type: disc;
}

4.2 ID选择器

详细解释:

  • 选择具有特定id属性的元素
  • 语法:#id名 { 属性: 值; }
  • 优先级高于类选择器
  • 每个id在页面中应唯一

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* 选择id为"main-header"的元素 */
#main-header {
background-color: #333;
color: white;
padding: 20px;
text-align: center;
}

/* 选择id为"contact-form"的表单元素 */
#contact-form {
max-width: 600px;
margin: 0 auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 5px;
}

4.3 类选择器

详细解释:

  • 选择具有特定class属性的元素
  • 语法:.类名 { 属性: 值; }
  • 可以应用于多个元素
  • 优先级低于ID选择器,高于元素选择器

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* 选择所有class为"btn"的元素 */
.btn {
display: inline-block;
padding: 8px 15px;
background: #0066cc;
color: white;
text-decoration: none;
border-radius: 3px;
}

/* 选择class为"btn-primary"的元素 */
.btn-primary {
background: #0066cc;
}

/* 选择class为"btn-danger"的元素 */
.btn-danger {
background: #cc0000;
}

/* 选择同时具有"btn"和"large"类的元素 */
.btn.large {
padding: 12px 25px;
font-size: 18px;
}

4.4 子选择器

详细解释:

  • 选择作为特定父元素直接子元素的元素
  • 语法:父元素 > 子元素 { 属性: 值; }
  • 与后代选择器不同,仅选择直接子元素

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* 选择div的直接子元素p(不包括嵌套的p) */
div > p {
color: blue;
}

/* 选择导航栏中直接的li元素(不包括嵌套的ul中的li) */
.navbar > ul > li {
margin-right: 15px;
}

/* 选择表格中直接的tr元素 */
table > tr {
background-color: #f0f0f0;
}

4.5 后代选择器

详细解释:

  • 选择作为特定祖先元素后代的所有元素(无论嵌套多深)
  • 语法:祖先元素 后代元素 { 属性: 值; }
  • 与子选择器不同,会匹配所有层级的后代

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* 选择div内所有p元素,无论嵌套多深 */
div p {
line-height: 1.6;
}

/* 选择导航栏内所有a元素 */
.navbar a {
color: white;
text-decoration: none;
}

/* 选择文章内所有列表项 */
.article ul li {
margin-bottom: 8px;
}

4.6 属性选择器

详细解释:

  • 选择具有特定属性或属性值的元素
  • 语法:元素[属性]元素[属性="值"]
  • 多种匹配方式:包含、开头、结尾等

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* 选择所有具有title属性的a元素 */
a[title] {
border-bottom: 1px dashed #0066cc;
}

/* 选择所有href属性以"https"开头的a元素 */
a[href^="https"] {
color: green;
}

/* 选择所有href属性包含"example.com"的a元素 */
a[href*="example.com"] {
font-weight: bold;
}

/* 选择所有href属性以".pdf"结尾的a元素 */
a[href$=".pdf"] {
background: url("pdf-icon.png") no-repeat left center;
padding-left: 20px;
}

/* 选择所有class属性包含"btn"的元素 */
[class*="btn"] {
cursor: pointer;
}

4.7 通配符选择器

详细解释:

  • 选择文档中的所有元素
  • 语法:* { 属性: 值; }
  • 通常用于全局重置样式
  • 优先级最低

示例:

1
2
3
4
5
6
7
8
9
10
11
/* 全局重置 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

/* 为所有元素添加过渡效果 */
* {
transition: all 0.3s ease;
}

4.8 群组选择器

详细解释:

  • 将多个选择器组合在一起,应用相同的样式
  • 语法:选择器1, 选择器2, 选择器3 { 属性: 值; }
  • 减少代码重复

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 为所有标题设置相同字体 */
h1, h2, h3, h4, h5, h6 {
font-family: "Microsoft YaHei", sans-serif;
}

/* 为所有表单元素设置相同边框 */
input, select, textarea {
border: 1px solid #ccc;
padding: 8px;
border-radius: 3px;
}

/* 为所有按钮和链接设置悬停效果 */
.btn, a {
transition: all 0.2s ease;
}

.btn:hover, a:hover {
opacity: 0.9;
}

5. 背景

5.1 背景属性详解

background-color

详细解释:

  • 设置元素的背景颜色
  • 可以使用颜色名称、十六进制值、RGB值、RGBA值等
  • 透明背景:transparentrgba(0,0,0,0)

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 使用颜色名称 */
div {
background-color: lightblue;
}

/* 使用十六进制值 */
.header {
background-color: #333333;
}

/* 使用RGB值 */
.banner {
background-color: rgb(255, 0, 0);
}

/* 使用RGBA值(带透明度) */
.modal {
background-color: rgba(0, 0, 0, 0.5);
}

background-position

详细解释:

  • 设置背景图像的位置
  • 可以使用关键字(如topcenterbottomleftright
  • 也可以使用百分比或像素值
  • 语法:background-position: [水平位置] [垂直位置];

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* 使用关键字 */
.bg1 {
background-image: url("pattern.png");
background-position: top left;
}

/* 使用百分比 */
.bg2 {
background-image: url("logo.png");
background-position: 50% 50%; /* 水平和垂直都居中 */
}

/* 使用像素值 */
.bg3 {
background-image: url("icon.png");
background-position: 10px 20px;
}

/* 混合使用 */
.bg4 {
background-image: url("watermark.png");
background-position: right 10px;
}

background-size

详细解释:

  • 设置背景图像的尺寸
  • 常用值:
    • auto:默认值,保持原始尺寸
    • cover:等比缩放图像,使图像完全覆盖背景区域
    • contain:等比缩放图像,使图像完整显示在背景区域
    • 具体尺寸:如100px 200px,或50% 100%

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/* 保持原始尺寸 */
.original {
background-size: auto;
}

/* 完全覆盖背景区域 */
.cover {
background-image: url("bg.jpg");
background-size: cover;
}

/* 完整显示在背景区域 */
.contain {
background-image: url("bg.jpg");
background-size: contain;
}

/* 具体尺寸 */
.sized {
background-image: url("icon.png");
background-size: 50px 50px;
}

/* 百分比尺寸 */
.percent {
background-image: url("pattern.png");
background-size: 50% 100%;
}

background-repeat

详细解释:

  • 设置背景图像如何重复
  • 常用值:
    • repeat:默认值,水平和垂直方向都重复
    • repeat-x:仅水平方向重复
    • repeat-y:仅垂直方向重复
    • no-repeat:不重复
    • space:均匀分布,不裁剪图像
    • round:缩放图像以适应区域

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/* 默认:水平和垂直重复 */
.repeat {
background-image: url("pattern.png");
background-repeat: repeat;
}

/* 仅水平重复 */
.repeat-x {
background-image: url("border-top.png");
background-repeat: repeat-x;
}

/* 仅垂直重复 */
.repeat-y {
background-image: url("border-left.png");
background-repeat: repeat-y;
}

/* 不重复 */
.no-repeat {
background-image: url("logo.png");
background-repeat: no-repeat;
}

/* 均匀分布 */
.space {
background-image: url("icon.png");
background-repeat: space;
}

/* 缩放以适应 */
.round {
background-image: url("icon.png");
background-repeat: round;
}

background-origin

详细解释:

  • 设置背景图像的定位区域
  • 常用值:
    • border-box:背景从边框区域开始
    • padding-box:背景从内边距区域开始(默认)
    • content-box:背景从内容区域开始

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* 背景从边框区域开始 */
.origin-border {
border: 10px solid rgba(0,0,0,0.2);
padding: 20px;
background-image: url("bg.png");
background-origin: border-box;
}

/* 背景从内边距区域开始(默认) */
.origin-padding {
border: 10px solid rgba(0,0,0,0.2);
padding: 20px;
background-image: url("bg.png");
background-origin: padding-box;
}

/* 背景从内容区域开始 */
.origin-content {
border: 10px solid rgba(0,0,0,0.2);
padding: 20px;
background-image: url("bg.png");
background-origin: content-box;
}

background-clip

详细解释:

  • 设置背景的绘制区域
  • 常用值:
    • border-box:背景延伸至边框外沿(默认)
    • padding-box:背景延伸至内边距外沿
    • content-box:背景仅在内容区域显示

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* 背景延伸至边框外沿(默认) */
.clip-border {
border: 10px solid rgba(0,0,0,0.2);
padding: 20px;
background: linear-gradient(to right, #0066cc, #cc0000);
background-clip: border-box;
}

/* 背景延伸至内边距外沿 */
.clip-padding {
border: 10px solid rgba(0,0,0,0.2);
padding: 20px;
background: linear-gradient(to right, #0066cc, #cc0000);
background-clip: padding-box;
}

/* 背景仅在内容区域显示 */
.clip-content {
border: 10px solid rgba(0,0,0,0.2);
padding: 20px;
background: linear-gradient(to right, #0066cc, #cc0000);
background-clip: content-box;
}

background-attachment

详细解释:

  • 设置背景图像是否固定或随内容滚动
  • 常用值:
    • scroll:默认值,背景随内容滚动
    • fixed:背景固定,不随内容滚动
    • local:背景随元素内容滚动

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 背景随内容滚动(默认) */
.attachment-scroll {
background-image: url("bg.jpg");
background-attachment: scroll;
}

/* 背景固定,不随内容滚动 */
.attachment-fixed {
background-image: url("bg.jpg");
background-attachment: fixed;
height: 100vh; /* 通常与视口高度一起使用 */
}

/* 背景随元素内容滚动 */
.attachment-local {
height: 300px;
overflow: auto;
background-image: url("bg.jpg");
background-attachment: local;
}

background-image

详细解释:

  • 设置元素的背景图像
  • 可以使用URL指定图像路径
  • 可以设置多个背景图像(逗号分隔)
  • 可以使用渐变作为背景

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* 单个背景图像 */
.single-bg {
background-image: url("bg.jpg");
}

/* 多个背景图像 */
.multiple-bg {
background-image: url("pattern.png"), url("overlay.png");
background-position: top left, bottom right;
background-repeat: repeat, no-repeat;
}

/* 线性渐变背景 */
.linear-gradient {
background-image: linear-gradient(to right, #0066cc, #cc0000);
}

/* 径向渐变背景 */
.radial-gradient {
background-image: radial-gradient(circle, #0066cc, #cc0000);
}

5.2 背景简写

详细解释:

  • 使用background属性可以一次性设置多个背景属性
  • 顺序不严格,但建议按标准顺序书写
  • 标准顺序:background: [color] [image] [repeat] [attachment] [position]/[size];

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* 基本简写 */
.simple {
background: #f0f0f0 url("bg.jpg") no-repeat fixed center;
}

/* 完整简写 */
.full {
background: #f0f0f0 url("bg.jpg") no-repeat fixed center center / cover;
}

/* 多个背景的简写 */
.multiple {
background:
url("pattern.png") repeat,
url("overlay.png") no-repeat 100% 100%,
linear-gradient(to bottom, rgba(255,255,255,0.5), rgba(255,255,255,0)) fixed;
}

/* 只设置颜色 */
.color-only {
background: #333;
}

/* 只设置图像 */
.image-only {
background: url("bg.jpg") no-repeat center;
}

6. 边框

6.1 边框属性详解

border-color

详细解释:

  • 设置边框的颜色
  • 可以为四条边设置不同颜色
  • 语法:border-color: [上] [右] [下] [左];

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* 所有边框相同颜色 */
.all-same {
border-color: #0066cc;
}

/* 上下相同,左右相同 */
.top-bottom {
border-color: #0066cc #cc0000;
}

/* 四条边各不相同 */
.four-different {
border-color: #0066cc #cc0000 #00cc66 #6600cc;
}

/* 分别设置每条边 */
.specific {
border-top-color: #0066cc;
border-right-color: #cc0000;
border-bottom-color: #00cc66;
border-left-color: #6600cc;
}

border-width

详细解释:

  • 设置边框的宽度
  • 可以为四条边设置不同宽度
  • 语法:border-width: [上] [右] [下] [左];
  • 常用单位:px、em、rem等

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* 所有边框相同宽度 */
.all-same {
border-width: 2px;
}

/* 上下相同,左右相同 */
.top-bottom {
border-width: 1px 3px;
}

/* 四条边各不相同 */
.four-different {
border-width: 1px 2px 3px 4px;
}

/* 分别设置每条边 */
.specific {
border-top-width: 1px;
border-right-width: 2px;
border-bottom-width: 3px;
border-left-width: 4px;
}

border-style

详细解释:

  • 设置边框的样式
  • 可以为四条边设置不同样式
  • 语法:border-style: [上] [右] [下] [左];

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* 所有边框相同样式 */
.all-same {
border-style: solid;
}

/* 上下相同,左右相同 */
.top-bottom {
border-style: dashed dotted;
}

/* 四条边各不相同 */
.four-different {
border-style: solid dashed dotted double;
}

/* 分别设置每条边 */
.specific {
border-top-style: solid;
border-right-style: dashed;
border-bottom-style: dotted;
border-left-style: double;
}

单独边框属性

详细解释:

  • 可以单独设置某条边的边框
  • 包括:border-topborder-rightborder-bottomborder-left
  • 每个属性都可以设置宽度、样式和颜色

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* 设置上边框 */
.border-top {
border-top: 2px solid #0066cc;
}

/* 设置右边框 */
.border-right {
border-right: 1px dashed #cc0000;
}

/* 设置下边框 */
.border-bottom {
border-bottom: 3px double #00cc66;
}

/* 设置左边框 */
.border-left {
border-left: 4px groove #6600cc;
}

/* 混合使用 */
.mixed {
border-top: 1px solid #000;
border-right: none;
border-bottom: 2px dashed #333;
border-left: 1px dotted #666;
}

6.2 边框简写

详细解释:

  • 使用border属性可以一次性设置边框的宽度、样式和颜色
  • 语法:border: [宽度] [样式] [颜色];
  • 可以针对特定边使用:border-topborder-right

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/* 所有边框相同 */
.all {
border: 1px solid #000;
}

/* 设置上边框 */
.top {
border-top: 2px solid #0066cc;
}

/* 设置右边框 */
.right {
border-right: 1px dashed #cc0000;
}

/* 设置下边框 */
.bottom {
border-bottom: 3px double #00cc66;
}

/* 设置左边框 */
.left {
border-left: 4px groove #6600cc;
}

/* 混合使用 */
.mixed {
border: 1px solid #ddd;
border-top: 2px solid #0066cc;
border-right: none;
}

7. 文字属性

7.1 文字属性详解

color

详细解释:

  • 设置文本颜色
  • 可以使用颜色名称、十六进制值、RGB值、RGBA值等

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* 颜色名称 */
.name {
color: red;
}

/* 十六进制值 */
.hex {
color: #0066cc;
}

/* RGB值 */
.rgb {
color: rgb(0, 102, 204);
}

/* RGBA值(带透明度) */
.rgba {
color: rgba(0, 102, 204, 0.8);
}

/* 系统颜色 */
.system {
color: windowtext; /* 使用系统文本颜色 */
}

font-size

详细解释:

  • 设置文本的大小
  • 常用单位:px、em、rem、%、pt等
  • 相对单位(em、rem、%)会根据父元素或根元素的字体大小进行缩放

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* 像素单位(固定大小) */
.px {
font-size: 16px;
}

/* em单位(相对于父元素) */
.em {
font-size: 1.2em; /* 1.2 × 父元素字体大小 */
}

/* rem单位(相对于根元素) */
.rem {
font-size: 1.2rem; /* 1.2 × <html>元素字体大小 */
}

/* 百分比(相对于父元素) */
.percent {
font-size: 120%; /* 120% × 父元素字体大小 */
}

/* 绝对大小关键字 */
.keywords {
font-size: large; /* 或 x-small, small, medium, large, x-large, xx-large */
}

font-weight

详细解释:

  • 设置文本的粗细
  • 常用值:normal(400)、bold(700)、bolderlighter或100-900的数字值

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* 关键字 */
.keywords {
font-weight: normal; /* 正常 */
/* 或 */
font-weight: bold; /* 加粗 */
}

/* 数字值 */
.numbers {
font-weight: 400; /* 正常 */
/* 或 */
font-weight: 700; /* 加粗 */
/* 或 */
font-weight: 600; /* 半粗体 */
}

/* 相对值 */
.relative {
font-weight: bolder; /* 比父元素更粗 */
/* 或 */
font-weight: lighter; /* 比父元素更细 */
}

font-family

详细解释:

  • 设置文本的字体
  • 指定多个字体作为备选,浏览器会使用第一个可用的字体
  • 通常包括一个具体的字体和一个通用字体族

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* 单个字体 */
.single {
font-family: "Microsoft YaHei";
}

/* 多个字体(带备选) */
.multiple {
font-family: "Microsoft YaHei", "Heiti SC", "SimSun", sans-serif;
}

/* 通用字体族 */
.generic {
font-family: serif; /* 衬线字体 */
/* 或 */
font-family: sans-serif; /* 无衬线字体 */
/* 或 */
font-family: monospace; /* 等宽字体 */
/* 或 */
font-family: cursive; /* 手写体 */
/* 或 */
font-family: fantasy; /* 装饰字体 */
}

font-variant

详细解释:

  • 设置文本的变体
  • 常用值:normalsmall-caps(小型大写字母)

示例:

1
2
3
4
5
6
7
8
9
10
11
/* 正常文本 */
.normal {
font-variant: normal;
}

/* 小型大写字母 */
.small-caps {
font-variant: small-caps;
/* 或 */
font-variant: small-caps;
}

8. 文本属性

8.1 文本属性详解

text-align

详细解释:

  • 设置文本的水平对齐方式
  • 常用值:leftrightcenterjustify(两端对齐)

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 左对齐(默认) */
.left {
text-align: left;
}

/* 右对齐 */
.right {
text-align: right;
}

/* 居中对齐 */
.center {
text-align: center;
}

/* 两端对齐 */
.justify {
text-align: justify;
}

line-height

详细解释:

  • 设置行高(行与行之间的垂直间距)
  • 可以使用无单位数值(相对于字体大小的倍数)、长度值或百分比
  • 常用于垂直居中文本

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 无单位数值(推荐) */
.unitless {
line-height: 1.5; /* 1.5 × 字体大小 */
}

/* 长度值 */
.length {
line-height: 24px;
}

/* 百分比 */
.percent {
line-height: 150%; /* 150% × 字体大小 */
}

/* 垂直居中(单行文本) */
.vertical-center {
height: 50px;
line-height: 50px; /* 与容器高度相同 */
}

text-indent

详细解释:

  • 设置首行缩进
  • 常用单位:px、em、rem、%等

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 像素单位 */
.px {
text-indent: 20px;
}

/* em单位 */
.em {
text-indent: 2em;
}

/* 百分比(相对于容器宽度) */
.percent {
text-indent: 5%;
}

/* 负值(悬挂缩进) */
.hanging {
text-indent: -20px;
padding-left: 20px;
}

text-decoration

详细解释:

  • 设置文本的装饰线
  • 常用值:noneunderlineoverlineline-throughblink
  • 可组合使用

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/* 无装饰线(默认) */
.none {
text-decoration: none;
}

/* 下划线 */
.underline {
text-decoration: underline;
}

/* 上划线 */
.overline {
text-decoration: overline;
}

/* 中划线 */
.line-through {
text-decoration: line-through;
}

/* 组合使用 */
.combined {
text-decoration: underline overline;
}

/* 指定颜色和样式 */
.specific {
text-decoration: underline;
text-decoration-color: red;
text-decoration-style: wavy;
}

letter-spacing

详细解释:

  • 设置字间距(字符之间的间距)
  • 可以使用正值(增加间距)或负值(减少间距)

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* 增加字间距 */
.spaced {
letter-spacing: 2px;
}

/* 减少字间距 */
.tight {
letter-spacing: -1px;
}

/* 相对值 */
.relative {
letter-spacing: 0.1em;
}

9. 列表

9.1 列表属性详解

list-style-type

详细解释:

  • 设置列表项标记的类型
  • 适用于有序列表(ol)和无序列表(ul)

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/* 无序列表 */
ul.disc {
list-style-type: disc; /* 默认 */
}

ul.circle {
list-style-type: circle;
}

ul.square {
list-style-type: square;
}

ul.none {
list-style-type: none; /* 无标记 */
}

/* 有序列表 */
ol.decimal {
list-style-type: decimal; /* 默认 */
}

ol.decimal-leading-zero {
list-style-type: decimal-leading-zero;
}

ol.lower-roman {
list-style-type: lower-roman;
}

ol.upper-roman {
list-style-type: upper-roman;
}

ol.lower-alpha {
list-style-type: lower-alpha;
}

ol.upper-alpha {
list-style-type: upper-alpha;
}

list-style-position

详细解释:

  • 设置列表项标记的位置
  • 常用值:insideoutside(默认)

示例:

1
2
3
4
5
6
7
8
9
/* 标记在文本内部 */
.inside {
list-style-position: inside;
}

/* 标记在文本外部(默认) */
.outside {
list-style-position: outside;
}

list-style-image

详细解释:

  • 使用图像代替列表项标记
  • 可以使用URL指定图像路径

示例:

1
2
3
4
5
6
7
8
9
/* 使用自定义图像作为列表标记 */
.custom-marker {
list-style-image: url("custom-bullet.png");
}

/* 无图像(回退到list-style-type) */
.no-image {
list-style-image: none;
}

list-style 简写

详细解释:

  • 使用list-style属性可以一次性设置列表的所有样式
  • 顺序:list-style: [type] [position] [image];

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* 基本简写 */
.simple {
list-style: square inside;
}

/* 完整简写 */
.full {
list-style: square inside url("bullet.png");
}

/* 仅设置类型 */
.type-only {
list-style: circle;
}

/* 仅设置位置 */
.position-only {
list-style: inside;
}

/* 仅设置图像 */
.image-only {
list-style: url("bullet.png");
}

10. 超链接

10.1 超链接状态详解

详细解释:

  • 超链接有四种状态,可以通过伪类选择器进行样式设置
  • 顺序建议:a:linka:visiteda:hovera:active(LVHA顺序)

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/* 未访问的链接 */
a:link {
color: #0066cc;
text-decoration: none;
}

/* 已访问的链接 */
a:visited {
color: #6600cc;
}

/* 鼠标悬停 */
a:hover {
color: #cc0000;
text-decoration: underline;
transition: all 0.2s ease;
}

/* 激活(点击)状态 */
a:active {
color: #ff6600;
}

/* 为所有状态设置共同样式 */
a {
transition: all 0.2s ease;
font-weight: bold;
}

/* 为特定链接设置样式 */
.nav-link {
padding: 5px 10px;
border-radius: 3px;
}

.nav-link:hover {
background-color: #f0f0f0;
}

11. 盒子模型

详细解释:

  • CSS盒子模型是网页布局的基础
  • 每个HTML元素都被视为一个矩形盒子
  • 盒子由四个部分组成:
    1. 内容区域(content):显示实际内容的区域
    2. 内边距(padding):内容区域与边框之间的空间
    3. 边框(border):围绕内边距和内容的边框
    4. 外边距(margin):边框外的空间,用于与其他元素的间隔

可视化表示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
+-------------------------------------------+
| MARGIN |
| +-----------------------------------+ |
| | BORDER | |
| | +---------------------------+ | |
| | | PADDING | | |
| | | +-------------------+ | | |
| | | | | | | |
| | | | CONTENT | | | |
| | | | | | | |
| | | +-------------------+ | | |
| | | | | |
| | +---------------------------+ | |
| | | |
| +-----------------------------------+ |
| |
+-------------------------------------------+

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.box {
/* 内容区域 */
width: 200px;
height: 150px;

/* 内边距 */
padding: 20px;

/* 边框 */
border: 2px solid #333;

/* 外边距 */
margin: 10px;

/* 背景(显示在padding和content区域) */
background-color: #f0f0f0;
}

注意: 默认情况下,元素的总宽度 = width + padding-left + padding-right + border-left + border-right + margin-left + margin-right

12. margin与padding

12.1 padding(内边距)

详细解释:

  • 内边距是内容区域与边框之间的空间
  • 增加内边距会扩大元素的总尺寸
  • 语法:padding: [上] [右] [下] [左];
  • 可以单独设置:padding-toppadding-rightpadding-bottompadding-left

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* 所有方向相同内边距 */
.all {
padding: 10px;
}

/* 上下相同,左右相同 */
.vertical-horizontal {
padding: 15px 20px;
}

/* 四个方向各不相同 */
.four-different {
padding: 10px 15px 20px 25px;
}

/* 单独设置 */
.specific {
padding-top: 10px;
padding-right: 15px;
padding-bottom: 20px;
padding-left: 25px;
}

12.2 margin(外边距)

详细解释:

  • 外边距是边框外的空间,用于与其他元素的间隔
  • 外边距不会影响元素自身尺寸,但会影响与其他元素的距离
  • 语法:margin: [上] [右] [下] [左];
  • 可以单独设置:margin-topmargin-rightmargin-bottommargin-left
  • 外边距合并:当两个垂直方向的外边距相邻时,它们会合并为一个外边距,取两者中的较大值

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/* 所有方向相同外边距 */
.all {
margin: 10px;
}

/* 上下相同,左右相同 */
.vertical-horizontal {
margin: 15px 20px;
}

/* 四个方向各不相同 */
.four-different {
margin: 10px 15px 20px 25px;
}

/* 单独设置 */
.specific {
margin-top: 10px;
margin-right: 15px;
margin-bottom: 20px;
margin-left: 25px;
}

/* 居中元素 */
.center {
margin: 0 auto; /* 水平居中 */
width: 80%; /* 必须指定宽度 */
}

/* 外边距合并示例 */
.p1 {
margin-bottom: 20px;
}

.p2 {
margin-top: 30px;
}
/* p1和p2之间的实际外边距为30px(较大值),而不是50px */

13. float(浮动)

详细解释:

  • 浮动使元素脱离标准文档流,向左或向右移动
  • 其他内容会环绕浮动元素
  • 常用于创建多列布局
  • 浮动元素会影响其父元素的高度(可能导致父元素高度塌陷)

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/* 向左浮动 */
.float-left {
float: left;
width: 30%;
}

/* 向右浮动 */
.float-right {
float: right;
width: 30%;
}

/* 清除浮动 */
.clearfix::after {
content: "";
display: table;
clear: both;
}

/* 清除左侧浮动 */
.clear-left {
clear: left;
}

/* 清除右侧浮动 */
.clear-right {
clear: right;
}

/* 清除两侧浮动 */
.clear-both {
clear: both;
}

浮动布局示例:

1
2
3
4
5
6
7
8
9
10
11
<div class="clearfix">
<div style="float: left; width: 30%; background: #f0f0f0; padding: 10px;">
左侧栏
</div>
<div style="float: right; width: 30%; background: #f0f0f0; padding: 10px;">
右侧栏
</div>
<div style="margin: 0 35%; background: #e0e0e0; padding: 10px;">
中间内容。由于左侧和右侧元素浮动,中间内容会自动调整宽度。
</div>
</div>

14. 块级元素、行内元素

14.1 块级元素

详细解释:

  • 块级元素独占一行
  • 默认宽度为父元素的100%
  • 可以设置width、height、margin、padding
  • 常见块级元素:<div>, <p>, <h1>-<h6>, <ul>, <ol>, <li>, <table>, <form>, <header>, <footer>, <section>, <article>

示例:

1
2
3
<div style="background: #f0f0f0; margin: 5px; padding: 10px;">div - 块级元素</div>
<p style="background: #e0e0e0; margin: 5px; padding: 10px;">p - 块级元素</p>
<h1 style="background: #d0d0d0; margin: 5px; padding: 10px;">h1 - 块级元素</h1>

14.2 行内元素

详细解释:

  • 行内元素不独占一行,与其他行内元素在同一行显示
  • 宽度由内容决定
  • 无法直接设置width、height
  • 水平方向的margin和padding有效,垂直方向无效
  • 常见行内元素:<a>, <span>, <img>, <strong>, <em>, <b>, <i>, <u>, <br>, <input>, <label>

示例:

1
2
3
<span style="background: #ffcccc;">span - 行内元素</span>
<a href="#" style="background: #ccffcc;">a - 行内元素</a>
<strong style="background: #ccccff;">strong - 行内元素</strong>

14.3 元素类型转换

详细解释:

  • 使用display属性可以转换元素类型
  • 常用值:
    • block:块级元素
    • inline:行内元素
    • inline-block:行内块元素(像行内元素一样排列,但可以设置宽高)
    • none:不显示元素

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* 转换为块级元素 */
.inline-to-block {
display: block;
}

/* 转换为行内元素 */
.block-to-inline {
display: inline;
}

/* 转换为行内块元素 */
.to-inline-block {
display: inline-block;
width: 100px;
height: 50px;
}

/* 隐藏元素 */
.hidden {
display: none;
}

15. 溢出

详细解释:

  • overflow属性控制当内容溢出元素框时的行为
  • 常用值:
    • visible:默认值,内容溢出时正常显示
    • hidden:内容溢出时被裁剪,不可见
    • scroll:内容溢出时显示滚动条(无论是否溢出)
    • auto:内容溢出时自动显示滚动条
    • clip:裁剪内容,不提供滚动机制

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* 默认:内容溢出时正常显示 */
.visible {
overflow: visible;
}

/* 内容溢出时被裁剪 */
.hidden {
overflow: hidden;
}

/* 始终显示滚动条 */
.scroll {
overflow: scroll;
}

/* 溢出时自动显示滚动条 */
.auto {
overflow: auto;
}

/* 水平溢出隐藏,垂直溢出自动滚动 */
.x-hidden-y-auto {
overflow-x: hidden;
overflow-y: auto;
}

16. 定位

16.1 定位类型详解

static(静态定位)

详细解释:

  • 默认定位方式
  • 元素在正常文档流中
  • 忽略top、bottom、left、right和z-index属性

示例:

1
2
3
4
.static {
position: static;
/* top、bottom等属性无效 */
}

relative(相对定位)

详细解释:

  • 相对于元素在正常文档流中的位置进行定位
  • 不脱离文档流,其他元素仍按正常流布局
  • 可以使用top、bottom、left、right调整位置

示例:

1
2
3
4
5
.relative {
position: relative;
top: 10px;
left: 20px;
}

absolute(绝对定位)

详细解释:

  • 相对于最近的已定位祖先元素(position不是static)进行定位
  • 脱离文档流,不占据空间
  • 如果没有已定位祖先元素,则相对于初始包含块(通常是视口)

示例:

1
2
3
4
5
.absolute {
position: absolute;
top: 10px;
right: 20px;
}

fixed(固定定位)

详细解释:

  • 相对于浏览器窗口进行定位
  • 脱离文档流,不占据空间
  • 即使页面滚动,元素位置保持不变

示例:

1
2
3
4
5
6
.fixed {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
}

sticky(粘性定位)

详细解释:

  • 相对于最近的滚动祖先元素进行定位
  • 在滚动到特定阈值前表现为相对定位,之后表现为固定定位
  • 需要指定至少一个阈值(top、bottom、left或right)

示例:

1
2
3
4
.sticky {
position: sticky;
top: 0;
}

16.2 z-index

详细解释:

  • 设置元素的堆叠顺序
  • 值越大,越靠近用户(显示在上层)
  • 仅对定位元素(position不是static)有效
  • 可以是正数、负数或auto

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.box1 {
position: absolute;
z-index: 1;
}

.box2 {
position: absolute;
z-index: 2; /* 会显示在box1之上 */
}

.box3 {
position: absolute;
z-index: -1; /* 会显示在其他元素之下 */
}

综合大例子

以下是一个包含所有知识点的综合性示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DIV+CSS综合示例</title>

<!-- 嵌入样式表 -->
<style>
/* 全局重置 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

body {
font-family: "Microsoft YaHei", "Heiti SC", "SimSun", sans-serif;
line-height: 1.6;
color: #333;
background-color: #f5f5f5;
}

/* 容器样式 */
.container {
width: 90%;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}

/* 头部样式 */
.header {
background: linear-gradient(to right, #0066cc, #003366);
color: white;
padding: 20px 0;
text-align: center;
position: relative;
}

.header::after {
content: "";
display: table;
clear: both;
}

.logo {
float: left;
font-size: 24px;
font-weight: bold;
padding: 0 20px;
}

.nav {
float: right;
}

.nav ul {
list-style: none;
display: flex;
}

.nav li {
margin-left: 20px;
}

.nav a {
color: white;
text-decoration: none;
padding: 5px 10px;
border-radius: 3px;
transition: all 0.2s ease;
}

.nav a:hover {
background-color: rgba(255, 255, 255, 0.2);
}

/* 主要内容区域 */
.main-content {
display: flex;
margin-top: 20px;
gap: 20px;
}

.sidebar {
width: 25%;
background: white;
border: 1px solid #ddd;
border-radius: 5px;
padding: 20px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}

.sidebar h2 {
color: #0066cc;
margin-bottom: 15px;
}

.sidebar ul {
list-style-type: square;
margin-left: 20px;
}

.sidebar li {
margin-bottom: 8px;
}

.content-area {
width: 75%;
}

.article {
background: white;
border: 1px solid #ddd;
border-radius: 5px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}

.article h2 {
color: #0066cc;
margin-bottom: 15px;
}

.article p {
margin-bottom: 15px;
text-indent: 2em;
}

.highlight {
background-color: #ffffcc;
padding: 5px;
border-radius: 3px;
display: inline-block;
}

.quote {
border-left: 3px solid #0066cc;
padding-left: 15px;
margin: 15px 0;
font-style: italic;
color: #666;
}

/* 卡片式布局 */
.card-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
margin-top: 20px;
}

.card {
background: white;
border: 1px solid #ddd;
border-radius: 5px;
overflow: hidden;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease;
}

.card:hover {
transform: translateY(-5px);
}

.card-img {
width: 100%;
height: 200px;
background: #f0f0f0;
background-image: linear-gradient(to right, #0066cc, #003366);
background-size: cover;
background-position: center;
}

.card-content {
padding: 20px;
}

.card h3 {
color: #0066cc;
margin-bottom: 10px;
}

/* 页脚样式 */
.footer {
background: #333;
color: white;
text-align: center;
padding: 20px 0;
margin-top: 40px;
}

/* 固定定位的返回顶部按钮 */
.back-to-top {
position: fixed;
bottom: 30px;
right: 30px;
width: 50px;
height: 50px;
background: #0066cc;
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
text-decoration: none;
font-size: 24px;
z-index: 100;
opacity: 0;
transition: opacity 0.3s ease;
}

.back-to-top.show {
opacity: 1;
}

/* 响应式设计 */
@media (max-width: 768px) {
.main-content {
flex-direction: column;
}

.sidebar, .content-area {
width: 100%;
}

.nav {
float: none;
text-align: center;
}

.nav ul {
flex-direction: column;
}

.nav li {
margin: 10px 0;
}
}
</style>

<!-- 内联样式(仅用于演示,实际项目不推荐) -->
<style>
/* 仅用于演示内联样式 */
.demo-inline {
color: red;
font-weight: bold;
background-color: #ffffcc;
padding: 5px;
border-radius: 3px;
}
</style>
</head>
<body>
<div class="container">
<header class="header">
<div class="logo">我的网站</div>
<nav class="nav">
<ul>
<li><a href="#">首页</a></li>
<li><a href="#">关于</a></li>
<li><a href="#">服务</a></li>
<li><a href="#">产品</a></li>
<li><a href="#">联系</a></li>
</ul>
</nav>
</header>

<div class="main-content">
<aside class="sidebar">
<h2>导航菜单</h2>
<ul>
<li><a href="#">首页</a></li>
<li><a href="#">关于</a></li>
<li><a href="#">服务</a></li>
<li><a href="#">产品</a></li>
<li><a href="#">博客</a></li>
<li><a href="#">联系</a></li>
</ul>

<h2 style="margin-top: 30px;">热门文章</h2>
<ul>
<li><a href="#">CSS3新特性详解</a></li>
<li><a href="#">响应式设计技巧</a></li>
<li><a href="#">Web性能优化</a></li>
<li><a href="#">JavaScript高级编程</a></li>
</ul>
</aside>

<div class="content-area">
<div class="article">
<h2>欢迎访问我的网站</h2>
<p>这是一个使用DIV+CSS布局的示例页面,展示了各种CSS特性和布局技巧。</p>
<p>本页面使用了<span class="highlight">嵌入样式表</span><span class="highlight">外部样式</span>和少量<span class="highlight">内联样式</span>(仅用于演示)。</p>

<div class="quote">
"CSS不仅仅是美化网页的工具,更是构建现代Web应用的基础。"
</div>

<p>页面采用了响应式设计,可以在不同设备上良好显示。主要使用了以下技术:</p>
<ul>
<li>Flexbox布局</li>
<li>CSS Grid</li>
<li>媒体查询</li>
<li>定位技术</li>
</ul>
</div>

<h2 style="margin-top: 20px;">特色内容</h2>
<div class="card-container">
<div class="card">
<div class="card-img"></div>
<div class="card-content">
<h3>响应式设计</h3>
<p>学习如何创建适应各种设备的网站,提升用户体验。</p>
<a href="#" class="btn">了解更多</a>
</div>
</div>

<div class="card">
<div class="card-img"></div>
<div class="card-content">
<h3>CSS动画</h3>
<p>使用CSS3实现平滑过渡和动画效果,无需JavaScript。</p>
<a href="#" class="btn">了解更多</a>
</div>
</div>

<div class="card">
<div class="card-img"></div>
<div class="card-content">
<h3>Web性能优化</h3>
<p>优化网站加载速度,提升SEO排名和用户体验。</p>
<a href="#" class="btn">了解更多</a>
</div>
</div>
</div>
</div>
</div>

<footer class="footer">
<p>© 2023 我的网站. 保留所有权利.</p>
<p>使用DIV+CSS技术构建,遵循现代Web标准。</p>
</footer>
</div>

<a href="#" class="back-to-top"></a>

<script>
// 仅用于演示返回顶部按钮
window.addEventListener('scroll', function() {
var backToTop = document.querySelector('.back-to-top');
if (window.pageYOffset > 300) {
backToTop.classList.add('show');
} else {
backToTop.classList.remove('show');
}
});

document.querySelector('.back-to-top').addEventListener('click', function(e) {
e.preventDefault();
window.scrollTo({
top: 0,
behavior: 'smooth'
});
});
</script>
</body>
</html>

总结

这个综合示例展示了以下知识点:

  1. DIV和CSS基础:使用DIV作为容器,CSS控制样式
  2. 样式表类型:嵌入样式表(主要部分)和内联样式(仅用于演示)
  3. 注释:CSS注释用于解释代码
  4. 样式选择器:元素选择器、类选择器、ID选择器、后代选择器、伪类选择器等
  5. 背景:背景颜色、背景图像、背景渐变、背景重复等
  6. 边框:边框样式、宽度、颜色
  7. 文字属性:颜色、大小、粗细、字体
  8. 文本属性:对齐、行高、首行缩进、文本装饰
  9. 列表:列表样式、位置、自定义图像
  10. 超链接:四种状态的样式设置
  11. 盒子模型:内容、内边距、边框、外边距
  12. margin与padding:设置元素间距
  13. float:创建多列布局,以及清除浮动
  14. 块级元素与行内元素:不同元素类型的特性和转换
  15. 溢出:处理内容溢出的情况
  16. 定位:static、relative、absolute、fixed、sticky定位方式
  17. z-index:控制元素堆叠顺序

这个示例还包含了响应式设计、CSS动画、Flexbox和Grid布局等现代Web技术,展示了如何将这些基础知识点应用到实际项目中。

6.1 网络应用模型

6.1.1 客户/服务器模型

  • 基本概念
    • 有一个总是打开的主机称为服务器
    • 服务于许多来自其他称为客户机的主机请求
  • 工作流程
      1. 服务器处于接收请求的状态
      1. 客户机发出服务请求,并等待接收结果
      1. 服务器收到请求后
      • 分析请求
      • 进行必要的处理
      • 得到结果并发送给客户机
  • 服务器特点
    • 运行专门提供服务的程序
    • 可以同时处理多个客户请求
      • 包括远程或本地客户
    • 不需要知道客户程序地址
  • 客户机特点
    • 必须知道服务器程序地址
  • 主要特征
    • 客户是服务请求方
    • 服务器是服务提供方
    • 举例
      • Web应用程序
        • Web服务器服务于浏览器请求
        • 处理流程
          • 接收客户机请求
          • 发送所请求对象响应
  • 常见应用
    • Web
    • 文件传输协议(FTP)
    • 远程登录
    • 电子邮件
  • 主要特点
      1. 网络中各计算机地位不平等
      • 服务器可管理客户机
        • 通过用户权限限制
      • 网络管理集中方便
        • 由少数服务器负责
      1. 客户机间不直接通信
      • 举例
        • Web应用中两个浏览器不直接通信
      1. 可扩展性不佳
      • 限制因素
        • 服务器硬件限制
        • 网络带宽限制
      • 结果
        • 服务器支持的客户机数量有限

6.1.2 P2P模型

  • 基本概念
    • 网络中的传输内容不再保存在中心服务器上
    • 每个节点同时具有下载、上传功能
    • 权利和义务大体对等
  • 特点
    • 无固定客户和服务器划分
    • 任意对等方(Peer)直接相互通信
    • 本质仍使用客户/服务器模型
      • 节点既作为客户访问资源
      • 又作为服务器提供资源
  • 优点
    • 减轻服务器计算压力
    • 消除对单个服务器的依赖
    • 任务分配到各个节点
    • 提高系统效率和资源利用率
    • 客户机间可直接共享文档
    • 可扩展性好
    • 网络健壮性强
  • 缺点
    • 占用较多内存
    • 影响整机速度
    • 对硬盘损伤较大
    • 占用大量网络流量(50%-90%)
    • 导致网络拥塞
    • ISP通常反对P2P应用

6.2 域名系统(DNS)

6.2.1 层次域名空间

  • 层次域名空间

    • 因特网采用层次树状结构的命名方法
    • 每个连接设备都有唯一的域名(Domain Name)
    • 域(Domain)是名字空间中的可管理划分
      • 可划分为子域
      • 形成多级域名结构(顶级域、二级域、三级域等)
    • 域名组成
      • 由标号序列组成
      • 标号之间用点(“.”)分隔
      • 示例:www.cskaoyan.com
        • com: 顶级域名
        • cskaoyan: 二级域名
        • www: 三级域名
  • 标号规则

    • 英文不区分大小写
    • 只能使用连字符(-),不能使用其他标点符号
    • 单个标号不超过63个字符
    • 完整域名最长不超过255个字符
    • 域名书写顺序
      • 最低级域名在最左边
      • 顶级域名在最右边
  • 顶级域名分类(TLD)

    • 国家(地区)顶级域名(nTLD)
      • .cn: 中国
      • .us: 美国
      • .uk: 英国
    • 通用顶级域名(gTLD)
      • .com: 公司
      • .net: 网络服务机构
      • .org: 非营利性组织
      • .edu: 教育机构
      • .gov: 政府部门
    • 基础结构域名
      • arpa: 用于反向域名解析(IP→域名)
  • 域名空间树状结构

      • 顶级域名
        • aero
        • com
        • net
        • org
        • edu
        • gov
        • cn
        • uk
      • 二级域名(示例)
        • cskaoyan
        • cctv
        • google
        • bj
        • edu
        • com
      • 三级域名(示例)
        • mail
        • www
        • hust
        • hit
      • 四级域名(示例)
        • mail
        • www
  • 域名管理

    • 顶级域名由ICANN管理
    • 国家顶级域名下的二级域名由各国自行管理
    • 子域可委托给其他组织管理

6.2.2 域名服务器

  • 定义
    • 域名到IP地址的解析由运行在域名服务器上的程序完成
    • 管辖范围称为区(小于或等于域)
    • 每个区设置权限域名服务器保存域名到IP地址的映射
    • 域名服务器功能
      • 进行域名到IP地址的解析
      • 具有连向其他域名服务器的信息
  • DNS服务器层次结构
    • 按层次方式组织
    • 映射分布在所有域名服务器上
    • 四种类型
      • 根域名服务器
        • 最高层次
        • 知道所有顶级域名服务器的域名和IP地址
        • 13个根域名服务器(实际是冗余服务器集群)
        • 功能
          • 管辖顶级域(如.com)
          • 通常不直接转换域名,而是指引查询方向
      • 顶级域名服务器
        • 管理在该顶级域名服务器注册的所有二级域名
        • 响应DNS查询请求
          • 可能给出最终结果
          • 可能指引下一步查询
      • 权限域名服务器(授权域名服务器)
        • 每台主机必须在此登记
        • 建议至少两台以提高可靠性
        • 功能
          • 总能将其管辖的主机名转换为IP地址
      • 本地域名服务器
        • 重要性
          • 对域名系统非常重要
        • 部署
          • ISP、大学或院系可拥有
        • 功能
          • 接收主机的DNS查询请求
          • 在Windows系统中配置为

6.2.3 域名解析过程

  • DNS协议的作用(2021)
  • 域名解析定义
    • 将域名转化为IP地址的过程
    • 客户端通过DNS客户端构造DNS请求报文,以UDP数据报方式发往本地域名服务器
  • 域名解析方式
    • 递归查询
      • 主机向本地域名服务器的查询方式
      • 本地域名服务器不知道被查询域名的IP地址时,以DNS客户身份向根域名服务器继续查询
    • 迭代查询
      • 本地域名服务器向其他域名服务器的查询方式
      • DNS的工作原理(2016、2020)
      • 服务器要么给出IP地址,要么告知下一步应查询的顶级域名服务器
  • 域名解析过程示例(y.abc.com)
    • 最多使用8个UDP报文(4查询+4回答)
    • 步骤:
      ①. 客户机向本地域名服务器发出DNS请求报文(递归查询)
      ②. 本地域名服务器查询本地缓存,若无记录则向根域名服务器发出解析请求(迭代查询)
      ③. 根域名服务器判断域名属于.com域,返回顶级域名服务器dns.com的IP地址
      ④. 本地域名服务器向dns.com发出解析请求(迭代查询)
      ⑤. dns.com判断域名属于abc.com域,返回权限域名服务器dns.abc.com的IP地址
      ⑥. 本地域名服务器向dns.abc.com发起解析请求(迭代查询)
      ⑦. dns.abc.com返回查询结果
      ⑧. 本地域名服务器保存结果到缓存并返回给客户机
  • DNS查询优化
    • 使用高速缓存
      • 缓存最近查询过的域名映射信息
      • 相同查询到达时可直接提供IP地址
      • 缓存信息会在一段时间后丢弃(映射非永久)
    • 主机端优化
      • 启动时从本地域名服务器下载全部数据库
      • 维护最近使用的域名高速缓存
      • 缓存中找不到时才使用域名服务器

6.3 文件传输协议(FTP)

6.3.1 FTP 的工作原理

  • 定义
    • 文件传输协议(File Transfer Protocol,FTP)
    • 因特网上使用最广泛的文件传输协议
    • 提供交互式访问
    • 允许指定文件类型与格式
    • 允许设置存取权限
    • 屏蔽计算机系统细节
    • 适合异构网络间文件传输
  • 功能
    • ①. 提供不同种类主机系统间的文件传输能力
    • ②. 以用户权限管理方式提供远程文件管理能力
    • ③. 以匿名FTP方式提供公用文件共享能力
  • 工作方式
    • 采用客户/服务器模式
    • 使用TCP可靠传输服务
    • 一个服务器进程可服务多个客户进程
  • 服务器组成
    • 主进程
      • 负责接收新请求
    • 从属进程
      • 负责处理单个请求
  • 工作步骤
    • ①. 打开熟知端口21(控制端口)
    • ②. 等待客户进程连接请求
    • ③. 启动从属进程处理请求
    • ④. 从属进程处理完毕后终止
    • ⑤. 主进程继续等待其他请求
    • 主进程与从属进程并发执行
  • 会话特性
    • 服务器必须保留用户状态信息
    • 必须关联用户账户与控制连接
    • 必须追踪用户远程目录当前位置

6.3.2 控制连接与数据连接

  • FTP使用两个并行的TCP连接
    • 控制连接(服务器端口号21)
    • 数据连接(服务器端口号20)
  • ①. 控制连接
    • 服务器监听21号端口
    • 传输控制信息
      • 连接请求
      • 传送请求等
    • 不用于传送文件
    • 在整个会话期间保持打开状态
  • ②. 数据连接
    • 服务器创建
    • 用于实际数据传输
    • 按需创建和关闭
    • 传输文件内容
    • 每次数据传输建立新的连接

6.4 电子邮件

6.4.1 电子邮件系统的组成结构

  • 电子邮件特点
    • 异步通信方式
    • 通信时不需要双方同时在场
    • 邮件存放在收件人邮箱中,可随时读取
  • 主要组成构件
    • 用户代理(User Agent)
      • 定义:用户与电子邮件系统的接口
      • 功能
        • 撰写
        • 显示
        • 邮件处理
      • 常见实例
        • Outlook
        • Foxmail
    • 邮件服务器
      • 功能
        • 发送和接收邮件
        • 报告邮件传送状态
      • 工作模式:客户/服务器模式
      • 特点:可同时充当客户和服务器
    • 电子邮件协议
      • 邮件发送协议
        • 用途
          • 用户代理→邮件服务器
          • 邮件服务器之间
        • 实例:SMTP
          • 通信方式:推(Push)
      • 邮件读取协议
        • 用途:用户代理从邮件服务器读取邮件
        • 实例:POP3
          • 通信方式:拉(Pull)
  • 电子邮件收发过程
    ①. 发件人撰写邮件
    ②. 用户代理通过SMTP发送邮件到发送端邮件服务器
    ③. 发送端邮件服务器将邮件放入缓存队列
    ④. SMTP客户与接收端SMTP服务器建立TCP连接并发送邮件
    ⑤. 接收端SMTP服务器将邮件放入收件人邮箱
    ⑥. 收件人通过POP3/IMAP协议取回邮件

6.4.2 电子邮件格式与MIME

  • ①. 电子邮件格式
    • 电子邮件分为信封和内容两大部分
      • 邮件内容分为首部和主体两部分
        • RFC 822规定了邮件的首部格式
        • 主体部分由用户自由撰写
    • 邮件内容的首部包含首部行
      • 每个首部行由关键字后跟冒号和值组成
        • 必需关键字:To
          • 填入一个或多个收件人的电子邮件地址
            • 格式:收件人邮箱名@邮箱所在主机的域名
        • 可选关键字:Subject
          • 邮件的主题
        • 必填关键字:From
          • 通常由邮件系统自动填入
    • 首部与主体之间用一个空行分割
  • ②. 多用途因特网邮件扩展 (MIME)
    • SMTP只能传送7位ASCII码文本邮件
      • 无法传送非英语国家文字
      • 无法传送可执行文件及其他二进制对象
    • MIME的作用
      • 未改动或取代SMTP
      • 发送端:将非ASCII码数据转换为ASCII码数据
      • 接收端:将ASCII码数据逆转换为非ASCII码数据
    • MIME主要包括三部分内容
      • 5个新的邮件首部字段
        • MIME版本
        • 内容描述
        • 内容标识
        • 传送编码
        • 内容类型
      • 定义了许多邮件内容的格式
        • 对多媒体电子邮件的表示方法进行标准化
      • 定义了传送编码
        • 可对任何内容格式进行转换
        • 不会被邮件系统改变

6.4.3 SMTP 和 POP3

  • 1.SMTP
    • 简单邮件传输协议 (Simple Mail Transfer Protocol,SMTP)
      • 提供可靠且有效的电子邮件传输的协议
      • 控制两个相互通信的SMTP进程交换信息
      • 采用客户/服务器模式
        • 发送邮件的SMTP进程是SMTP客户
        • 接收邮件的SMTP进程是SMTP服务器
      • 使用TCP连接,端口号为25
    • SMTP 通信的三个阶段
      • (1)连接建立
        • SMTP客户与接收方SMTP服务器建立TCP连接
        • SMTP服务器发出220 Service ready
        • SMTP客户发送HELO命令,附上发送方的主机名
        • TCP连接在发送方和接收方邮件服务器之间直接建立
      • (2)邮件传送
        • 从MAIL命令开始,后面有发件人的地址
        • 一个或多个RCPT命令,格式为RCPT TO:<收件人地址>
        • 客户端使用DATA命令开始传送邮件内容
        • .表示邮件内容的结束
      • (3)连接释放
        • SMTP客户发送QUIT命令
        • SMTP服务器返回221(服务关闭)
  • 2.POP3 和 IMAP
    • 邮局协议 (Post Office Protocol,POP)
      • 版本:POP3
      • 采用客户/服务器模式
      • 传输层使用TCP,端口号为110
      • 两种工作方式
        • 下载并保留
        • 下载并删除
    • 因特网报文存取协议(IMAP)
      • 比POP复杂
      • 提供创建文件夹、移动邮件、查询邮件等联机命令
      • IMAP服务器维护会话用户的状态信息
      • 允许用户代理只获取报文的某些部分
    • 基于万维网的电子邮件
      • 用户浏览器与邮件服务器之间使用HTTP
      • 不同邮件服务器之间传送邮件时使用SMTP

6.5 万维网(WwW)

6.5.1 WwW 的概念与组成结构

  • 万维网(WWW)定义
    • 分布式、联机式的信息存储空间
    • 资源由URL标识
    • 通过HTTP协议传输
    • 使用超链接实现站点间访问
  • 三个核心标准
    • 统一资源定位符(URL)
      • 功能:标识万维网文档
      • 格式:<协议>://<主机>:<端口>/<路径>
      • 特点:不区分大小写
    • 超文本传输协议(HTTP)
      • 应用层协议
      • 使用TCP连接
    • 超文本标记语言(HTML)
      • 文档结构标记语言
      • 描述页面信息和格式
  • 工作模式
    • 客户/服务器模式
      • 浏览器:客户程序
      • Web服务器:服务器程序
    • 工作流程
      ①. 浏览器(指定URL)与服务器建立连接
      ②. 服务器将URL转换为文件路径并返回信息
      ③. 通信完成关闭连接
  • 万维网与因特网关系
    • 构成因特网最主要部分
    • 还包括:电子邮件、Usenet、新闻组

6.5.2 超文本传输协议(HTTP)

  • 定义
    • 浏览器与服务器请求和传送文档的协议
    • 面向事务的应用层协议
  • HTTP操作过程
    • 域名解析
    • TCP连接建立(端口80)
    • HTTP请求
    • HTTP响应
    • TCP连接释放
    • 用户点击事件顺序示例
      • URL分析
      • DNS解析
      • TCP连接
      • HTTP请求
      • HTTP响应
      • TCP释放
      • 页面显示
  • HTTP特点
    • 使用TCP保证可靠传输
    • 无连接
    • 无状态
    • Cookie机制
      • 识别码生成
      • Set-cookie首部
      • Cookie首部
    • 连接方式
      • 非持续连接(HTTP/1.0)
        • 每个对象单独TCP连接
        • 2×RTT开销
      • 持续连接(HTTP/1.1)
        • 非流水线
        • 流水线
  • HTTP报文结构
    • 请求报文
      • 请求行(方法、URL、版本)
      • 首部行
      • 实体主体
    • 响应报文
      • 状态行(版本、状态码、短语)
      • 首部行
      • 实体主体
    • 常用方法
      • GET
      • HEAD
      • POST
      • PUT
      • DELETE
  • HTTP请求报文示例
    • 以太网帧结构
    • IP首部
    • TCP首部
    • HTTP请求内容解析

5.1 传输层提供的服务

5.1.1 传输层的功能

  • 基本概念
    • 位于网络层之上、应用层之下
    • 为运行在不同主机上的进程之间提供逻辑通信
    • 面向通信部分的最高层,用户功能中的最低层
    • 即使网络层协议不可靠,也能为应用程序提供可靠服务
  • 通信特点
    • 只有主机协议栈才有传输层
    • 路由器转发分组只用到下三层功能
    • 传输层只存在于通信子网以外的主机中
  • 主要功能
    • 应用进程之间的逻辑通信
      • 通信的真正端点是主机中的进程
      • 端到端的逻辑通信
    • 复用和分用
      • 复用:不同应用进程使用同一传输协议
      • 分用:正确交付数据到目的应用进程
    • 差错检测
      • 检测报文首部和数据部分
      • TCP:出错则要求重发
      • UDP:出错则直接丢弃
      • 网络层只检验IP首部
    • 提供两种传输协议
      • 面向连接的TCP
        • 提供可靠的全双工信道
      • 无连接的UDP
        • 提供不可靠信道

5.1.2 传输层的寻址与端口

  • ①. 端口的作用
    • 端口能让应用层的各种进程将其数据通过端口向下交付给传输层

    • 让传输层知道应当将其报文段中的数据向上通过端口交付给应用层相应的进程

    • 端口在传输层的作用类似于IP地址在网络层的作用

      • IP地址标识的是主机
      • 端口标识的是主机中的应用进程
    • 各层服务访问点:

      • 数据链路层:帧的”类型”字段
      • 网络层:IP数据报的”协议”字段
      • 传输层:”端口号”字段
      • 应用层:”用户界面”
    • 协议端口与硬件端口的区别

      • 协议端口是软件端口
      • 硬件端口是不同硬件设备交互的接口
      • 软件端口是应用层协议进程与传输实体交互的地址
      • 传输层使用软件端口
    • ②. 端口号

      • 应用进程通过端口号进行标识
      • 端口号长度为16比特,可表示65536(2¹⁶)个不同端口号
      • 端口号只具有本地意义
        • 只标识本计算机应用层中的各进程
        • 不同计算机的相同端口号没有联系
      • 端口号分类:
        • 服务器端使用的端口号
          • 熟知端口号(0~1023)
            • IANA指派给TCP/IP重要应用程序
            • 常用熟知端口号:
              • FTP: 21
              • TELNET: 23
              • SMTP: 25
              • DNS: 53
              • TFTP: 69
              • HTTP: 80
              • SNMP: 161
          • 登记端口号(1024~49151)
            • 供没有熟知端口号的应用程序使用
            • 必须在IANA登记以防止重复
        • 客户端使用的端口号(49152~65535)
          • 也称短暂端口号
          • 仅在客户进程运行时动态选择
          • 通信结束后端口号可复用
    • ③. 套接字

      • 网络中通过IP地址标识不同主机
      • 通过端口号标识主机中的不同应用进程
      • 套接字(Socket) = IP地址:端口号
        • 唯一标识网络中的一台主机上的一个应用进程
        • 是一个通信端点
      • 通信过程:
        • 主机A发给主机B的报文包含目的端口号和源端口号
        • 源端口号是”返回地址”的一部分
        • B发回A的报文中的目的端口号是A到B报文的源端口号
        • 完整返回地址是A的IP地址和源端口号

5.1.3 无连接服务与面向连接服务

  • TCP/IP传输协议
    • 面向连接的传输控制协议 (TCP)
      • 特点
        • 全双工的可靠逻辑信道
        • 通信前需建立连接
        • 数据传输结束后释放连接
        • 不提供广播/多播服务
      • 可靠性措施
        • 确认机制
        • 流量控制
        • 计时器
        • 连接管理
      • 适用场景
        • 文件传输协议(FTP)
        • 超文本传输协议(HTTP)
        • 远程登录(TELNET)
    • 无连接的用户数据报协议 (UDP)
      • 特点
        • 不可靠的逻辑信道
        • 通信前无需建立连接
        • 无确认机制
      • 附加服务
        • 多路复用
        • 数据错误检查
      • 优势
        • 协议简单
        • 执行速度快
        • 实时性好
      • 适用场景
        • 小文件传送协议(TFTP)
        • DNS
        • SNMP
        • 实时传输协议(RTP)

5.2 UDP 协议

5.2.1 UDP 数据报

  • UDP概述
    • UDP特点
      • 仅在IP数据报服务上增加复用、分用和差错检测功能
      • 优点
          1. 无须建立连接
          1. 无连接状态
          1. 首部开销小(8B)
          1. 没有拥塞控制
          1. 支持多种交互通信方式
      • 应用场景
        • DNS、SNMP等一次性传输较少数据的应用
        • 多媒体应用(IP电话、视频会议、流媒体等)
    • UDP可靠性
      • 不保证可靠交付
      • 可靠性可由应用层实现
    • UDP报文处理
      • 面向报文
      • 保留报文边界
      • 报文不可分割
  • UDP首部格式
    • 组成
      • 源端口(2B)
      • 目的端口(2B)
      • 长度(2B)
      • 检验和(2B)
    • 字段说明
      • 源端口:源端口号,可选
      • 目的端口:目的端口号,必须
      • 长度:UDP数据报总长度(最小8)
      • 检验和:可选,全0表示不计算
    • 处理流程
      • 根据目的端口交付应用进程
      • 端口错误处理:丢弃报文并发送ICMP差错报文

5.2.2 UDP 检验

  • UDP检验和计算
    • 伪首部
      • 12字节临时添加
      • 不向下传送也不向上递交
      • 用于计算检验和
    • 计算方法
      • 发送方
        • 检验和字段置全0
        • 伪首部+UDP数据报视为16位字串接
        • 数据部分非偶数字节时补全0字节(不发送)
        • 二进制反码计算16位字和
        • 和的二进制反码写入检验和字段
      • 接收方
        • 接收数据报+伪首部(非偶数字节补全0)
        • 二进制反码求16位字和
        • 无差错时结果为全1
        • 有差错则丢弃数据报
    • 二进制反码求和规则
      • 运算规则
        • 低位到高位逐列计算
        • 0+0=0
        • 0+1=1
        • 1+1=0(进位1)
      • 最高位进位处理
        • 结果最低位加1(回卷)
    • 特点
      • 校错能力不强
      • 优点:简单、处理速度快

5.3 TCP 协议

5.3.1 TCP 协议的特点

  • TCP概述
    • 在不可靠的IP层之上实现的可靠数据传输协议
    • 解决传输的可靠、有序、无丢失和不重复问题
    • TCP/IP体系中非常复杂的协议
  • 主要特点
    • ①. 面向连接
      • 传输层协议
      • TCP连接是逻辑连接
    • ②. 一对一连接
      • 每一条TCP连接只能有两个端点
      • 只能是一对一的
    • ③. 可靠交付
      • 保证数据无差错
      • 保证数据不丢失
      • 保证数据不重复
      • 保证数据有序
    • ④. 全双工通信
      • 通信双方可随时发送数据
      • 设有发送缓存和接收缓存
        • 发送缓存用途
          • ① 发送应用程序传送给发送方TCP准备发送的数据
          • ② TCP已发送但尚未收到确认的数据
        • 接收缓存用途
          • ① 按序到达但尚未被接收应用程序读取的数据
          • ② 不按序到达的数据
    • ⑤. 面向字节流
      • 应用程序和TCP交互是一次一个数据块
      • TCP视为一连串无结构的字节流
  • TCP与UDP发送方式对比
    • UDP报文长度
      • 由发送应用进程决定
    • TCP报文长度
      • 根据接收方窗口值决定
      • 根据当前网络拥塞程度决定
      • 处理方式
        • 数据块太长:划分后传送
        • 数据块太短:积累足够字节后再发送

5.3.2 TCP 报文段

  • TCP首部
    • 固定部分(20B)
      • 源端口(2B)
      • 目的端口(2B)
      • 序号(4B)
      • 确认号(4B)
      • 数据偏移(4位)
      • 保留(6位)
      • 控制位
        • 紧急位URG
        • 确认位ACK
        • 推送位PSH
        • 复位位RST
        • 同步位SYN
        • 终止位FIN
      • 窗口(2B)
      • 检验和(2B)
      • 紧急指针(2B)
    • 选项部分(4N B)
      • 最大报文段长度(MSS)
      • 窗口扩大
      • 时间戳
      • 其他选项
    • 填充
  • TCP数据部分
  • 封装关系
    • TCP报文段封装在IP数据报中

5.3.3 TCP 连接管理

  • TCP连接阶段
    • 连接建立
    • 数据传送
    • 连接释放
  • 连接建立解决的问题
    • 确知对方存在
    • 协商参数
    • 分配运输实体资源
  • TCP连接端点
    • 套接字(Socket)
    • 唯一由两个套接字确定
    • 同一IP地址可有多个TCP连接
    • 同一端口号可出现在多个TCP连接
  • 客户/服务器模式
    • 客户(Client):主动发起连接
    • 服务器(Server):被动等待连接
  • 1.TCP连接的建立(三次握手)
    • 步骤1:客户机发送连接请求
      • SYN=1,seq=x
      • 进入SYN-SENT状态
    • 步骤2:服务器确认
      • SYN=1,ACK=1,seq=y,ack=x+1
      • 进入SYN-RCVD状态
    • 步骤3:客户机确认
      • ACK=1,seq=x+1,ack=y+1
      • 进入ESTABLISHED状态
    • 服务器收到确认后进入ESTABLISHED状态
  • 2.TCP连接的释放(四次挥手)
    • 步骤1:客户机发送释放请求
      • FIN=1,seq=u
      • 进入FIN-WAIT-1状态
    • 步骤2:服务器确认
      • ACK=1,seq=v,ack=u+1
      • 进入CLOSE-WAIT状态
      • 客户机进入FIN-WAIT-2状态
    • 步骤3:服务器发送释放请求
      • FIN=1,ACK=1,seq=w,ack=u+1
      • 进入LAST-ACK状态
    • 步骤4:客户机确认
      • ACK=1,seq=u+1,ack=w+1
      • 进入TIME-WAIT状态
      • 服务器进入CLOSED状态
      • 客户机等待2MSL后进入CLOSED状态
  • 计时器
    • 时间等待计时器(2MSL)
    • 保活计时器
      • 服务器每收到数据重置
      • 超时后发送探测报文段
      • 连续10次无响应则关闭连接
  • 总结
    • 建立连接三步
      • ①SYN=1,seq=x
      • ②SYN=1,ACK=1,seq=y,ack=x+1
      • ③ACK=1,seq=x+1,ack=y+1
    • 释放连接四步
      • ①FIN=1,seq=u
      • ②ACK=1,seq=v,ack=u+1
      • ③FIN=1,ACK=1,seq=w,ack=u+1
      • ④ACK=1,seq=u+1,ack=w+1

5.3.4 TCP 可靠传输

  • 可靠传输机制
    • 检验
    • 序号
    • 确认
    • 重传
  • 序号
    • 定义
      • 保证数据有序提交给应用层
      • 基于字节流而非报文段
  • 确认
    • 定义
      • 确认号=期望收到的下一个字节序号
    • 特点
      • 累积确认
      • 捎带确认
  • 重传
    • 触发条件
      • 超时
        • 自适应算法计算RTO
        • 维护加权平均RTTs
      • 冗余ACK
        • 定义:重复确认同一报文段
        • 快速重传机制
          • 收到3个冗余ACK立即重传

5.3.5 TCP 流量控制

  • 功能
    • 速度匹配服务
    • 匹配发送速率与接收速率
  • 实现机制
    • 滑动窗口
      • 接收窗口(rwnd)
        • 动态调整
        • 反映接收方容量
      • 发送窗口限制
        • 不超过接收窗口值
  • 持续计时器
    • 零窗口处理
      • 发送探测报文
      • 重新设置计时器
  • 与数据链路层区别
    • 范围
      • 端到端 vs 相邻节点
    • 窗口大小
      • 动态变化 vs 固定

5.3.6 TCP 拥塞控制

  • 拥塞控制概述
    • 定义
      • 防止过多数据注入网络
      • 避免路由器或链路过载
    • 表现
      • 通信时延增加
  • 拥塞控制 vs 流量控制
    • 拥塞控制
      • 全局性过程
      • 涉及所有主机和路由器
      • 目标
        • 让网络承受现有负荷
    • 流量控制
      • 点对点通信控制
      • 接收端控制发送端
      • 目标
        • 使接收端来得及接收
    • 相似点
      • 都通过控制发送速率实现
  • TCP拥塞控制算法
    • 慢开始
      • 原理
        • 初始cwnd=1
        • 指数增长
      • 传输轮次(RTT)后
        • cwnd加倍
      • 设置
        • 慢开始门限ssthresh
    • 拥塞避免
      • 原理
        • cwnd线性增长
      • 每RTT
        • cwnd加1
      • 算法切换条件
        • cwnd<ssthresh
          • 慢开始
        • cwnd>ssthresh
          • 拥塞避免
        • cwnd=ssthresh
          • 两者皆可
    • 网络拥塞处理
      • 设置
        • ssthresh=cwnd/2
      • 重置
        • cwnd=1
      • 执行
        • 慢开始
    • 快重传
      • 原理
        • 收到3个冗余ACK立即重传
      • 优点
        • 避免等待超时
    • 快恢复
      • 原理
        • 收到3个冗余ACK时
          • ssthresh=cwnd/2
          • cwnd=ssthresh
          • 执行拥塞避免
  • 窗口管理
    • 发送窗口上限
      • min[rwnd,cwnd]
    • 拥塞窗口(cwnd)动态调整原则
      • 网络未拥塞
        • 增大cwnd
      • 网络拥塞
        • 减小cwnd
  • 算法应用场景
    • TCP连接建立/网络超时
      • 慢开始+拥塞避免
    • 收到3个冗余ACK
      • 快重传+快恢复

4.1 网络层的功能

4.1.1 异构网络互连

  • 定义
    • 互联网由全球范围内数以百万计的异构网络互连
    • 网络层任务之一是实现异构网络互连
    • 网络互连:将两个以上计算机网络通过中继系统相互连接
  • 中继系统分类(按层次)
    • 物理层中继系统
      • 转发器
      • 集线器
    • 数据链路层中继系统
      • 网桥
      • 交换机
    • 网络层中继系统
      • 路由器
    • 网络层以上中继系统
      • 网关
  • 网络互连特点
    • 通常指用路由器进行连接和路由选择
    • 路由器是专用计算机
    • 历史原因:路由器有时被称为网关
  • TCP/IP网络互连方案
    • 网络层采用标准化协议
    • 可连接异构网络
    • IP网络概念
      • 实际互连网络(通过路由器连接)
      • 虚拟IP网络(统一网络视图)
  • IP网络优势
    • 主机通信时如同在单个网络上
    • 隐藏底层网络异构细节

4.1.2 路由与转发

  • 路由器主要完成两个功能
    • 路由选择(确定哪一条路径)
      • 根据路由选择协议构造并维护路由表
      • 经常或定期与相邻路由器交换信息
      • 获取网络最新拓扑
      • 动态更新维护路由表
      • 决定分组到达目的地节点的最优路径
    • 分组转发(分组到达时所采取的动作)
      • 处理通过路由器的数据流
      • 关键操作
        • 转发表查询
        • 转发
        • 队列管理
        • 任务调度
  • 路由表与转发表的关系
    • 路由表根据路由选择算法得出
    • 转发表从路由表得出
    • 转发表结构优化查找过程
    • 路由表优化网络拓扑变化计算
  • 注意
    • 讨论路由选择原理时
      • 不区分转发表和路由表
      • 笼统使用路由表一词

4.1.3 网络层提供的两种服务

  • 网络层提供两种通信服务方式

    • 面向连接的虚电路服务
    • 无连接的数据报服务
  • ①. 虚电路(Virtual Circuit, VC)

    • 基本概念
      • 计算机通信前先建立网络层连接
      • 连接是一条逻辑上的路径(非物理专用)
      • 分为三个阶段:建立、传输、释放
    • 虚电路号(VCID)
      • 每次建立时分配唯一编号
      • 区分不同虚电路
    • 数据传输特点
      • 首部仅携带VCID,不重复目的地址
      • 每个节点维护虚电路表
        • 包含VCID、入链路、出链路、前后节点等信息
    • 工作流程
      • 建立连接:发送“呼叫请求”分组 → 接收方确认“呼叫应答”
      • 数据传输:通过已建立路径传输数据分组
      • 释放连接:发送“释放请求”分组 → 逐段拆除连接
    • 特点总结
      • 建立/拆除需要开销,适合长时间频繁通信
      • 路由选择在连接建立时确定
      • 提供可靠传输、有序到达、流量控制
      • 对网络故障适应性差
        • 节点或链路失效 → 所有相关虚电路中断
      • 分组首部开销小(只用VCID)
  • ②. 数据报(Datagram)

    • 基本概念
      • 发送前不需要建立连接
      • 每个分组独立路由转发
      • 网络层不承诺服务质量
    • 数据传输特点
      • 每个分组包含完整源和目的地址
      • 中间节点缓存并查找转发表进行转发
      • 不保证顺序、可靠性、流量控制
    • 工作流程
      • 主机A将分组发给相邻交换节点A
      • 节点A查找转发表决定下一跳
      • 其他节点类似转发,直到到达主机B
    • 特点总结
      • 无需连接建立,灵活高效
      • 尽最大努力交付,可能出错、丢失、乱序
      • 支持资源复用,利用率高
      • 对网络故障适应性强
        • 可动态更新路由避开故障节点
      • 分组需排队转发,可能造成延迟或丢包
  • ③. 数据报服务与虚电路服务比较

    • 连接的建立
      • 数据报服务:不需要
      • 虚电路服务:必须有
    • 目的地址
      • 数据报服务:每个分组都有完整的目的地址
      • 虚电路服务:连接阶段

4.1.4 SDN 的基本概念

  • 网络层抽象划分
    • 数据平面(转发层面)
      • 功能:转发
    • 控制平面
      • 功能:路由选择
  • SDN架构特点
    • 集中式的控制平面
    • 分布式的数据平面
    • 控制平面与数据平面分离
    • 控制平面通过控制-数据接口集中控制路由器
  • 传统路由器 vs SDN路由器
    • 传统路由器
      • 包含转发表和路由选择软件
      • 既有数据平面又有控制平面
    • SDN路由器
      • 简化设计
      • 无需路由选择软件
      • 路由器间不交换路由信息
  • SDN结构
    • 远程控制器
      • 逻辑上的控制中心
      • 掌握网络状态
      • 计算最佳路由
      • 通过Openflow协议下发流表
    • 路由器工作流程
      • 收到分组
      • 查找转发表
      • 转发分组
  • SDN应用场景
    • 大型数据中心之间的广域网
  • SDN接口
    • 北向接口
      • 面向应用开发者的编程接口
      • 提供丰富API
    • 南向接口
      • 控制器与转发设备间的双向会话接口
      • 协议示例:Openflow
    • 东西向接口
      • 控制器集群内部通信接口
  • SDN优点
    • 全局集中式控制和分布式高速转发
    • 灵活可编程与性能的平衡
    • 降低成本
  • SDN问题
    • 安全风险
      • 集中管理易受攻击
    • 瓶颈问题
      • 控制器可能成为性能瓶颈

4.1.5 拥塞控制

  • 定义
    • 因出现过量的分组而引起网络性能下降的现象
  • 判断方法
    • 观察吞吐量与网络负载的关系
      • 轻度拥塞:吞吐量明显小于正常值
      • 拥塞状态:吞吐量随负载增大而下降
  • 主要问题
    • 如何获取拥塞信息
    • 利用信息进行控制
  • 作用
    • 确保网络承载能力
    • 全局性过程
      • 涉及所有主机、路由器
    • 增加资源不能单独解决
  • 与流量控制的区别
    • 流量控制:点对点通信量控制
    • 目的:抑制发送速率使接收方来得及接收
  • 控制方法
    • 开环控制
      • 特点:静态预防
      • 手段:
        • 确定接收新流量时机
        • 分组丢弃策略
        • 调度策略
      • 特点:不考虑当前网络状态
    • 闭环控制
      • 特点:动态方法
      • 原理:基于反馈环路
      • 过程:
        • 监测网络状态
        • 检测拥塞
        • 传递拥塞信息
        • 调整系统运行

4.2 IPV4

4.2.1 IPv4分组

  • IPv4概述
    • IP定义数据传送的基本单元——IP分组及其确切的数据格式
    • 包含处理规则、错误控制机制
    • 实现非可靠投递和路由选择思想
  • IPv4分组格式
    • 组成
      • 首部
        • 固定部分(20B)
        • 可选字段(长度可变)
      • 数据部分
    • 重要字段
      • 版本(4位)
        • 值为4表示IPv4
      • 首部长度(4位)
        • 以4B为单位
        • 最大60B(15×4B)
        • 常用20B(5×4B)
      • 总长度(16位)
        • 首部+数据的总长度
        • 最大65535B
      • 标识(16位)
        • 数据报唯一标识
        • 分片时复制相同标识
      • 标志(3位)
        • MF(More Fragment)
        • DF(Don’t Fragment)
      • 片偏移(13位)
        • 以8B为单位
      • 生存时间(TTL)(8位)
        • 最大路由器跳数
      • 协议(8位)
        • 上层协议类型
        • 6:TCP,17:UDP
      • 首部检验和(16位)
        • 仅检验首部
      • 源地址(4B)
      • 目的地址(4B)
  • IP数据报分片
    • 分片原因
      • 链路层MTU限制
      • 不同链路MTU可能不同
    • 分片过程
      • 标识字段保持相同
      • 设置MF和DF标志
      • 计算片偏移
    • 重组过程
      • 目的主机重组
      • 使用标识、标志、片偏移字段
    • 分片示例
      • 4000B数据报(20B首部+3980B数据)
      • MTU=1500B
      • 分3片
        • 1480B+1480B+1020B

4.2.2 IPv4地址与NAT

  • IPv4地址
    • IP地址定义
      • 32位全球唯一标识符
      • 由ICANN分配
      • 点分十进制记法
    • IP地址结构
      • 分类IP地址(A、B、C类)
      • 组成:网络号 + 主机号
        • 网络号:互联网范围内唯一
        • 主机号:网络范围内唯一
    • IP地址特点
      • 分等级地址结构
        • 优点:
          • 方便管理
          • 减小路由表存储空间
      • 标志主机和链路接口
        • 多网络主机需多个IP地址
      • 同一LAN网络号相同
      • 所有网络平等
      • 同一局域网网络号相同
    • 特殊IP地址
      • 主机号全0:本网络
      • 主机号全1:直接广播地址
      • 127.x.x.x:环回测试
      • 0.0.0.0:本网络本主机
      • 255.255.255.255:受限广播地址
    • IP地址使用范围
      • A类:网络数2⁷-2
      • B类/C类:早期限制已取消
      • 主机数减2(全0/全1不指派)
  • NAT(网络地址转换)
    • 定义
      • 专用网络地址转公用地址
      • 隐藏内部管理IP
      • 节省IP地址
      • 提高安全性
    • 私有IP地址
      • 范围:
        • 10.0.0.0/8
        • 172.16.0.0/12
        • 192.168.0.0/16
      • 特点:
        • 仅用于LAN
        • 可重复使用
        • 需NAT转换才能上网
    • NAT工作原理
      • 转换表:{本地IP:端口} ↔ {全球IP:端口}
      • 多私有IP映射单一全球IP
      • 过程:
        • ①. 主机发送请求
        • ②. NAT修改源地址/端口
        • ③. 服务器响应NAT地址
        • ④. NAT转换返回主机
    • 服务器应用
      • 公网访问私网服务器
      • 配置特定端口映射

4.2.3 划分子网与路由聚合

  • 划分子网

    • 两级IP地址的缺点
      • IP地址空间利用率低
      • 路由表过大影响性能
      • 灵活性不足
    • 划分子网发展
      • 1985年成为标准协议
      • 增加子网号字段形成三级IP地址
    • 基本思路
      • 单位内部行为,对外表现单一网络
      • 从主机号借位作为子网号
      • 三级IP地址结构:{网络号,子网号,主机号}
      • 路由器转发流程
        • 先按目的网络号转发
        • 本单位路由器再按子网号转发
  • 子网掩码和默认网关

    • 子网掩码作用
      • 标识主机号借位情况
      • 32位二进制串(1对应网络/子网号,0对应主机号)
      • 通过AND运算获取网络地址
    • 默认网关
      • 子网与外部网络的连接点
      • 路由器接口IP地址
      • 转发非本子网数据
    • 使用规范
      • 所有网络必须使用子网掩码
      • 未划分子网时使用默认子网掩码
        • A类:255.0.0.0
        • B类:255.255.0.0
        • C类:255.255.255.0
    • 配置要求
      • 主机必须同时配置IP和子网掩码
      • 同一子网设备需配置相同子网掩码
      • 路由表关键字段:
        • 目的网络地址
        • 子网掩码
        • 下一跳地址
  • 无分类编址CIDR

    • 核心概念
      • 消除传统ABC类地址划分
      • 使用可变长网络前缀
      • 记法:IP地址/前缀位数(如128.14.32.5/20)
    • 地址块特性
      • 最小地址:主机号全0
      • 最大地址:主机号全1
      • 可用地址数:2^N-2(N=主机号位数)
    • 特殊说明
      • 仍可使用”掩码”概念
      • 单位内部可继续划分子网
      • 地址块大小必为2的整数次幂
  • 路由聚合

    • 原理
      • 用大CIDR地址块代替多个小地址块
      • 压缩路由表空间
    • 最长前缀匹配规则
      • 选择网络前缀最长的路由
      • 实现方式:层次式数据结构(如二叉线索)
  • 子网划分应用

    • 定长子网掩码
      • 特点
        • 统一子网掩码
        • 每个子网地址数相同
        • 可能造成浪费
    • 变长子网掩码
      • 特点
        • 不同子网使用不同掩码
        • 按需分配地址数量
        • 减少地址浪费
    • 特殊场景
      • 路由器间链路:使用/30地址块(2个可用地址)

4.2.4 网络层转发分组的过程

  • 分组转发基于目的主机所在网络
    • 原因:网络数远小于主机数,压缩转发表大小
    • 路由器根据目的IP地址网络前缀查找转发表
  • 转发表路由信息格式
    • (目的网络地址,下一跳地址)
  • CIDR编址时的转发规则
    • 最长前缀匹配原则
    • 转发表排序:前缀长度降序排列
  • 特殊路由类型
    • 特定主机路由
      • 格式:a.b.c.d/32
      • 用途:网络管理员控制和测试网络
      • 匹配优先级最高
    • 默认路由
      • 格式:0.0.0.0/0
      • 用途:路由器到互联网的路由
      • 匹配优先级最低
  • 分组转发算法步骤
    1. 提取目的IP地址D
    2. 检查特定主机路由
    3. 逐行检查转发表
    • 子网掩码与D进行AND操作
    • 匹配则转发
    1. 检查默认路由
  • 转发表特点
    • 不指明完整路径
    • 采用逐步查找下一跳的方式

4.2.5 地址解析协议(ARP)

  • 1.IP地址与硬件地址
    • IP地址
      • 网络层及以上使用
      • 分层式结构
      • 放在IP数据报首部
    • 硬件地址(MAC地址)
      • 数据链路层使用
      • 平面式结构
      • 放在MAC帧首部
    • 网络层特性
      • 只能看到IP数据报
      • 路由器只根据目的IP地址转发
      • 局域网链路层只能看到MAC帧
      • IP层屏蔽硬件地址细节
    • 路由器特性
      • 有多个IP地址
      • 有多个硬件地址
  • 2.地址解析协议(ARP)
    • 功能
      • IP地址到MAC地址的映射
      • 动态维护ARP表
    • 工作原理
      • 检查ARP缓存
      • 无缓存时广播ARP请求(目的MAC为FF-FF-FF-FF-FF-FF)
      • 目标主机单播响应
      • 更新ARP缓存
    • 工作层次
      • 网络层(能看到IP地址)
    • 四种典型情况
      • 主机→本网络主机
      • 主机→其他网络主机
      • 路由器→直连网络主机
      • 路由器→非直连网络主机

4.2.6 动态主机配置协议(DHCP)

  • 定义
    • 动态主机配置协议 (Dynamic Host Configuration Protocol, DHCP)
    • 用于动态分配IP地址
    • 提供即插即用联网机制
    • 应用层协议,基于UDP
  • 配置项目
    • IP地址
    • 子网掩码
    • 默认路由器IP地址(默认网关)
    • 域名服务器IP地址
  • 工作原理
    • 客户/服务器模型
    • 主机启动时广播发送发现报文
    • 只有DHCP服务器能回应
    • 服务器查找配置信息
      • 找到:返回配置信息
      • 找不到:从地址池分配IP
  • 报文交换过程
    • DHCP发现
      • 客户广播”DHCP发现”消息
      • 源地址:0.0.0.0
      • 目的地址:255.255.255.255
    • DHCP提供
      • 服务器广播”DHCP提供”消息
      • 包含提供的IP地址
      • 源地址:DHCP服务器地址
      • 目的地址:255.255.255.255
    • DHCP请求
      • 客户广播”DHCP请求”消息
      • 源地址:0.0.0.0
      • 目的地址:255.255.255.255
    • DHCP确认
      • 服务器广播”DHCP确认”消息
      • 分配IP地址给客户
      • 源地址:DHCP服务器地址
      • 目的地址:255.255.255.255
  • 租用期
    • IP地址是临时的
    • 租用期由服务器决定
    • 客户可提出租用期要求
    • 客户可提前终止租用期
      • 发送释放报文
  • 通信方式
    • 采用广播方式的原因
      • 初期不知道服务器IP
      • 中间阶段客户未被分配IP
    • 采用UDP而非TCP的原因
      • TCP需要建立连接
      • 不知道对方IP无法建立连接

4.2.7 网际控制报文协议(ICMP)

  • 功能
    • 报告差错和异常情况
    • 封装在IP数据报中发送
    • 网络层协议
  • ICMP报文类型
    • ICMP差错报告报文
      • 常用类型
        • 终点不可达
        • 源点抑制
        • 时间超过
        • 参数问题
        • 改变路由(重定向)
      • 不发送ICMP差错报告报文的情况
        • 对ICMP差错报告报文
        • 对第一个分片的数据报片的所有后续数据报片
        • 对具有多播地址的数据报
        • 对具有特殊地址(如127.0.0.0或0.0.0.0)的数据报
    • ICMP询问报文
      • 常用类型
        • 回送请求和回答报文
        • 时间戳请求和回答报文
  • ICMP应用
    • 分组网间探测PING
      • 使用ICMP回送请求和回答报文
    • Traceroute/Tracert
      • 使用ICMP时间超过报文

4.3 IPV6

4.3.1 IPv6的特点

  • IPv4的问题
    • 地址耗尽问题
      • 解决措施
        • 采用无类别编址CIDR
        • 采用网络地址转换(NAT)
        • 采用IPv6
  • IPv6的主要特点
    • 更大的地址空间
      • 128位地址
      • 地址空间是IPv4的2^96倍
    • 扩展的地址层次结构
    • 灵活的首部格式
      • 可选的扩展首部
      • 提高路由器处理效率
    • 改进的选项
      • 固定首部长度
      • 选项放在有效载荷中
    • 允许协议继续扩充
    • 支持即插即用(自动配置)
      • 不需要使用DHCP
    • 支持资源的预分配
      • 支持实时音/视频应用
    • 分片机制
      • 只有源主机才能分片
      • 端到端分片
    • 固定首部长度
      • 40B固定长度
    • 增大了安全性
      • 身份鉴别和保密功能
  • IPv6兼容性
    • 与IPv4不兼容
    • 与其他互联网协议兼容
      • TCP
      • UDP
      • ICMP
      • IGMP
      • DNS

4.3.2 IPv6数据报的基本首部

  • IPv6 数据报组成
    • 基本首部
    • 有效载荷
      • 扩展首部
      • 数据部分
  • IPv6与IPv4首部字段对比
    • 取消的字段
      • 首部长度字段
      • 服务类型字段
      • 总长度字段
      • 标识、标志和片偏移字段
      • TTL字段
      • 协议字段
      • 检验和字段
      • 选项字段
    • 更改的字段
      • 跳数限制字段(原TTL字段)
      • 下一个首部字段(原协议字段)
  • IPv6基本首部特点
    • 字段数减少到8个
    • 长度增大到40B
  • IPv6基本首部字段
    • 版本(4位)
    • 通信量类(8位)
    • 流标号(20位)
    • 有效载荷长度(16位)
    • 下一个首部(8位)
    • 跳数限制(8位)
    • 源地址(128位)
    • 目的地址(128位)

4.3.3 IPv6地址

  • 基本类型
    • 单播
      • 点对点通信
    • 多播
      • 一点对多点通信
      • 数据报发送到一组计算机中的每一台
    • 任播
      • IPv6新增类型
      • 终点是一组计算机
      • 数据报只交付其中一台(通常距离最近)
  • 表示法
    • 冒号十六进制记法
      • 每4位用一个十六进制数表示
      • 冒号分隔每16位
      • 示例:4BF5:AA12:0216:FEBC:BA5F:039A:BE9A:2170
    • 缩写表示法
      • 16位域开头有0时可缩写
      • 域中至少保留一个数字
      • 示例:4BF5:0:0:0:BA5F:39A:A:2176
    • 双冒号缩写
      • 用于相继的0值域
      • 一个地址中仅能出现一次
      • 示例:4BF5::BA5F:39A:A:2176
  • 地址分类
    • 未指明地址
      • 不能用作目的地址
      • 只能用于未配置IPv6地址的主机作为源地址
    • 环回地址
      • 作用与IPv4环回地址相同
      • IPv6仅此一个
    • 多播地址
      • 作用与IPv4相同
      • 占IPv6地址空间的1/256
    • 本地链路单播地址
      • 类似于IPv4的私有IP地址
    • 全球单播地址
      • 三级结构
        • 全球路由选择前缀(48位)
          • 相当于IPv4的网络号
        • 子网标识符(16位)
          • 用于机构构建子网
        • 接口标识符(64位)
          • 相当于IPv4的主机号
  • 接口标识符特点
    • 64位长度
    • 可直接编码硬件地址
    • 无需使用ARP进行地址解析

4.3.4 从IPv4 向IPv6过渡

  • 过渡特点
    • 逐步演进
    • 新安装的IPv6系统必须向后兼容
    • IPv6系统要求
      • 能接收和转发IPv4分组
      • 能为IPv4分组选择路由
  • 过渡策略(2023)
    • 双协议栈
      • 定义
        • 一台设备同时装有IPv4和IPv6协议栈
        • 分别配置IPv4和IPv6地址
      • 功能
        • 能与IPv4网络通信
        • 能与IPv6网络通信
      • 通信机制
        • 与IPv6主机通信:使用IPv6地址
        • 与IPv4主机通信:使用IPv4地址
      • DNS解析过程
        • 返回IPv4地址:使用IPv4地址
        • 返回IPv6地址:使用IPv6地址
    • 隧道技术
      • 实现方式
        • IPv6数据报进入IPv4网络时
          • 将整个IPv6数据报封装成IPv4数据报的数据部分
        • IPv4数据报离开IPv4网络时
          • 将数据部分交给主机的IPv6协议
      • 效果
        • IPv6数据报在IPv4网络中传输

4.4 路由算法与路由协议

4.4.1 路由算法

  • 定义
    • 路由选择协议的核心是路由算法
    • 目的是找到从源路由器到目的路由器的”最佳”路径
    • “最佳”通常指具有最低费用的路径
  • 分类
    • 静态路由与动态路由
      • 静态路由算法
        • 由网络管理员手工配置
        • 特点:简单、开销小
        • 缺点:不能及时适应网络状态变化
        • 适用场景:小型简单网络
      • 动态路由算法
        • 根据网络流量和拓扑变化动态调整
        • 特点:实现复杂、开销大
        • 优点:能适应网络状态变化
        • 适用场景:复杂大型网络
        • 子分类
          • 距离-向量路由算法
          • 链路状态路由算法
  • 距离-向量路由算法
    • 基础:Bellman-Ford算法
    • 基本思想
      • 每个节点维护:
        • 到直接邻居的链路费用
        • 自身距离向量(到其他节点的费用)
        • 邻居的距离向量
      • 定期交换距离向量
      • 使用公式更新:d(y)=min{c(x,v)+d(v)}
    • 实现过程
      • 初始化阶段
      • 第一次交换更新
      • 后续交换直至收敛
    • 特点
      • 更新报文大小与网络节点数量成正比
      • 典型实现:RIP协议(使用跳数作为度量)
    • 示例
      • 三节点网络示例
      • 初始状态
      • 第一次更新后
      • 第二次更新后收敛
  • 链路状态路由算法
    • 定义
      • 每个节点知道全网拓扑
      • 执行任务:
        • 测试相邻节点状态
        • 定期传播链路状态
    • 工作原理
      • 使用Dijkstra算法计算最短路径
      • 链路状态变化时重新计算
    • 优点
      • 适用于大型网络
      • 链路状态报文大小与网络规模无关
      • 易于故障排查
      • 保证一步汇聚
    • 典型实现:OSPF协议
  • 两种算法比较
    • 距离-向量算法
      • 仅与直接邻居通信
      • 发送整个路由表
      • 报文大小与节点数量相关
    • 链路状态算法
      • 与所有节点通信(广播)
      • 仅发送直接链路信息
      • 报文大小固定
    • 规模可伸展性:链路状态算法更优

4.4.2 分层次的路由选择协议

  • 互联网采用自适应的、分布式路由选择协议
  • 划分为许多较小的自治系统 (Autonomous System, AS)
    • 定义:在单一技术管理下的一组路由器
    • 特点:
      • 使用一种AS内部的路由选择协议
      • 共同的度量
      • 对外表现单一和一致的路由选择策略
  • 路由选择协议分类:
    • ①. 内部网关协议 (IGP)
      • 定义:在一个自治系统内部使用的路由选择协议
      • 特点:
        • 与其他自治系统选用的协议无关
        • 常用协议:
          • RIP
          • OSPF
    • ②. 外部网关协议 (EGP)
      • 定义:在不同自治系统间传递路由选择信息的协议
      • 应用场景:
        • 源主机和目的主机处在不同自治系统
        • 数据报传到自治系统边界时使用
      • 常用协议:
        • BGP-4
  • 路由选择类型:
    • 域间路由选择:自治系统之间的路由选择
    • 域内路由选择:自治系统内部的路由选择
  • 两个自治系统互连示意图
    • 自治系统A
      • 路由器R1
        • 运行:
          • 内部网关协议 (如RIP)
          • 外部网关协议 (如BGP-4)
    • 自治系统B
      • 路由器R2
        • 运行:
          • 内部网关协议 (如OSPF)
          • 外部网关协议 (如BGP-4)

4.4.3 路由信息协议(RIP)

  • RIP的规定

    • 每个路由器维护距离向量
    • 使用跳数衡量距离
      • 直接连接网络距离=1
      • 每经过一个路由器距离+1
    • 好的路由=跳数少
    • 最大跳数=15(16表示不可达)
      • 防止环路
    • 路由表项格式
      • <目的网络N, 距离d, 下一跳路由器地址X>
  • RIP的特点

    • 交换信息对象
      • 仅与直接相邻路由器交换
    • 交换内容
      • 整个路由表
    • 交换时机
      • 固定时间间隔(30秒)
      • 拓扑变化时及时通告
    • 收敛过程
      • 初始仅知直接连接网络
      • 通过周期性交换最终收敛
    • RIP协议特性
      • 应用层协议
      • 使用UDP传输(端口520)
      • 选择最少跳数路径
  • RIP的距离向量算法

    • 处理相邻路由器RIP报文步骤
      • 修改报文
        • 下一跳地址改为X
        • 所有距离字段+1
      • 更新路由表
        • 新目的网络:添加
        • 已有目的网络且下一跳相同:更新
        • 已有目的网络但下一跳不同:比较距离
        • 其他情况:不处理
      • 超时处理
        • 180秒未收到更新则标记为不可达(距离=16)
    • 路由表更新示例
      • R6和R4互为相邻路由器
      • R6收到R4路由表后的更新过程
  • RIP的优缺点

    • 优点
      • 实现简单
      • 开销小
      • 收敛较快
      • 好消息传播快
    • 缺点
      • 网络规模受限(最大15跳)
      • 交换完整路由表导致开销大
      • 坏消息传播慢(慢收敛)

4.4.4 开放最短路径优先(OSPF )协议

  • 基本特点
    • OSPF和RIP的比较(2024)
      • OSPF使用洪泛法向本自治系统中所有路由器发送信息
      • RIP仅向自己相邻的几个路由器发送信息
      • OSPF发送的信息是与本路由器相邻的所有路由器的链路状态
      • RIP发送的信息是本路由器所知道的全部信息
      • OSPF只有当链路状态发生变化时才发送信息
      • RIP不管网络拓扑是否变化都要定期交换信息
    • OSPF是网络层协议,直接用IP数据报传送(协议字段为89)
    • RIP是应用层协议,使用UDP传输
    • 其他特点
      • 允许对每条路由设置不同代价
      • 支持多路径负载均衡
      • 分组具有鉴别功能
      • 支持可变长度子网划分和CIDR
      • 链路状态带32位序号
  • 基本工作原理
    • 建立链路状态数据库(全网拓扑结构图)
    • 使用Dijkstra算法计算最优路径
    • 划分区域
      • 减少洪泛法交换范围
      • 区域边界路由器
      • 主干区域
      • 自治系统边界路由器
  • 分组类型
    • 问候分组(发现和维持邻站可达性)
    • 数据库描述分组(链路状态项目摘要)
    • 链路状态请求分组(请求详细信息)
    • 链路状态更新分组(全网更新链路状态)
    • 链路状态确认分组(确认更新)
  • 操作流程
    • 每10秒交换问候分组
    • 40秒未收到则认为不可达
    • 初始工作流程
      • 通过问候分组发现相邻路由器
      • 交换数据库描述分组
      • 请求缺少的链路状态信息
      • 建立同步链路数据库
    • 链路状态变化时
      • 使用洪泛法更新
      • 其他路由器发送确认
    • 定期刷新(如30分钟)

4.4.5 边界网关协议(BGP)

  • BGP的基本特点

    • 边界网关协议(Border Gateway Protocol, BGP)
      • 不同自治系统(AS)的路由器之间交换路由信息的协议
      • 属于外部网关协议
      • 常用于互联网网关之间
    • 与其他协议对比
      • RIP和OSPF只能在AS内工作
      • 没有BGP时,全球AS会成为孤岛
    • 使用环境特点
      • 互联网规模太大导致AS间路由选择困难
      • AS间路由需考虑政治、安全、经济等因素
    • 协议特性
      • 力求找到可达且不兜圈子的路由(非最佳路由)
      • 采用路径向量路由选择协议
      • 是应用层协议,基于TCP
  • BGP会话

    • 两种BGP会话定义
      • 外部BGP(eBGP)会话
        • 跨越两个AS的BGP会话
      • 内部BGP(iBGP)会话
        • 同一AS内两个路由器之间的BGP会话
    • 连接方式
      • 通过端口号179的半永久TCP连接
      • 交换信息后仍保持连接状态
  • BGP路由

    • 路由格式
      • <CIDR前缀, BGP属性>
    • 重要BGP属性
      • AS-PATH(自治系统路径)
        • 记录路由经过的自治系统
        • 使用ASN(自治系统号)标识
      • NEXT-HOP(下一跳)
        • 通告的BGP路由起点
    • 路由处理过程
      • 路由器收到BGP路由后需转换起点
      • 利用内部网关协议找到最佳路由中的下一跳
      • 在转发表中增加相应表项
  • BGP路由选择

    • 选择原则(按优先级顺序)
      ①. 本地偏好值最高的路由
      ②. AS跳数最少(AS-PATH最短)的路由
      ③. 热土豆路由选择算法
      • 选择最靠近NEXT-HOP路由器的路由
      • 让分组最快离开本AS
        ④. BGP标识符数值最小的路由
  • BGP的四种报文

    • Open(打开)报文
      • 建立BGP对等方关系
      • 初始化通信
    • Update(更新)报文
      • 通知路由信息
      • 列出要撤销的路由
      • 每次只能增加一条新路由
    • Keepalive(保活)报文
      • 周期性确认邻站连通性
      • 19字节大小
    • Notification(通知)报文
      • 发送检测到的差错
  • 三种路由协议比较

    • RIP
      • 类型: 内部
      • 路由算法: 距离向量
      • 传递协议: UDP
      • 路径选择: 跳数最少
      • 交换节点: 相邻路由器
      • 交换内容: 整个路由表
    • OSPF
      • 类型: 内部
      • 路由算法: 链路状态
      • 传递协议: IP
      • 路径选择: 代价最低
      • 交换节点: 网络中所有路由器
      • 交换内容: 相邻路由器链路状态
    • BGP
      • 类型: 外部
      • 路由算法: 路径向量
      • 传递协议: TCP
      • 路径选择: 较好(非最佳)
      • 交换节点: 相邻路由器
      • 交换内容:
        • 首次: 整个路由表
        • 非首次: 有变化的部分

4.5 IP多播

4.5.1 多播的概念

  • 定义
    • 让源主机一次发送的单个分组可以抵达用一个组地址标识的若干目的主机
    • 一对多的通信
    • 在互联网上进行的多播称为IP多播
  • 优势
    • 与单播相比
      • 大大节约网络资源
      • 示例:视频服务器向90台主机传送同样的视频节目
        • 单播:需要发送90次
        • 多播:仅发送一份数据,只需发送一次
    • 技术特点
      • 传送路径出现分岔时才将分组复制后继续转发
      • 大大减轻发送者负担和网络负载
  • 实现要求
    • 需要路由器支持
    • 能够运行多播协议的路由器称为多播路由器

4.5.2 IP多播地址

  • 多播数据报特点

    • 源地址:源主机的IP地址
    • 目的地址:IP多播地址(D类地址)
  • D类地址范围

    • 前四位:1110
    • 范围:224.0.0.0~239.255.255.255
  • 多播组

    • 每个D类IP地址标志一个多播组
    • 主机可随时加入或离开多播组
  • 多播数据报与普通IP数据报的区别

    • 目的地址:使用D类IP地址
    • 协议字段值:2(表示使用IGMP)

4.5.3 在局域网上进行硬件多播

  • 局域网支持硬件多播
    • 实现方式:将IP多播地址映射成多播MAC地址
      • 将IP多播数据报封装在MAC帧中
      • MAC帧目的地址设置为映射后的多播MAC地址
  • IANA分配的以太网多播地址范围
    • 01-00-5E-00-00-00 到 01-00-5E-7F-FF-FF
    • 可用位数
      • 总长度:48位
      • 可用部分:后23位
  • D类IP地址与以太网地址映射关系
    • D类IP地址可用位数:28位
    • 映射特点
      • 前5位无法映射到以太网地址
      • 结果:多对一映射关系
  • 接收端处理
    • 需要IP层软件过滤
      • 原因:多对一映射导致地址冲突
      • 处理方式:丢弃非目标主机的数据报

4.5.4 IGMP 与多播路由协议

  • IGMP协议
    • 作用: 让多播路由器获知局域网内主机加入/退出多播组
    • 特点
      • 不管理互联网范围内的多播组成员
      • 不知道组成员数量和分布
    • 报文封装: 封装在IP数据报中传送
    • 工作阶段
      • 第一阶段: 主机加入时发送IGMP报文
      • 第二阶段: 周期性探询组成员状态
  • 多播路由协议
    • 目的: 最小代价传送多播数据报给所有组成员
    • 多播转发树
      • 以源主机为根节点
      • 每个分组在每条链路上只传送一次
      • 不同多播组对应不同转发树
      • 同一多播组对不同源点有不同转发树

4.6 移动IP

4.6.1 移动IP 的概念

  • 移动IP技术
    • 定义
      • 移动站以固定的IP地址实现跨越不同网络的漫游功能
    • 目标
      • 把分组自动地投递给移动站
    • 移动站定义
      • 把其连接点从一个网络或子网改变到另一个网络或子网的主机
  • 功能实体
    • 移动节点
      • 具有永久IP地址的移动主机
    • 本地代理
      • 通常就是连接在归属网络上的路由器
    • 外地代理
      • 通常就是连接在被访网络上的路由器
  • 注意事项
    • 通过DHCP自动获取新IP地址不是移动IP
    • 移动IP需要保持TCP连接不中断
    • 移动IP要求IP地址在移动中保持不变

4.6.2 移 动IP 通信过程

  • 移动IP原理类比
    • 本科毕业通信例子
      • 留下家庭地址(永久地址)
      • 家长转交信件
  • 基本概念
    • 移动站永久地址(归属地址)
    • 归属网络
      • 例:移动站A永久地址131.8.6.7/16
      • 归属网络131.8.0.0/16
    • 归属代理
      • 连接归属网络的路由器
      • 应用层功能
    • 被访网络
      • 例:15.0.0.0/8
    • 外地代理
      • 连接被访网络的路由器
      • 功能
        • 创建转交地址
          • 例:15.5.6.7/8
        • 通知归属代理转交地址
  • 通信流程
    • 1)移动站在归属网络
      • 传统TCP/IP通信
    • 2)漫游到被访网络
      • 外地代理登记获取转交地址
      • 外地代理向归属代理登记
    • 3)归属代理操作
      • 构建通向转交地址隧道
      • 封装并转发IP分组
    • 4)外地代理操作
      • 拆封恢复原始IP分组
      • 发送给移动站
    • 5)移动站发送IP分组
      • 使用永久地址作为源地址
      • 直接通过外地代理
    • 6)移动到新被访网络
      • 新外地代理登记
      • 更新归属代理转交地址
    • 7)返回归属网络
      • 注销转交地址
  • 支持移动性的新功能
    • 移动站到外地代理登记协议
    • 外地代理到归属代理登记协议
    • 归属代理数据报封装协议
    • 外地代理拆封协议

4.7 网络层设备

4.7.1 冲突域和广播域

  • ①. 冲突域
    • 定义
      • 连接到同一物理介质上的所有节点的集合
      • 这些节点之间存在介质争用的现象
    • OSI层次
      • 第1层概念
    • 设备影响
      • 不能划分冲突域的设备
        • 集线器
        • 中继器等第1层设备
      • 可以划分冲突域的设备
        • 第2层设备
          • 网桥
          • 交换机
        • 第3层设备
          • 路由器
  • ②. 广播域
    • 定义
      • 接收同样广播消息的节点集合
    • OSI层次
      • 第2层概念
    • 设备影响
      • 属于同一广播域的设备
        • 第1层设备
          • 集线器等
        • 第2层设备
          • 交换机等
      • 可以划分广播域的设备
        • 路由器(第3层设备)
    • 局域网(LAN)定义
      • 特指使用路由器分割的网络
      • 也就是广播域

4.7.2 路由器的组成和功能

  • 路由器定义
    • 具有多个输入/输出端口的专用计算机
    • 任务:连接不同网络并完成分组转发
  • 网络连接特性
    • 连接异构网络
    • 多个逻辑网络互连时必须使用
    • 隔离广播域
  • 数据转发原理
    • 同网络通信:直接交付
    • 跨网络通信:间接交付(通过路由器)
    • 连接能力
      • 不同LAN
      • 不同VLAN
      • 不同WAN
      • LAN和WAN互连
  • 结构组成
    • 路由选择部分(控制部分)
      • 核心构件:路由选择处理机
      • 功能
        • 构造路由表
        • 更新维护路由表
    • 分组转发部分
      • 交换结构(交换组织)
        • 根据转发表处理分组
      • 输入端口组
      • 输出端口组
  • 层次实现
    • 实现网络模型下三层
      • 物理层
      • 数据链路层
      • 网络层
  • 端口处理机制
    • 输入端口处理流程
      • 物理层:接收比特流
      • 数据链路层:提取帧
      • 网络层:处理分组
    • 输出端口处理流程(反向操作)
    • 缓冲队列
      • 暂存分组
      • 进行差错检测
      • 可能发生缓冲区溢出

4.7.3 路由表与分组转发

  • 路由表
    • 根据路由选择算法得出
    • 主要用途是路由选择
    • 标准路由表项目
      • 目的网络IP地址
      • 子网掩码
      • 下一跳IP地址
      • 接口
  • 转发表
    • 从路由表得出
    • 表项与路由表项对应关系
      • 图4.27 转发表的示例
    • 格式与路由表不同
      • 结构优化查找过程
    • 内容
      • 分组发往的目的网络
      • 分组的下一跳(MAC地址)
      • 可设置默认路由
        • 匹配优先级最低
    • 实现方式
      • 软件实现
      • 特殊硬件实现
  • 转发与路由选择的区别
    • 转发
      • 单个路由器行为
      • 根据转发表转发IP数据报
    • 路由选择
      • 多个路由器协同
      • 使用复杂路由算法
      • 根据网络拓扑变化动态调整
      • 构造整个路由表
  • 关键区别
    • 路由表≠转发表
    • 分组实际转发
      • 直接查找转发表
      • 不查找路由表

3.1 数据链路层的功能

3.1.1 数据链路层

  • 通信示例
    • 主机H1 → 路由器R1 → 广域网 → 路由器R2 → 主机H2
    • 主机使用完整五层协议栈
    • 路由器仅使用下三层协议栈
  • 数据流动特点
    • 数据在路径节点协议栈中多次上下流动
    • 学习时通常只关心水平方向数据链路层
  • 基本概念
      1. 链路
      • 定义:节点到相邻节点的一段物理线路
      • 特点:通信路径的组成部分
      1. 数据链路
      • 组成:物理链路 + 通信协议(硬件和软件)
      • 别名:物理链路 vs 逻辑链路
      • 定义:数据链路层协议数据单元
      • 功能:封装网络层数据/向上交付数据
  • 3.1.2 链路管理
    • 定义:连接的建立、维持和释放过程
    • 应用:主要用于面向连接的服务
    • 过程
      • 确认对方就绪状态
      • 交换必要信息
      • 初始化帧序号
      • 建立连接 → 维持连接 → 释放连接

3.1.4 封装成帧与透明传输

  • 定义
    • 限制发送方的发送速率,使之不超过接收方的接收能力
    • 防止帧丢失和错误
  • 原因
    • 链路两端节点的工作速率和缓存空间存在差异
    • 发送能力可能大于接收能力
  • 实现机制
    • 通过反馈机制控制发送
      • 可继续发送下一帧的情况
      • 必须暂停发送等待反馈的情况
  • 体系结构差异
    • OSI体系结构
      • 数据链路层实现流量控制
      • 控制相邻节点间数据链路上的流量
    • TCP/IP体系结构
      • 传输层实现流量控制
      • 控制源端到目的端之间的流量

3.1.5 流量控制

  • 原因
    • 链路两端节点工作速率和缓存空间存在差异。
    • 发送方发送能力可能大于接收方接收能力。
    • 若不限制发送方发送速率,来不及接收的帧会被后续帧“淹没”,造成帧丢失出错。
  • 目的
    • 限制发送方发送速率,不超过接收方接收能力。
  • 实现方式
    • 通过某种反馈机制。
    • 使发送方知晓何时可接着发送下一帧。
    • 使发送方知晓何时必须暂停发送,等待反馈信息后继续发送。
  • 不同体系结构中的情况
    • OSI体系结构
      • 数据链路层具有流量控制功能。
      • 控制对象是相邻节点之间数据链路上的流量。
    • TCP/IP体系结构
      • 流量控制功能移到传输层。
      • 控制对象是从源端到目的端之间的流量。

3.1.6 差错检测

  • 传输错误原因
    • 信道噪声导致帧传输错误
  • 错误类型
    • 位错
      • 定义:帧中某些位出现差错
      • 检测方法:循环冗余检验(CRC)
    • 帧错
      • 类型
        • 帧丢失
        • 帧重复
        • 帧失序
      • 性质:都属于传输差错
  • 历史处理方式(OSI观点)
    • 要求数据链路层提供可靠传输
    • 实现机制
      • 在CRC检错基础上增加
        • 帧编号
        • 确认机制
        • 重传机制
      • 工作流程
        • 接收方收到正确帧后发送确认
        • 发送方未收到确认时重传
  • 现代应用场景
    • 无线传输(通信质量差)
      • 仍使用确认和重传机制
      • 向上提供可靠传输服务
    • 有线链路(通信质量好)
      • 不再使用确认和重传机制
      • 仅进行CRC检错
        • 处理方式:丢弃有差错帧
        • 目的:保证上交帧都正确
      • 重传任务转移
        • 由高层协议完成
        • 例如:传输层TCP协议

3.2 组帧

3.2.1 字符计数法

  • 定义
    • 在帧首部使用计数字段记录该帧所含字节数
    • 包括计数字段自身占用的1字节
  • 工作原理
    • 接收方读取帧首部的字节计数值
    • 根据计数值确定帧结束位置
    • 连续传输特性可确定下一帧开始位置
  • 主要问题
    • 计数字段出错会导致帧边界划分失败
    • 后果
      • 无法判断帧结束位
      • 无法确定下一帧开始位
      • 收发双方失去同步
      • 造成灾难性后果

3.2.2 字节填充法

  • 定界方法
    • 使用特定字节定界帧的开始与结束
    • SOH: 帧开始控制字符
    • EOT: 帧结束控制字符
  • 特殊字符处理
    • 在特殊字符前填充转义字符ESC
    • 防止误判为帧首尾定界符
    • 转义字符是ASCII控制字符(单个字符)
  • 发送方处理
    • 数据段出现EOT/SOH时
      • 插入ESC字符
    • ESC出现在数据中时
      • 在ESC前再插入ESC
  • 接收方处理
    • 收到转义字符后
      • 知道后面是数据信息
    • 删除插入的ESC字符
      • 恢复原始数据

3.2.3 零比特填充法

  • 基本原理
    • 允许数据帧包含任意个数的比特
    • 使用特定比特串01111110标志帧的开始和结束
  • 发送方处理流程
    • 扫描整个数据字段
    • 每遇到5个连续的”1”
      • 自动在其后插入一个”0”
    • 保证数据字段中不会出现6个连续的”1”
  • 接收方处理流程
    • 执行逆操作
    • 每收到5个连续的”1”
      • 自动删除后面紧跟的”0”
    • 恢复原始数据
  • 应用实例
    • 数据链路层早期使用的HDLC协议
    • 采用这种比特填充的首尾标志法
    • 实现透明传输
  • 特点
    • 容易由硬件实现
    • 性能优于字节填充法

3.2.4 违规编码法

  • 违规编码法

    • 示例:曼彻斯特编码
      • 数据比特”1”编码为”高-低”电平对
      • 数据比特”0”编码为”低-高”电平对
      • 违规编码序列
        • “高-高”电平对
        • “低-低”电平对
    • 应用
      • 用于定界帧的起始和终止
      • 局域网IEEE 802标准采用
    • 特点
      • 无需填充技术实现透明传输
      • 仅适用于冗余编码的特殊编码环境
  • 组帧方法比较

    • 字符计数法
      • 缺点:计数字段脆弱
    • 字节填充法
      • 缺点
        • 实现复杂
        • 存在不兼容性
    • 常用方法
      • 零比特填充法
      • 违规编码法

3.3 差错控制

3.3.1 检错编码

  • 核心思想
    • 冗余编码技术
    • 有效数据+冗余位构成码字
    • 接收方根据规则判断是否出错
  • 常见检错编码
    • 奇偶检验码
      • 组成:n-1位数据 + 1位检验位
      • 类型
        • 奇检验码:1的个数为奇数
        • 偶检验码:1的个数为偶数
      • 特点
        • 只能检测奇数位出错
        • 不能定位错误位
        • 不能发现偶数位出错
    • 循环冗余码(CRC)
      • 基本思想
        • 约定生成多项式G(x)
        • 发送方计算并附加冗余码
        • 接收方通过G(x)检验差错
      • 帧检验序列(FCS)
        • m位数据 + r位冗余码
        • 帧能被G(x)整除
      • 计算步骤
        ①. 加0:数据后加r个0
        ②. 模2除:用G(x)二进制串除数据串
      • 模2运算规则
        • 加法不进位
        • 减法不借位
        • 对应位逻辑异或
      • 特点
        • 硬件实现快速
        • 无差错时余数为0
        • 误码时余数为0概率极低
      • 数据链路层应用
        • 仅使用检错功能
        • 检测出错直接丢弃
        • 不实现纠错功能

3.3.2 纠错编码

  • 海明码
    • 实现原理
      • 在有效信息位中加入检验位形成海明码
      • 把海明码的每个二进制位分配到几个奇偶检验组中
      • 某一位出错会引起相关检验位变化
      • 可以发现错位并指出位置
  • 码距
    • 定义
      • 两个码字对应位取值不同的比特数量
      • 计算方法:对两个位串进行异或运算,结果中1的个数
    • 编码集码距
      • 任意两个码字的码距的最小值
    • 纠错理论
      • 关系式:1=d+c+1, d≥c
      • 码距越大,检错位数d和纠错位数c越大
      • 纠错能力≤检错能力
    • 结论
      • 检测d位错误需要码距d+1
      • 纠正c位错误需要码距2c+1
  • 海明码编码过程
    • 确定海明码位数
      • 满足2^k≥n+k+1
    • 检验位分布
      • P_i位于海明位号2^(i-1)的位置
    • 分组形成检验关系
      • D1由P2P1检验
      • D2由P3P1检验
      • D3由P3P2检验
      • D4由P3P2P1检验
    • 检验位取值
      • 第i组所有位求异或
    • 检验原理
      • 检验方程:
        • S1=P1⊕D1⊕D2⊕D4
        • S2=P2⊕D1⊕D3⊕D4
        • S3=P3⊕D2⊕D3⊕D4
      • 判断:
        • S3S2S1=000表示无错
        • 否则数值表示错误位号

3.4 流量控制与可靠传输机制

3.4.1 流量控制与滑动窗口机制

  • 流量控制定义
    • 由接收方控制发送方的发送速率
    • 确保接收方有足够的缓冲空间接收每个帧
  • 流量控制方法
    • 停止-等待协议
    • 滑动窗口协议
  • 数据链路层与传输层流量控制的区别
      1. 控制范围
      • 数据链路层:相邻节点之间
      • 传输层:端到端
      1. 控制手段
      • 数据链路层:接收方收不下时不返回确认
      • 传输层:通过确认报文段中的窗口值调整发送窗口
  • 停止-等待流量控制
    • 基本原理
      • 发送方每次只发送一个帧
      • 接收方反馈确认信号后才能发送下一帧
      • 未收到确认则一直等待
    • 特点
      • 传输效率较低
  • 滑动窗口流量控制
    • 基本原理
      • 发送窗口:允许发送的连续帧序号
      • 接收窗口:允许接收的连续帧序号
    • 窗口滑动机制
      • 发送方:收到按序确认后窗口前滑
      • 接收方:收到落入窗口的帧后前滑并确认
    • 重要特性
        1. 接收窗口前滑是发送窗口前滑的前提
        1. 不同协议的窗口大小差异
        • 停止-等待协议:WT=1, WR=1
        • 后退N帧协议:WT>1, WR=1
        • 选择重传协议:WT>1, WR>1
        • 若采用n比特编号:WT+WR≤2ⁿ
        1. WR=1时可保证有序接收
        1. 数据链路层窗口大小固定

3.4.2 可靠传输机制

  • 定义
    • 发送方发送的数据都能被接收方正确地接收
  • 实现机制
    • 确认机制
      • 接收方向发送方发回确认帧
    • 超时重传机制
      • 发送方启动计时器,超时未收到确认则重传
  • 自动重传请求(ARQ)协议
    • 特点
      • 重传自动进行
      • 数据帧和确认帧必须编号
    • 分类
      • 停止-等待协议(S-W)
      • 后退N帧协议(GBN)
      • 选择重传协议(SR)
    • 应用范围
      • 不仅限于数据链路层
  • 有线网络与无线网络的差异
    • 有线网络
      • 误码率低
      • 可靠传输由上层处理
    • 无线网络
      • 误码率高
      • 数据链路层提供可靠传输
  • ①. 单帧滑动窗口与停止-等待协议(S-W)
    • 工作原理
      • 发送窗口=1,接收窗口=1
      • 收到确认后才能发送下一帧
    • 差错处理
      • 数据帧出错/丢失
        • 接收方丢弃
        • 发送方超时重传
      • 确认帧出错/丢失
        • 发送方重传
        • 接收方丢弃重复帧并重发确认
    • 帧编号
      • 1比特编号(0/1交替)
    • 缓冲区设置
      • 发送方保留副本直到收到确认
    • 信道利用率
  • ②. 多帧滑动窗口与后退N帧协议(GBN)
    • 工作原理
      • 发送窗口>1
      • 累积确认机制
      • 按序接收
    • 帧编号
      • n比特编号
      • 发送窗口限制:1<WT≤2ⁿ-1
    • 接收窗口
      • WR=1
    • 效率问题
      • 重传正确到达的帧
  • ③. 多帧滑动窗口与选择重传协议(SR)
    • 工作原理
      • 选择性重传
      • 接收窗口>1
      • 逐一确认
    • 帧编号
      • n比特编号
      • 窗口限制
        • WR+WT≤2ⁿ
        • WR≤WT
        • WR≤2ⁿ⁻¹
    • 差错处理
      • 否定帧NAK
  • ④. 信道利用率的分析
    • 定义
      • 有效发送时间/发送周期
    • 停止-等待协议
      • 计算公式
        • U=Tp/(Tp+RTT+TA)
      • 特点
        • 利用率低
    • 连续ARQ协议
      • 流水线传输
      • 两种情况
        ①. nTp<Tp+RTT+TA
        • U=nTp/(Tp+RTT+TA)
          ②. nTp≥Tp+RTT+TA
        • U=1
    • 数据传输速率计算
      • 信道平均速率=利用率×带宽

3.5 介质访问控制

3.5.1 信道划分介质访问控制

  • 定义
    • 将使用同一传输介质的多个设备的通信隔离开来
    • 通过复用技术实现
    • 复用原理:发送端组合信号,接收端分离信号
  • 实质
    • 通过分时、分频、分码等方法
    • 将广播信道转变为点对点信道
  • 分类
    • 频分复用 (FDM)
      • 原理:将总频带划分为多个子频带
      • 特点:所有用户在同一时间占用不同频带
      • 优点:充分利用带宽,系统效率高
    • 时分复用 (TDM)
      • 原理:将传输时间划分为TDM帧
      • 特点:固定时隙分配,周期性出现
      • 缺点:信道利用率不高
      • 改进:统计时分复用 (STDM)
        • 动态分配时隙
        • 提高线路利用率
    • 波分复用 (WDM)
      • 原理:光的频分复用
      • 特点:不同波长光信号互不干扰
      • 应用:光纤通信
    • 码分复用 (CDM)
      • 原理:采用不同编码区分信号
      • 特点:共享频率和时间
      • 码分多址 (CDMA)
        • 码片序列
        • 正交性要求
        • 数据分离计算
      • 优点
        • 频谱利用率高
        • 抗干扰能力强
        • 保密性强
      • 应用:无线通信系统

3.5.2 随机访问介质访问控制

  • 核心思想
    • 胜利者通过争用获得信道,进而获得信息的发送权
    • 随机访问介质访问控制协议也称争用型协议
  • 特点
    • 不采用集中控制方式
    • 所有用户随机发送信息
    • 可能产生帧冲突
  • 机制
    • 广播信道转换为点到点信道的机制
  • 1.ALOHA协议
    • 纯ALOHA协议
      • 基本思想
        • 不进行任何检测就发送数据
        • 未收到确认则认为发生冲突
        • 等待随机时间后重发
      • 工作原理
        • 帧长用发送时间T₀表示
        • 冲突后等待随机时间重传
      • 缺点
        • 吞吐量低
    • 时隙ALOHA协议
      • 改进
        • 时间划分为等长时隙
        • 只能在时隙开始时发送
      • 优点
        • 降低冲突概率
        • 提高信道利用率
  • 2.CSMA协议
    • 改进点
      • 发送前监听信道
    • 三种类型
      • 1-坚持CSMA
        • 信道空闲立即发送
        • 信道忙持续监听
      • 非坚持CSMA
        • 信道忙放弃监听
        • 随机时间后重新监听
      • p-坚持CSMA
        • 时分信道适用
        • 概率p发送数据
        • 概率1-p推迟
  • 3.CSMA/CD协议
    • 特点(2015)
      • 适用于总线形网络或半双工网络
      • 全双工网络不需要
    • 工作流程
      • 先听后发
      • 边听边发
      • 冲突停发
      • 随机重发
    • 最短帧长
      • 计算公式
        • 最短帧长=最大单向传播时延×数据传输速率×2
      • 以太网规定
        • 争用期51.2 μs
        • 10Mb/s以太网最短帧长64B
    • 二进制指数退避算法(2023)
      • 基本退避时间2t
      • 随机数r从[0,1,…,(2^k-1)]选取
      • 重传推迟时间2rt
      • 重传16次失败则丢弃
  • 4.CSMA/CA协议
    • 改进原因
      • 无线信号强度变化大
      • 隐蔽站问题
    • 确认机制(2011)
      • 使用链路层确认/重传(ARQ)
    • 帧间间隔(2020)
      • SIFS(最短)
      • PIFS(中等)
      • DIFS(最长)
    • 隐蔽站问题处理
      • RTS和CTS预约
    • 与CSMA/CD区别
      • CSMA/CD可检测冲突
      • CSMA/CA尽量避免冲突
      • 传输介质不同
      • 检测方式不同

3.5.3 轮询访问:令牌传递协议

  • 定义

    • 用户不能随机发送信息
    • 通过集中控制的监控站循环轮询每个节点
    • 决定信道分配
  • 令牌传递协议

    • 令牌特性
      • 特殊控制帧
      • 不包含信息
      • 控制信道使用
      • 确保同一时刻只有一个站独占信道
    • 工作流程
      • 站点必须等待令牌才能发送帧
      • 发送完成后释放令牌
      • 令牌按顺序依次传递
    • 优点
      • 不会发生冲突
      • 访问权公平
  • 令牌环网络工作过程

    • 网络空闲时只有令牌帧循环传递
    • 有数据要发送的站点
      • 修改令牌标志位
      • 附加传输数据
      • 将令牌变成数据帧发送
    • 数据帧传输过程
      • 站点转发数据
      • 检查目的地址
      • 地址匹配则复制数据帧
    • 数据帧返回源站点
      • 源站点停止转发
      • 检验传输错误
      • 出错则重传
    • 传输完成后
      • 重新产生令牌
      • 传递给下一站点
      • 交出信道控制权
  • 协议特点

    • 适合高负载广播信道
    • 不共享时间和空间
    • 限定有权发送数据的节点只能有一个
  • 数据链路层特性

    • 通过介质访问控制机制
    • 将广播信道变为逻辑点对点信道
    • 研究

3.6 局域网

3.6.1 局域网的基本概念和体系结构

  • 局域网(LAN)定义
    • 较小地理范围内
    • 连接计算机、外部设备和数据库系统
    • 资源和信息共享
  • 主要特点
      1. 单位所有,地理范围和站点数量有限
      1. 共享较高总带宽
      1. 低时延和低误码率
      1. 站点平等关系
      1. 能进行广播和多播
  • 决定因素
    • 拓扑结构
    • 传输介质
    • 介质访问控制方式(最重要)
  • 常见拓扑结构
    • ① 星形结构
    • ② 环形结构
    • ③ 总线形结构
    • ④ 星形和总线形结合的复合型结构
  • 传输介质
    • 铜缆
    • 双绞线(主流)
    • 光纤
  • 介质访问控制方法
    • CSMA/CD协议(总线形)
    • 令牌总线协议(总线形)
    • 令牌环协议(环形)
  • 特殊局域网拓扑实现
    • 以太网
      • 逻辑拓扑:总线形
      • 物理拓扑:星形
    • 令牌环(IEEE 802.5)
      • 逻辑拓扑:环形
      • 物理拓扑:星形
    • FDDI(IEEE 802.8)
      • 逻辑拓扑:环形
      • 物理拓扑:双环结构
  • IEEE802参考模型
    • 对应OSI的数据链路层和物理层
    • 数据链路层子层
      • 逻辑链路控制(LLC)子层
        • 与传输介质无关
        • 提供四种连接服务类型
          • 无确认无连接
          • 面向连接
          • 带确认无连接
          • 高速传送
      • 介质访问控制(MAC)子层
        • 屏蔽物理层访问差异
        • 主要功能
          • 组帧和拆卸帧
          • 比特传输差错检测
          • 透明传输
  • 现状
    • 以太网垄断市场
    • 许多网卡仅装MAC协议

3.6.2 以太网与IEEE 802.3

  • 以太网概述
    • 最流行的有线局域网技术
    • 发展历史
      • DIX V1(DEC、Intel、Xerox联合提出)
      • DIX Ethernet V2(第一个局域网产品规约)
      • IEEE 802.3标准(基于DIX Ethernet V2)
  • 以太网特点
    • 无连接工作方式
      • 不编号、不确认
      • 尽最大努力交付(不可靠服务)
      • 差错纠正由高层完成
    • 曼彻斯特编码
      • 中间电压转换
      • 便于位同步提取
  • ①. 传输介质与网卡
    • 传输介质类型
      • 粗缆
      • 细缆
      • 双绞线
      • 光纤
    • 网络适配器(网卡)
      • 功能
        • 串并转换
        • 物理连接与电信号匹配
        • 帧处理(发送/接收、封装/拆封)
        • 介质访问控制
        • 编码/解码
        • 数据缓存
      • 工作方式
        • 与局域网:串行通信
        • 与计算机:并行通信(通过I/O总线)
  • ②. MAC地址
    • 特点
      • 48位全球地址
      • 固化在适配器ROM中
      • 地理位置无关
    • 格式
      • 6字节(12位十六进制)
      • 高24位:厂商代码
      • 低24位:适配器序列号
    • 帧接收规则
      • 单播帧(目的地址=本站地址)
      • 广播帧(全1地址)
      • 多播帧(部分站点)
  • ③. MAC帧格式
    • 以太网V2标准
      • 前导码(8字节)
        • 前同步码(7字节)
        • 帧开始定界符(1字节)
      • 帧结构
        • 目的地址(6字节)
        • 源地址(6字节)
        • 类型(2字节)
        • 数据(46-1500字节)
        • FCS(4字节)
    • 与802.3帧区别
      • 长度域替代类型域
      • 长度/类型并存机制
  • ④. 高速以太网
    • 100BASE-T(快速以太网)
      • 100Mb/s速率
      • 保持802.3帧格式
      • 最大网段长度:100m
      • 帧间间隔:0.96μs
    • 吉比特以太网
      • 1Gb/s速率
      • 兼容10/100BASE-T
      • 全双工/半双工
    • 10吉比特以太网
      • 10Gb/s速率
      • 保持最小/最大帧长
      • 仅全双工工作

3.6.3 IEEE 802.11无线局域网

  • ①. 无线局域网的组成
    • (1)有固定基础设施无线局域网
      • IEEE 802.11系列协议标准(802.1la/b/g/n等)
      • 星形拓扑,中心为接入点(AP)
      • MAC层使用CSMA/CA协议
      • 基本服务集(BSS)
        • 组成:一个AP和若干移动站
        • 通信必须通过AP
        • 服务集标识符(SSID)和信道
        • 基本服务区(BSA),直径一般不超过100m
      • 扩展服务集(ESS)
        • 通过分配系统(DS)连接多个BSS
        • 通过Portal设备提供有线以太网接入
      • 移动站漫游
    • (2)无固定基础设施移动自组织网络
      • 自组网络(ad hoc network)
      • 平等状态的移动站组成临时网络
      • 每个移动站参与路由发现和维护
      • 与移动IP的区别
  • ②. 802.11局域网的MAC帧
    • 帧类型:数据帧、控制帧、管理帧
    • 数据帧格式
      • MAC首部(30字节)
      • 帧主体(不超过2312字节)
      • 帧检验序列FCS(4字节)
    • MAC首部地址字段
      • 地址1:直接接收数据帧的节点地址
      • 地址2:实际发送数据帧的节点地址
      • 地址3:实际目的地址或源地址
      • 地址4:用于自组网络
    • 帧控制字段
      • 类型字段和子类型字段
      • 控制帧(RTS、CTS、ACK等)
      • 数据帧
      • 管理帧
    • 持续期字段
      • 用于信道预约时间

3.7 广域网

3.7.1 广域网的基本概念

  • 广域网定义
    • 英文缩写: WAN (Wide Area Network)
    • 覆盖范围: 远超一个城市的长距离网络
    • 主要任务: 长距离运送主机发送的数据
  • 广域网特点
    • 节点间连接: 高速链路
    • 首要考虑: 通信容量必须足够大
  • 广域网与互联网的关系
    • 区别: 广域网≠互联网
    • 互联网特点: 可以连接不同类型网络,使用路由器连接
    • 连接方式: 局域网通过路由器与广域网相连
  • 广域网组成
    • 主要设备: 节点交换机(非路由器)
      • 功能: 存储并转发分组
      • 与路由器区别: 在单个网络中转发分组
    • 连接方式: 点到点连接
    • 可靠性设计: 一个节点交换机通常连接多个节点交换机
  • 数据链路层协议发展
    • 历史协议: HDLC(高级数据链路控制)
      • 适用环境: 通信线路质量较差年代
    • 当前主流协议: 点对点协议(PPP)
      • 适用环境: 误码率低的有线链路

3.7.2 PPP 协议

  • 应用场景
    • 用户计算机与ISP通信
    • 网络设备间直连专用线路
  • 组成部分
    • 链路控制协议(LCP)
      • 功能:建立/配置/测试数据链路连接
    • 网络控制协议(NCP)
      • 功能:为不同网络层协议建立逻辑连接
    • IP数据报封装方法
      • 受MTU限制
  • 帧格式
    • 首部(4字段)
      • 标志字段(F): 0x7E(定界符)
      • 地址字段(A): 0xFF
      • 控制字段(C): 0x03
      • 协议字段(2字节)
        • 0x0021: IP数据报
        • 0xC021: LCP数据
    • 信息段(0-1500字节)
    • 尾部(2字段)
      • 帧检验序列(FCS): 2字节CRC
      • 标志字段(F): 0x7E
  • 透明传输实现
    • 异步传输: 字节填充法(转义字符0x7D)
    • 同步传输: 零比特填充法
  • 工作流程(用户拨号示例)
    • ①. 链路静止状态
    • ②. 物理连接建立→链路建立状态
    • ③. LCP协商配置选项
      • 成功→鉴别状态
      • 失败→链路静止
    • ④. 身份鉴别
      • 成功→网络层协议状态
      • 失败→链路终止
    • ⑤. NCP配置网络层→链路打开状态
    • ⑥. 终止流程
      • 主动终止
      • 故障终止
  • 特点
    • ①. 无序号确认机制(不可靠服务)
    • ②. 仅支持全双工点对点
    • ③. 支持两端不同网络层协议
    • ④. 面向字节(帧长为整数字节)

3.8 数据链路层设备

3.8.2 以太网交换机

  • ①. 交换机的原理和特点
    • 以太网交换机也称二层交换机,工作在数据链路层
    • 实质是多接口的网桥,将网络分成小的冲突域
    • 优点:总容量为N×10Mb/s(N个接口)
    • 以太网交换机的特点:
        1. 接口直接连接主机或交换机时工作在全双工方式
        1. 具有并行性,能同时连通多对接口
        1. 接口连接集线器时使用CSMA/CD协议且工作在半双工方式
        1. 即插即用设备,帧转发表通过自学习算法建立
        1. 使用专用交换结构芯片,交换速率较高
    • 交换模式:
      • 直通交换方式
        • 优点:转发时延小
        • 缺点:不检查差错
      • 存储转发交换方式
        • 优点:可靠性高,支持不同速率接口转换
        • 缺点:时延较大
    • 具有多种速率接口(10Mb/s、100Mb/s等)
  • ②. 交换机的自学习功能
    • 过滤和转发借助交换表完成
    • 交换表表项包含:
        1. MAC地址
        1. 连通该MAC地址的接口
    • 自学习过程:
      • 收到帧后查找交换表
      • 若找不到目的MAC地址则广播
      • 将源地址和接口写入交换表
    • 表项设有有效时间,过期自动删除
  • ③. 共享式以太网和交换式以太网的对比
    • 主机发送普通帧:
      • 共享式:集线器转发到所有接口
      • 交换式:交换机根据目的MAC地址转发
    • 主机发送广播帧:
      • 共享式:集线器转发到所有接口
      • 交换式:交换机转发到所有接口
    • 多对主机同时通信:
      • 共享式:产生冲突
      • 交换式:不会产生冲突
    • 集线器和交换机的区别:
      • 集线器:不隔离广播域和冲突域
      • 交换机:不隔离广播域,隔离冲突域

2.1 通信基础

2.1.1 基本概念

  • ①. 数据、信号与码元
    • 通信目的:传输信息(文字、图像、视频等)
    • 数据:传送信息的实体
    • 信号:数据的电气或电磁表现
    • 分类:
      • 模拟数据/信号:取值连续
      • 数字数据/信号:取值离散
    • 码元:
      • 定义:固定时长的信号波形表示k进制数
      • 码元宽度:信号周期
      • 信息量:1码元可携带若干比特
  • ②. 信源、信道与信宿
    • 通信系统模型:
      • 信源:产生和发送数据的源头
      • 信道:信号的传输介质
        • 分类:
          • 按信号形式:模拟信道、数字信道
          • 按传输介质:无线信道、有线信道
        • 信号类型:
          • 基带信号:未调制的原始电信号
          • 宽带信号:调制后的频分复用模拟信号
      • 信宿:接收数据的终点
    • 数据传输方式:
      • 串行传输:逐比特按序传输(长距离)
      • 并行传输:多比特同时传输(近距离)
    • 通信交互方式:
      • 单向通信:单方向(广播)
      • 半双工通信:双向但不能同时
      • 全双工通信:双向同时
  • ③. 速率、波特与带宽
    • 速率:
      • 码元传输速率(波特率):每秒传输码元数(Baud)
      • 信息传输速率(比特率):每秒传输比特数(b/s)
      • 关系:比特率 = 波特率 × n(n为每码元比特数)
    • 带宽:
      • 模拟系统:频率范围(Hz)
      • 计算机网络:最高数据率(b/s)

2.1.2 信道的极限容量

  • 信道失真影响
    • 失真不影响通信质量的条件
    • 导致严重失真的因素
      • 码元传输速率高
      • 信号传输距离远
      • 噪声干扰大
      • 传输介质质量差
  • 奈奎斯特定理(奈氏准则)
    • 适用场景: 理想低通(无噪声、带宽有限)信道
    • 核心公式: 极限数据传输速率=2Wlog₂V (b/s)
    • 关键参数
      • W: 信道频率带宽(Hz)
      • V: 码元离散电平数量
    • 重要结论
      ①. 码元传输速率存在上限
      ②. 带宽越大传输能力越强
      ③. 只限制码元速率不限制信息速率
    • 提高数据速率的方法: 多元制调制
  • 香农定理
    • 适用场景: 带宽受限且有高斯噪声的信道
    • 核心公式: 极限数据传输速率=Wlog₂(1+S/N) (b/s)
    • 关键参数
      • W: 信道频率带宽(Hz)
      • S: 信号平均功率
      • N: 高斯噪声功率
    • 信噪比表示方法
      • 无单位记法: S/N
      • 分贝记法: 10log₁₀(S/N) dB
    • 重要结论
      ①. 带宽/信噪比越大速率越高
      ②. 给定条件下速率上限确定
      ③. 低于极限速率可实现无差错传输
      ④. 实际速率远低于理论极限
  • 奈氏准则 vs 香农定理
    • 奈氏准则: 仅考虑带宽与码元速率
    • 香农定理: 同时考虑带宽和信噪比
    • 共同结论: 单个码元携带比特数有限

2.1.3 编码与调制

  • 信号与数据转换
    • 编码: 数据→数字信号
    • 调制: 数据→模拟信号
  • 数字数据转换方式
    • 数字发送器→数字信号
    • 调制器→模拟信号
  • 模拟数据转换方式
    • PCM编码器→数字信号
    • 放大器调制器→模拟信号
  • 四种编码与调制方式
    • 数字数据编码为数字信号
      • 常用编码方式
        • 归零(RZ)编码
          • 特点: 码元中间跳变到零电平
          • 优点: 提供自同步机制
          • 缺点: 占用带宽
        • 非归零(NRZ)编码
          • 特点: 不归零
          • 优点: 编码效率最高
          • 缺点: 需要时钟线同步
        • 反向非归零(NRZI)编码
          • 特点: 电平跳变表示0,不变表示1
          • 应用: USB 2.0
        • 曼彻斯特编码
          • 特点: 码元中间电平跳变
          • 应用: 标准以太网
        • 差分曼彻斯特编码
          • 特点: 码元开始处跳变表示0
          • 优点: 抗干扰能力强
          • 应用: 宽带高速网
    • 模拟数据编码为数字信号
      • 步骤
        • 采样
          • 奈奎斯特定理: 采样频率≥2倍最大频率
        • 量化
          • 电平幅值→离散数字量
        • 编码
          • 离散整数→二进制编码
      • 应用: PCM编码
    • 数字数据调制为模拟信号
      • 调制方式
        • 调幅(AM)/幅移键控(ASK)
          • 特点: 改变振幅表示1和0
          • 缺点: 抗干扰能力差
        • 调频(FM)/频移键控(FSK)
          • 特点: 改变频率表示1和0
          • 优点: 抗干扰能力强
        • 调相(PM)/相移键控(PSK)
          • 特点: 改变相位表示1和0
          • 变种: DPSK(差分相移键控)
        • 正交幅度调制(QAM)
          • 特点: AM与PM结合
          • 数据传输速率公式: R=Blog₂(mn)
    • 模拟数据调制为模拟信号
      • 应用
        • 电话机和本地局交换机
      • 技术: 频分复用(FDM)

2.2 传输介质

2.2.1 双绞线、同轴电缆、光纤与无线传输介质

  • 传输介质分类
    • 导向传输介质
      • 铜线或光纤
      • 电磁波沿固体介质传播
    • 非导向传输介质
      • 自由空间(空气、真空或海水)
      • 无线传输
  • ①. 双绞线
    • 特点
      • 最常用传输介质
      • 两根绝缘铜导线绞合
      • 减少电磁干扰
    • 分类
      • 屏蔽双绞线(STP)
      • 非屏蔽双绞线(UTP)
    • 性能
      • 价格便宜
      • 模拟/数字传输
      • 通信距离:几千米到数十千米
      • 带宽取决于铜线粗细和传输距离
  • ②. 同轴电缆
    • 结构
      • 内导体
      • 绝缘层
      • 外导体屏蔽层
      • 绝缘保护套层
    • 分类
      • 50Ω同轴电缆
        • 传送基带数字信号
        • 早期局域网应用
      • 75Ω同轴电缆
        • 传送宽带信号
        • 有线电视系统应用
    • 特点
      • 良好抗干扰特性
      • 传输较高速率数据
  • ③. 光纤
    • 原理
      • 利用光脉冲通信
      • 1:有光脉冲
      • 0:无光脉冲
    • 结构
      • 纤芯(8-100μm)
      • 包层(较低折射率)
    • 传输原理
      • 全反射现象
    • 分类
      • 多模光纤
        • 多条光线传输
        • 适合近距离
      • 单模光纤
        • 单波长传输
        • 适合远距离
    • 优点
      • 通信容量大
      • 传输损耗小
      • 抗干扰性能好
      • 无串音干扰
      • 体积小重量轻
  • ④. 无线传输介质
    • 应用场景
      • 蜂窝移动电话
      • 无线局域网(WLAN)
      • 特殊场合移动联网
    • (1) 无线电波
      • 特点
        • 穿透能力强
        • 传输距离长
        • 全向传播
    • (2) 微波、红外线和激光
      • 共同特点
        • 需要视线通路
        • 指向性强
      • 微波通信
        • 频率:2-40GHz
        • 容量大
        • 直线传播
        • 需中继站
      • 卫星通信
        • 地球同步卫星中继
        • 优点
          • 容量大
          • 距离远
          • 覆盖广
        • 缺点
          • 保密性差
          • 传播时延长

2.2.2 物理层接口的特性

  • 定义
    • 在连接各种计算机的传输介质上传输比特流
    • 屏蔽硬件设备和传输介质的差异
  • 主要任务
    • 确定与传输介质接口有关的特性
      • 机械特性
        • 接线器的形状和尺寸
        • 引脚数量和排列
        • 固定和锁定装置
      • 电气特性
        • 各条线上的电压范围
        • 传输速率
        • 距离限制
      • 功能特性
        • 电平电压的意义
        • 每条线的功能
      • 过程特性(规程特性)
        • 不同功能事件的出现顺序

2.3 物理层设备

2.3.1 中继器

  • 主要功能
    • 放大、整形并转发信号
    • 消除信号失真和衰减
    • 扩大网络传输距离
  • 工作原理
    • 信号再生(非简单放大)
    • 双端口设计
      • 数据从一个端口输入
      • 从另一个端口发出
    • 仅作用于信号电气部分
  • 网络特性
    • 连接的是网段而非子网
    • 仍属于同一局域网
    • 故障影响
      • 对相邻两个网段产生影响
  • 使用限制
    • 理论上数量无限
    • 实际限制因素
      • 信号延迟范围规定
      • 5-4-3规则示例
        • 10BASE5以太网规范
        • 最多4个中继器串联
        • 5段介质中3段可接计算机
  • 与放大器的区别
    • 放大器
      • 放大模拟信号
      • 原理:放大衰减信号
    • 中继器
      • 放大数字信号
      • 原理:整形再生信号

2.3.2 集线器

  • 定义
    • 集线器(Hub)实质上是一个多端口的中继器
  • 工作原理
    • 端口接收数据信号
    • 信号整形放大(再生)
    • 转发到其他所有工作端口(除输入端口外)
    • 多端口输入时会发生冲突导致数据无效
  • 功能特点
    • 信号放大和转发
    • 扩大网络传输范围
    • 不具备信号定向传送能力
    • 标准的共享式设备
  • 组网特性
    • 组网灵活
    • 所有节点通信集中在中心节点
    • 组成共享式网络
    • 逻辑上仍是总线网
    • 每个端口连接同一网络的不同网段
    • 只能半双工工作
    • 网络吞吐率受限

1.1 计算机网络概述

1.1.1 计算机网络的概念

  • 计算机网络的概念
    • 定义
      • 将众多分散的、自治的计算机系统,通过通信设备与线路连接起来
      • 由功能完善的软件实现资源共享和信息传递的系统
    • 组成
      • 节点(Node)
        • 计算机
        • 集线器
        • 交换机
        • 路由器
      • 链路(Link)
    • 互连网(internet)
      • 网络之间通过路由器互连
      • 构成覆盖范围更广的计算机网络
    • 名词区分
      • internet(互连网)
        • 通用名词
        • 多个计算机网络互连而成
        • 可使用任意通信协议
      • Internet(互联网/因特网)
        • 专用名词
        • 全球最大、开放的特定计算机网络
        • 采用TCP/IP族作为通信规则

1.1.2 计算机网络的组成

  • 从组成部分看
    • 硬件
      • 主机(端系统)
      • 通信链路
        • 双绞线
        • 光纤
      • 交换设备
        • 路由器
        • 交换机
      • 通信处理机
        • 网卡
    • 软件
      • 资源共享软件
      • 工具软件
        • E-mail程序
        • FTP程序
        • 聊天程序
    • 协议
      • 网络传输数据规范
  • 从工作方式看(Internet)
    • 边缘部分
      • 用户直接使用的主机
      • 功能
        • 通信
          • 数据传输
          • 音频/视频
        • 资源共享
    • 核心部分
      • 网络和路由器
      • 功能
        • 提供连通性
        • 交换服务
  • 从功能组成看
    • 通信子网
      • 组成
        • 传输介质
        • 通信设备
        • 网络协议
      • 功能
        • 数据传输
        • 交换
        • 控制
        • 存储
    • 资源子网
      • 组成
        • 资源共享设备
        • 软件
      • 功能
        • 提供硬件资源共享服务
        • 提供软件资源共享服务
        • 提供数据资源共享服务

1.1.3 计算机网络的功能

  • 数据通信
    • 最基本和最重要的功能
    • 实现联网计算机之间各种信息的传输
    • 应用示例
      • 文件传输
      • 电子邮件
  • 资源共享
    • 共享类型
      • 软件共享
      • 数据共享
      • 硬件共享
    • 优势
      • 互通有无、分工协作
      • 提高资源利用率
  • 分布式处理
    • 定义
      • 将复杂任务分配给网络中空闲计算机
    • 优势
      • 提高系统利用率
  • 提高可靠性
    • 定义
      • 各台计算机互为替代机
  • 负载均衡
    • 定义
      • 均衡分配工作任务给各台计算机
  • 其他功能
    • 电子化办公与服务
    • 远程教育
    • 娱乐功能
    • 社会效益
      • 满足社会需求
      • 方便学习、工作和生活
      • 巨大经济效益

1.1.4 电路交换、报文交换与分组交换

  • 电路交换
    • 特点
      • 建立连接、传输数据、释放连接
      • 物理通信路径独占
    • 优点
      • 通信时延小
      • 有序传输
      • 没有冲突
      • 实时性强
    • 缺点
      • 建立连接时间长
      • 线路利用率低
      • 灵活性差
      • 难以实现差错控制
  • 报文交换
    • 特点
      • 存储转发技术
      • 报文为单位传输
    • 优点
      • 无建立连接时延
      • 灵活分配线路
      • 线路利用率高
      • 支持差错控制
    • 缺点
      • 转发时延高
      • 缓存开销大
      • 错误处理低效
  • 分组交换
    • 特点
      • 存储转发技术
      • 将报文划分为分组
    • 优点
      • 方便存储管理
      • 传输效率高
      • 减少出错概率和重传代价
    • 缺点
      • 存在存储转发时延
      • 需要传输额外信息量
      • 可能出现失序、丢失或重复分组
  • 三种交换方式比较
    • 电路交换适合连续大量数据传输
    • 报文交换和分组交换信道利用率更高
    • 分组交换更适合突发式数据传送

1.1.5 计算机网络的分类

  • 按分布范围分类
    • 广域网 (WAN)
      • 任务: 提供长距离通信
      • 覆盖范围: 几十米到几千千米
      • 特点: 互联网核心部分, 高速链路
    • 城域网 (MAN)
      • 覆盖范围: 5~50km
      • 技术: 以太网技术
    • 局域网 (LAN)
      • 覆盖范围: 几十到几千米
      • 特点: 主机高速线路相连, 广播技术
    • 个人区域网 (PAN)
      • 定义: 个人电子设备无线连接
      • 别名: 无线个人区域网 (WPAN)
  • 按传输技术分类
    • 广播式网络
      • 特点: 共享公共通信信道
      • 应用: 局域网, 无线/卫星通信
    • 点对点网络
      • 特点: 物理线路连接一对计算机
      • 传输方式: 存储转发
  • 按拓扑结构分类
    • 总线形网络
      • 特点: 单根传输线连接
      • 优点: 建网容易, 节省线路
      • 缺点: 重负载效率低
    • 星形网络
      • 特点: 单独线路连接中央设备
      • 优点: 便于集中控制
      • 缺点: 成本高
    • 环形网络
      • 特点: 接口设备连接成环
      • 例子: 令牌环局域网
    • 网状网络
      • 特点: 每个节点多条路径
      • 应用: 广域网
      • 优点: 可靠性高
      • 缺点: 控制复杂
  • 按使用者分类
    • 公用网 (Public Network)
      • 特点: 电信公司建造, 付费使用
    • 专用网 (Private Network)
      • 特点: 单位专用, 不对外开放
  • 按传输介质分类
    • 有线网络
      • 类型
        • 双绞线
        • 同轴电缆
    • 无线网络
      • 类型
        • 蓝牙
        • 微波
        • 无线电

1.1.6 计算机网络的性能指标

  • 1)速率 (Speed)
    • 定义:节点在数字信道上传送数据的速率
    • 别名:数据传输速率/数据率/比特率
    • 单位:b/s(bit/s/bps)
    • 高数据率表示:kb/s(10³)/Mb/s(10⁶)/Gb/s(10⁹)
  • 2)带宽(Bandwidth)
    • 原义:通信线路允许通过的信号频率范围(Hz)
    • 网络定义:通信线路传送数据的能力(最高数据传输速率)
    • 单位:b/s
  • 3)吞吐量(Throughput)
    • 定义:单位时间通过网络的实际数据量
    • 用途:实际网络测量
  • 4)时延(Delay)
    • 定义:数据从网络一端传送到另一端的总时间
    • 组成:
      • 发送时延(传输时延)
        • 公式:分组长度/发送速率
      • 传播时延
        • 公式:信道长度/电磁波传播速率
      • 处理时延
      • 排队时延
    • 总时延公式:发送+传播+处理+排队
  • 5)时延带宽积
    • 定义:传播时延×信道带宽
    • 物理意义:链路可容纳的比特数量
  • 6)往返时延(RTT)
    • 定义:发送分组到收到确认的总时间
    • 包含:中间节点处理/排队/发送时延
  • 7)信道利用率
    • 定义:信道有数据通过的时间百分比
    • 公式:有数据时间/(有数据+无数据时间)
    • 注意事项:过高会导致时延增大

1.2 计算机网络体系结构与参考模型

1.2.1 计算机网络分层结构

  • 网络体系结构的定义
    • 计算机网络的各层及其协议的集合称为网络的体系结构
    • 体系结构是抽象的,实现是具体的
  • 分层的基本原则
    • 1)每层实现相对独立的功能
    • 2)各层接口清晰,交流少
    • 3)功能定义独立于实现方法
    • 4)下层对上层的独立性
    • 5)促进标准化工作
  • 分层结构中的概念
    • 实体
      • 第n层的活动元素
      • 对等层和对等实体
    • 服务关系
      • 第n层向第n+1层提供服务
      • 服务提供者与服务用户
  • 数据单元
    • 协议数据单元(PDU)
      • n-PDU = n-SDU + n-PCI
      • 各层PDU名称
        • 物理层:比特流
        • 数据链路层:帧
        • 网络层:分组
        • 传输层:报文段
    • 服务数据单元(SDU)
    • 协议控制信息(PCI)
  • 层次结构的含义
    • 1)第n层使用n-1层服务,并向n+1层提供服务
    • 2)最低层只提供服务,最高层面向用户
    • 3)上层只能通过相邻层接口使用下层服务
    • 4)对等层在逻辑上有直接信道

1.2.2 计算机网络协议、接口、服务的概念

  • 协议
    • 定义
      • 控制对等实体之间通信的规则的集合
      • 是水平的
    • 组成
      • 语法
        • 数据与控制信息的格式
      • 语义
        • 需要发出何种控制信息、完成何种动作及做出何种应答
      • 同步(时序)
        • 执行各种操作的条件、时序关系
  • 接口
    • 定义
      • 同一节点内相邻两层实体交换信息的逻辑接口(SAP)
    • 特点
      • 只能在紧邻层之间定义
      • 第n层SAP是第n+1层访问第n层服务的入口
  • 服务
    • 定义
      • 下层为紧邻上层提供的功能调用
      • 是垂直的
    • 服务与协议的区别
      • 协议是水平的,服务是垂直的
      • 只有本层协议实现才能向上层提供服务
      • 下层协议对上层服务用户透明
    • 服务分类
      • 面向连接服务与无连接服务
        • 面向连接服务
          • 三个阶段:连接建立、数据传输、连接释放
        • 无连接服务
          • 直接发送数据包
      • 可靠服务和不可靠服务
        • 可靠服务
          • 具有纠错、检错、应答机制
        • 不可靠服务
          • 尽力而为的服务
      • 有应答服务和无应答服务
        • 有应答服务
          • 传输系统内部自动实现应答
        • 无应答服务
          • 需要应答由高层实现

1.2.3 ISO/OSI 参考模型和TCP/IP模 型

  • OSI 参考模型
    • 层次结构
      • 物理层
        • 传输单位:比特
        • 功能:透明传输原始比特流
        • 研究内容
          • 电路接口参数
          • 信号意义和电气特征
      • 数据链路层
        • 传输单位:帧
        • 功能
          • 差错控制
          • 流量控制
          • 广播信道访问控制
      • 网络层
        • 传输单位:数据报
        • 功能
          • 路由选择
          • 流量控制
          • 拥塞控制
          • 差错控制
          • 网际互联
      • 传输层
        • 传输单位:报文段/用户数据报
        • 功能
          • 端到端通信
          • 流量控制
          • 差错控制
          • 连接管理
      • 会话层
        • 功能
          • 建立/管理/终止会话
          • 同步机制
      • 表示层
        • 功能
          • 数据表示转换
          • 数据压缩
          • 加密解密
      • 应用层
        • 功能:用户与网络接口
        • 协议:多种应用协议
  • TCP/IP 模型
    • 层次结构
      • 网络接口层
        • 对应OSI:物理层+数据链路层
      • 网际层
        • 核心协议:IP
        • 功能:分组路由选择
      • 传输层
        • 协议
          • TCP:面向连接可靠传输
          • UDP:无连接不可靠传输
      • 应用层
        • 协议
          • Telnet
          • FTP
          • DNS
          • SMTP
          • HTTP
  • TCP/IP模型与OSI参考模型比较
    • 相似之处
      • 分层体系结构
      • 独立协议栈
      • 解决异构网络互联
    • 差异
      • 概念区分
        • OSI明确区分服务/协议/接口
        • TCP/IP未明确区分
      • 层次数量
        • OSI:7层
        • TCP/IP:4层
      • 设计顺序
        • OSI:先模型后协议
        • TCP/IP:先协议后模型
      • 通信模式
        • OSI网络层:无连接+面向连接
        • TCP/IP网际层:仅无连接

1. 简单的HTML页面架构

HTML5标准文档结构是网页的基础框架,包含文档类型声明、根元素、头部和主体部分。

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>WEB安全学习平台</title>
</head>
<body>
<!-- 页面内容将放置在这里 -->
</body>
</html>

关键点解析:

  • <!DOCTYPE html>:声明文档类型为HTML5,确保浏览器以标准模式渲染页面
  • <html lang="zh-CN">:根元素,lang属性指定页面语言为中文
  • <meta charset="UTF-8">:设置字符编码为UTF-8,确保中文等特殊字符正常显示
  • <title>:定义浏览器标签页显示的标题
  • <body>:包含所有页面可见内容的容器

安全提示:UTF-8编码是安全首选,避免使用GBK等编码,防止编码转换导致的XSS漏洞。

2. HTML常见标签详解

2.1 meta标签

<meta> 元素用于提供关于HTML文档的元数据,对SEO和安全配置至关重要。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<!-- 字符编码 -->
<meta charset="UTF-8">

<!-- 页面描述(SEO优化) -->
<meta name="description" content="WEB安全HTML基础教程 - 安全渗透必备技能">

<!-- 关键词(现代搜索引擎已不依赖,但部分场景仍有用) -->
<meta name="keywords" content="网络安全, WEB渗透, 数据安全, 渗透测试, 安全培训">

<!-- 作者信息 -->
<meta name="author" content="moonsec">

<!-- 移动设备适配 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<!-- 内容安全策略(CSP)- 重要安全配置 -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'">

<!-- X-Frame-Options - 防止点击劫持 -->
<meta http-equiv="X-Frame-Options" content="DENY">

<!-- 刷新页面(5秒后跳转) -->
<meta http-equiv="refresh" content="5;url=https://www.example.com">
</head>
<body>
</body>
</html>

安全说明:

  • Content-Security-Policy 是防御XSS攻击的重要手段,限制可执行的脚本来源
  • X-Frame-Options: DENY 防止页面被嵌入到iframe中,避免点击劫持攻击
  • charset=UTF-8 是安全基础,避免编码转换漏洞

2.2 标题标签

HTML提供6级标题标签,从<h1><h6>,其中<h1>级别最高,<h6>最低。

1
2
3
4
5
6
7
8
9
10
11
12
13
<h1>WEB安全核心知识</h1>
<h2>HTML基础</h2>
<h3>表单安全</h3>
<h4>常见漏洞类型</h4>
<h5>XSS攻击原理</h5>
<h6>防御措施</h6>

<!-- 换行标签 -->
<p>这是第一段内容<br>换行后的内容</p>

<!-- 水平线标签 -->
<hr>
<p>水平线分割内容</p>

最佳实践:

  • 一个页面通常只有一个<h1>,用于主标题
  • 标题层级应逐级下降,不要跳级使用(如不要从<h1>直接到<h4>
  • 合理的标题结构有助于屏幕阅读器理解页面结构,提升可访问性
  • 换行标签<br>应避免过度使用,优先使用CSS控制布局

2.3 文本属性

常用文本格式化标签,注意HTML5中已废弃某些标签,应使用CSS替代。

1
2
3
4
5
6
7
8
9
10
11
12
<p><strong>加粗文本(语义重要)</strong><b>加粗文本(仅视觉)</b></p>
<p><em>斜体文本(语义强调)</em><i>斜体文本(仅视觉)</i></p>
<p><u>下划线文本(谨慎使用,通常用于链接)</u></p>
<p>数学公式: X<sup>2</sup> + H<sub>2</sub>O</p>
<p><del>已删除的内容</del> <ins>已添加的内容</ins></p>
<pre>
预格式化文本示例:
保留空格和换行
function example() {
console.log("Hello World");
}
</pre>

安全注意事项:

  • <font> 标签在HTML5中已被废弃,应使用CSS控制字体样式
  • <strong><em> 具有语义含义,表示内容的重要性或强调,对SEO和可访问性有帮助
  • <del><ins> 用于表示内容的删除和添加,常用于修订文档
  • <pre> 保留所有空格和换行,适合展示代码、ASCII艺术等

2.4 form表单

<form> 用于创建用户可提交数据的表单,是Web交互的核心组件,也是安全漏洞高发区。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<form action="/submit" method="post" enctype="multipart/form-data">
<label for="username">用户名:</label>
<input type="text" id="username" name="username" placeholder="请输入用户名" required>
<br><br>

<label for="password">密码:</label>
<input type="password" id="password" name="password" minlength="8" required>
<br><br>

<label for="file">上传头像:</label>
<input type="file" id="file" name="avatar" accept="image/*">
<br><br>

<label for="email">邮箱:</label>
<input type="email" id="email" name="email" required>
<br><br>

<label for="color">选择颜色:</label>
<input type="color" id="color" name="color" value="#ff0000">
<br><br>

<label for="checkbox1">选项1</label>
<input type="checkbox" id="checkbox1" name="option" value="1">
<label for="checkbox2">选项2</label>
<input type="checkbox" id="checkbox2" name="option" value="2">
<br><br>

<label for="radio1">选项A</label>
<input type="radio" id="radio1" name="group" value="A" checked>
<label for="radio2">选项B</label>
<input type="radio" id="radio2" name="group" value="B">
<br><br>

<input type="submit" value="提交">
<input type="reset" value="重置">
<input type="hidden" name="csrf_token" value="abc123">
</form>

安全关键点:

  • method="post":数据通过HTTP请求体发送,适合敏感数据(如登录),GET方法会将数据暴露在URL中
  • enctype="multipart/form-data":文件上传时必须使用此编码类型
  • required:必填字段,提交时会自动验证
  • placeholder:输入框提示文本
  • accept="image/*":限制文件类型为图片
  • minlength:设置密码最小长度
  • hidden:隐藏域,用于传递不可见数据(如CSRF令牌)
  • 安全提示:表单应使用HTTPS传输,对用户输入进行严格验证,防止XSS和SQL注入攻击

2.5 a标签、img标签、table标签

a标签(超链接)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- 外部链接(新窗口打开) -->
<a href="https://www.baidu.com" target="_blank" rel="noopener noreferrer">百度(新窗口打开)</a>

<!-- 锚点跳转 -->
<a href="#section1">跳转到章节1</a>
<a href="#section2">跳转到章节2</a>

<!-- 锚点定义 -->
<h2 id="section1">章节1</h2>
<h2 id="section2">章节2</h2>

<!-- 邮箱链接 -->
<a href="mailto:example@example.com">发送邮件</a>

<!-- 电话链接 -->
<a href="tel:+8613800138000">拨打电话</a>

安全注意事项:

  • rel="noopener noreferrer" 是必须的,防止新打开的页面通过window.opener访问原页面
  • 避免直接使用target="_blank"而不加rel属性,存在安全风险
  • 锚点跳转应使用id属性,而非name属性

img标签(图像)

1
<img src="logo.png" alt="网站Logo" width="200" height="100" loading="lazy" style="border: 1px solid #ccc;">

关键属性:

  • src:图像URL(必须)
  • alt:替代文本,当图像无法加载时显示,对SEO和可访问性至关重要,也是防止XSS攻击的关键
  • width/height:设置图像尺寸(建议同时设置以避免布局抖动)
  • loading="lazy":延迟加载,提升页面性能
  • 安全提示:始终设置alt属性,避免空alt(alt=””)用于装饰性图片

table标签(表格)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<table>
<caption>常见Web安全漏洞类型</caption>
<thead>
<tr>
<th>漏洞类型</th>
<th>危害等级</th>
<th>检测方法</th>
<th>防御措施</th>
</tr>
</thead>
<tbody>
<tr>
<td>XSS(跨站脚本)</td>
<td></td>
<td>输入验证、输出编码检查</td>
<td>对用户输入进行过滤,对输出进行HTML编码</td>
</tr>
<tr>
<td>SQL注入</td>
<td></td>
<td>SQL语句参数化查询检查</td>
<td>使用预编译语句、ORM框架</td>
</tr>
<tr>
<td>CSRF(跨站请求伪造)</td>
<td></td>
<td>检查Referer头、CSRF令牌验证</td>
<td>实施CSRF令牌机制、SameSite Cookie属性</td>
</tr>
</tbody>
</table>

表格结构详解:

标签 作用 说明
<table> 表格容器 定义表格的开始和结束
<caption> 表格标题 放置在表格顶部,描述表格内容
<thead> 表头部分 包含表格的表头行,通常包含<tr><th>
<tbody> 表格主体 包含表格的主要数据行
<tfoot> 表尾部分 包含表格的总结行(可选)
<tr> 表格行 定义一行数据
<th> 表头单元格 默认加粗并居中显示,用于表头
<td> 普通单元格 用于表格中的常规数据单元格

合并单元格示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<table>
<caption>漏洞类型与防御措施</caption>
<thead>
<tr>
<th>漏洞类型</th>
<th colspan="2">防御措施</th>
</tr>
</thead>
<tbody>
<tr>
<td rowspan="2">XSS</td>
<td>输入过滤</td>
<td>输出编码</td>
</tr>
<tr>
<td colspan="2">使用Content Security Policy (CSP)</td>
</tr>
<tr>
<td>SQL注入</td>
<td colspan="2">参数化查询、ORM框架</td>
</tr>
</tbody>
</table>

现代表格样式(推荐):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<style>
.security-table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
.security-table th, .security-table td {
padding: 12px;
border: 1px solid #ddd;
}
.security-table th {
background-color: #f2f2f2;
font-weight: bold;
}
.high-risk {
color: #e74c3c;
font-weight: bold;
}
.medium-risk {
color: #f39c12;
font-weight: bold;
}
.low-risk {
color: #2ecc71;
font-weight: bold;
}
</style>

<table class="security-table">
<caption>常见Web安全漏洞类型</caption>
<thead>
<tr>
<th>漏洞类型</th>
<th>危害等级</th>
<th>检测方法</th>
<th>防御措施</th>
</tr>
</thead>
<tbody>
<tr>
<td>XSS(跨站脚本)</td>
<td class="high-risk"></td>
<td>输入验证、输出编码检查</td>
<td>对用户输入进行过滤,对输出进行HTML编码</td>
</tr>
<tr>
<td>SQL注入</td>
<td class="high-risk"></td>
<td>SQL语句参数化查询检查</td>
<td>使用预编译语句、ORM框架</td>
</tr>
<tr>
<td>CSRF(跨站请求伪造)</td>
<td class="medium-risk"></td>
<td>检查Referer头、CSRF令牌验证</td>
<td>实施CSRF令牌机制、SameSite Cookie属性</td>
</tr>
</tbody>
</table>

表格使用注意事项:

  • 不要用表格做页面布局,现代Web开发应使用CSS Flexbox或Grid
  • 表格应只用于展示表格形式的数据
  • 为表格添加适当的标题和描述,提高屏幕阅读器的可访问性

2.6 锚文本

锚文本用于页面内跳转,通过id属性定义锚点,然后使用<a href="#id">链接到该位置。

1
2
3
4
5
6
<!-- 锚点链接 -->
<a href="#section3">跳转到章节3</a>

<!-- 锚点定义 -->
<h2 id="section3">章节3</h2>
<p>这是章节3的内容,点击上方链接可快速跳转至此</p>

最佳实践:

  • 使用id属性定义锚点(现代标准),而非name属性
  • 锚点ID应具有语义性,如id="contact-form"而非id="section1"
  • 避免在单页应用中过度使用锚点,可能影响用户体验

2.7 列表标签

无序列表

1
2
3
4
5
<ul style="list-style-type: circle;">
<li>项目1</li>
<li>项目2</li>
<li>项目3</li>
</ul>

有序列表

1
2
3
4
5
<ol type="A">
<li>第一项</li>
<li>第二项</li>
<li>第三项</li>
</ol>

列表类型说明:

  • 无序列表(ul):项目符号样式可通过CSS控制(disc, circle, square)
  • 有序列表(ol):type属性可指定编号样式:
    • 1:数字(默认)
    • A:大写字母
    • a:小写字母
    • I:大写罗马数字
    • i:小写罗马数字
  • 现代实践:列表样式应使用CSS控制,而非HTML属性

2.8 框架的使用

重要提示<frameset> 在HTML5中已被废弃,不推荐使用。现代网页开发中应使用<iframe>嵌入其他页面。

1
2
3
4
5
6
7
8
<iframe 
src="https://www.example.com"
width="800"
height="600"
scrolling="auto"
title="示例嵌入页面"
style="border: 1px solid #ccc;">
</iframe>

iframe属性详解:

  • src:嵌入页面的URL
  • width/height:尺寸(建议使用CSS控制)
  • scrolling:滚动条行为(auto/yes/no)
  • title:提供描述,提高可访问性
  • 安全注意:嵌入第三方内容时需谨慎,防止XSS攻击

安全提示

  • 使用allow属性限制iframe功能
  • 设置sandbox属性增强安全性
  • 避免嵌入不可信的第三方内容
  • 配置CSP的frame-ancestors指令控制iframe嵌入

综合示例:WEB安全学习平台

以下是一个包含所有知识点的完整HTML页面示例,展示如何将各种HTML标签组合成一个实用的WEB安全学习页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="WEB安全HTML基础综合示例 - 安全培训课程">
<meta name="keywords" content="网络安全, WEB渗透, 数据安全, 渗透测试, 安全培训, HTML基础">
<meta name="author" content="moonsec">
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'">
<meta http-equiv="X-Frame-Options" content="DENY">
<title>WEB安全学习平台 - HTML基础教程</title>
<style>
body {
font-family: 'Microsoft YaHei', sans-serif;
line-height: 1.6;
margin: 0;
padding: 20px;
color: #333;
}
header {
background-color: #2c3e50;
color: white;
padding: 20px;
text-align: center;
border-radius: 5px;
margin-bottom: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.section {
background: #f9f9f9;
padding: 20px;
margin-bottom: 20px;
border-radius: 5px;
border-left: 4px solid #3498db;
}
.security-table {
width: 100%;
border-collapse: collapse;
margin: 10px 0;
}
.security-table th, .security-table td {
padding: 12px;
border: 1px solid #ddd;
}
.security-table th {
background-color: #f2f2f2;
font-weight: bold;
}
.high-risk {
color: #e74c3c;
font-weight: bold;
}
.medium-risk {
color: #f39c12;
font-weight: bold;
}
.low-risk {
color: #2ecc71;
font-weight: bold;
}
.code-block {
background: #2d2d2d;
color: #f8f8f2;
padding: 15px;
border-radius: 5px;
overflow-x: auto;
font-family: monospace;
}
footer {
text-align: center;
margin-top: 30px;
padding: 20px;
background: #2c3e50;
color: white;
border-radius: 5px;
}
</style>
</head>
<body>
<header>
<h1>WEB安全学习平台</h1>
<p>HTML基础教程 - 安全渗透必备技能</p>
</header>

<div class="container">
<div class="section">
<h2 id="introduction">一、HTML基础概述</h2>
<p>HTML(超文本标记语言)是构建Web页面的基础,是WEB安全人员必须掌握的核心技能之一。掌握HTML有助于理解网页结构、识别潜在安全漏洞(如XSS、CSRF等)。</p>

<h3>HTML文档结构</h3>
<pre class="code-block">
&lt;!DOCTYPE html&gt;
&lt;html lang="zh-CN"&gt;
&lt;head&gt;
&lt;meta charset="UTF-8"&gt;
&lt;title&gt;示例页面&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;!-- 页面内容 --&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
</div>

<div class="section">
<h2 id="form-example">二、表单安全示例</h2>
<p>表单是WEB应用中常见漏洞来源,了解表单结构有助于识别安全问题。</p>

<form action="/submit" method="post" enctype="multipart/form-data">
<label for="username">用户名:</label>
<input type="text" id="username" name="username" placeholder="请输入用户名" required>
<br><br>

<label for="password">密码:</label>
<input type="password" id="password" name="password" minlength="8" required>
<br><br>

<label for="file">上传头像:</label>
<input type="file" id="file" name="avatar" accept="image/*">
<br><br>

<label for="email">邮箱:</label>
<input type="email" id="email" name="email" required>
<br><br>

<label for="color">选择颜色:</label>
<input type="color" id="color" name="color" value="#ff0000">
<br><br>

<input type="submit" value="提交表单">
<input type="hidden" name="csrf_token" value="abc123">
</form>

<p><strong>安全提示:</strong>表单应使用HTTPS传输,对用户输入进行严格验证,防止XSS和SQL注入攻击。</p>
</div>

<div class="section">
<h2 id="table-example">三、数据表格示例</h2>
<p>表格常用于展示结构化数据,安全人员需理解其结构以识别潜在漏洞。</p>

<table class="security-table">
<caption>常见Web安全漏洞类型</caption>
<thead>
<tr>
<th>漏洞类型</th>
<th>危害等级</th>
<th>检测方法</th>
<th>防御措施</th>
</tr>
</thead>
<tbody>
<tr>
<td>XSS(跨站脚本)</td>
<td class="high-risk"></td>
<td>输入验证、输出编码检查</td>
<td>对用户输入进行过滤,对输出进行HTML编码</td>
</tr>
<tr>
<td>SQL注入</td>
<td class="high-risk"></td>
<td>SQL语句参数化查询检查</td>
<td>使用预编译语句、ORM框架</td>
</tr>
<tr>
<td>CSRF(跨站请求伪造)</td>
<td class="medium-risk"></td>
<td>检查Referer头、CSRF令牌验证</td>
<td>实施CSRF令牌机制、SameSite Cookie属性</td>
</tr>
<tr>
<td>文件上传漏洞</td>
<td class="high-risk"></td>
<td>检查文件类型验证<br>查看文件存储路径是否可预测</td>
<td>限制文件类型<br>重命名上传文件<br>将上传文件存储在非Web可访问目录<br>检查文件内容</td>
</tr>
</tbody>
</table>
</div>

<div class="section">
<h2 id="resources">四、学习资源</h2>
<p>以下是一些WEB安全学习资源:</p>

<ul>
<li><a href="https://owasp.org" target="_blank" rel="noopener noreferrer">OWASP(开放Web应用安全项目)</a></li>
<li><a href="https://portswigger.net" target="_blank" rel="noopener noreferrer">PortSwigger(Burp Suite开发者)</a></li>
<li><a href="https://www.freebuf.com" target="_blank" rel="noopener noreferrer">FreeBuf(安全资讯平台)</a></li>
</ul>

<h3>相关视频教程</h3>
<iframe
src="https://www.youtube.com/embed/dQw4w9WgXcQ"
width="560"
height="315"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen
title="WEB安全入门视频"
sandbox="allow-same-origin allow-scripts allow-popups">
</iframe>
</div>

<div class="section">
<h2 id="contact">五、联系我们</h2>
<p>有任何问题欢迎通过以下方式联系我们:</p>
<ul>
<li>邮箱:<a href="mailto:support@websec.com">support@websec.com</a></li>
<li>电话:<a href="tel:+8613800138000">138-0013-8000</a></li>
</ul>

<h3>反馈表单</h3>
<form action="/feedback" method="post">
<label for="feedback">您的意见:</label>
<textarea id="feedback" name="feedback" rows="4" required></textarea>
<br><br>
<input type="submit" value="提交反馈">
</form>
</div>
</div>

<footer>
<p>&copy; 2025 WEB安全学习平台 | 本页面使用HTML5标准构建</p>
<p><a href="#introduction">返回顶部</a> | <a href="#form-example">表单示例</a> | <a href="#table-example">表格示例</a></p>
</footer>
</body>
</html>

安全最佳实践总结

  1. 字符编码:始终使用UTF-8编码,避免编码转换漏洞
  2. 表单安全
    • 使用POST方法提交敏感数据
    • 对用户输入进行严格验证和过滤
    • 使用CSRF令牌防止跨站请求伪造
    • 限制文件上传类型和大小
  3. 内容安全策略(CSP)
    • 通过Content-Security-Policy头限制可执行的脚本来源
    • 防止XSS攻击
  4. X-Frame-Options
    • 设置为DENYSAMEORIGIN防止点击劫持
  5. iframe安全
    • 使用sandbox属性限制iframe功能
    • 避免嵌入不可信的第三方内容
  6. 链接安全
    • 外部链接使用target="_blank" rel="noopener noreferrer"
    • 防止通过window.opener访问原页面
  7. 表格使用
    • 仅用于展示结构化数据,不用于页面布局
    • 为表格添加适当的标题和描述
    • 使用CSS控制样式,而非HTML属性

重要提醒:HTML是Web安全的基础,掌握HTML标签的正确使用和安全配置是识别和防御各类Web安全漏洞的前提。在实际应用中,应结合后端安全措施,共同构建安全的Web应用。

0%