目录
我们已经用 HTML 搭建了网页的"骨架",用 CSS 给它化了"妆容",现在,是时候让它真正"活"起来了!JavaScript 就是负责这项任务的魔法师。
如果说 HTML 是房子的结构,CSS 是装修,那么 JavaScript 就像是给房子通上了电,安装了各种智能家居系统。它能让灯(页面元素)根据开关(用户点击)亮灭,能让电视(数据显示区域)播放不同的节目(从服务器获取数据),能让门禁(表单)验证访客身份。总之,JavaScript 负责处理网页的交互逻辑和动态行为。
1. JavaScript 基础语法:电线、开关和仪表盘
JavaScript 是一种脚本语言,主要运行在用户的浏览器(客户端)中,用来实现网页的动态交互。
引入 JS:
- 内联:
<script> alert('Hello!'); </script>
(不推荐,除非极简短) - 外部:
<script src="myscript.js"></script>
(推荐!放在<body>
结束前)。这就像把复杂的电路图纸单独存放。
注释: 解释代码用途,方便自己和他人阅读。
变量: 存储数据的容器,就像电路中的各种开关、传感器、存储器。
var
: (旧版) 有函数作用域和变量提升问题,尽量避免使用。let
: 声明块级作用域的变量,值可以被修改。推荐用于需要重新赋值的变量。const
: 声明块级作用域的常量,值在声明后不能被重新赋值(但如果值是对象或数组,其内部内容可修改)。推荐优先使用 const,除非明确需要重新赋值。
数据类型: JavaScript 能处理不同类型的数据,就像电器有不同的规格。
- 基本类型: 存储简单值。String (文本), Number (数字), Boolean (真/假), Null (空值), Undefined (未定义), Symbol (唯一标识符), BigInt (大整数)。
- 引用类型: Object (对象,包含数组、函数等复杂结构)。
console.log(): 开发者的"仪表盘",可以在浏览器开发者工具的 Console 面板输出信息,是调试代码的最基本、最重要的工具。
1.1 小例子:声明不同类型的变量并在控制台输出
创建01.js
// 01.js
// 使用 let 声明可变变量
let message = "你好,JavaScript!"; // String 类型
let currentYear = 2025; // Number 类型
let isLearning = true; // Boolean 类型
// 使用 const 声明常量
const PI = 3.14159; // Number 类型常量
const SITE_NAME = "我的学习网站"; // String 类型常量
// 特殊类型
let user = null; // Null 类型
let undefinedVar; // Undefined 类型
// 在控制台输出变量值
console.log(message);
console.log("当前年份:", currentYear); // 可以输出多个值
console.log("正在学习中?", isLearning);
console.log("圆周率:", PI);
console.log("网站名称:", SITE_NAME);
console.log("用户信息:", user);
console.log("未定义变量:", undefinedVar);
// 修改 let 声明的变量
message = "JavaScript 基础入门";
console.log("更新后的消息:", message);
// 尝试修改 const 声明的常量会报错 (取消注释会看到错误)
// PI = 3.14;
创建01.html
<!DOCTYPE html>
<html>
<head> <title>JS 基础</title> </head>
<body>
<h1>查看浏览器控制台</h1>
<script src="myscript.js"></script>
</body>
</html>
为了看到输出,我们可以在trae的对话窗口输入预览这个文件
他会自动识别到意图,选择合适的命令,现在点击一下预览
我们的内容页面需要一定的样式,你可以把新写的这个html和一个已经开发好的拖入右侧窗口,告诉trae让他仿写一下
代码改写后点击全部接受,然后再点击预览
然后回到我们的主文件,增加我们的内容页的链接,后续就可以按tab键,trae就会自动识别意图做改写
改好主文件后,打开我们的第一节内容
点击浏览器的三个点,选择开发者工具
可以看到控制台输出了具体的内容
1.2 练习
- 编写代码,交换两个变量的值(例如 let a = 5; let b = 10; 交换后 a 为 10,b 为 5)。
- 声明变量分别存储你的姓名(String)、年龄(Number)、是否已工作(Boolean),并在控制台输出。
2 运算符与表达式:连接电路与计算逻辑
运算符就像电路中的连接器和逻辑门,用于对数据(变量)进行计算、比较和组合。表达式是由变量、常量和运算符组成的式子,会产生一个结果。
- 算术: 进行数学计算。+ 也可用于字符串拼接。
- 赋值: 给变量赋值。+= 等是简写形式 (如 x += 5 等价于 x = x + 5)。
- 比较: 比较两个值,返回 true 或 false。强烈推荐使用 === 和 !== (全等/不全等),它们不仅比较值,还比较数据类型,可以避免一些隐式类型转换带来的坑。== 只比较值,会进行类型转换 (如 5 == ‘5’ 为 true,但 5 === ‘5’ 为 false)。
- 逻辑: 组合布尔值。&& (都为真才为真), || (有一个为真就为真), ! (取反)。
- 三元: if…else 的简洁写法,适用于简单的条件赋值。
2.1 小例子:计算圆的面积,判断数字是否为偶数
// 计算圆面积
const radius = 5;
const area = Math.PI * radius ** 2; // Math.PI 是内置的圆周率,** 是幂运算符
console.log(`半径为 ${radius} 的圆面积是: ${area}`); // 使用模板字符串
// 判断偶数
let numberToCheck = 10;
let isEven = numberToCheck % 2 === 0; // 取模运算,余数为 0 则是偶数
console.log(`${numberToCheck} 是偶数吗? ${isEven}`);
numberToCheck = 7;
isEven = numberToCheck % 2 === 0;
console.log(`${numberToCheck} 是偶数吗? ${isEven}`);
// 比较运算符示例
console.log("5 == '5'?", 5 == '5'); // true (值相等,类型不同但会转换)
console.log("5 === '5'?", 5 === '5'); // false (类型不同)
console.log("5 !== '5'?", 5 !== '5'); // true
// 逻辑运算符示例
let age = 25;
let hasLicense = true;
let canDrive = age >= 18 && hasLicense; // 年龄大于等于18 且 有驾照
console.log("可以开车吗?", canDrive);
// 三元运算符示例
let score = 75;
let result = score >= 60 ? "及格" : "不及格";
console.log(`分数 ${score}, 结果: ${result}`);
运行后的效果
2.2 练习
编写一个简单的身体质量指数 (BMI) 计算器逻辑。需要两个变量:身高(米)和体重(公斤),计算公式为 BMI = 体重 / (身高 * 身高),并将结果输出到控制台。
3 流程控制语句:设定程序的运行路径
流程控制就像设定智能家居的自动化规则:“如果 (if) 温度低于 20 度,就打开暖气,否则 (else) 关闭”;“重复执行 (for/while) 打扫任务,直到电量耗尽”。
条件语句: 根据不同的条件执行不同的代码块。if 用于单一条件,if…else 用于两种情况,if…else if…else 用于多种条件判断。switch 适用于基于一个表达式的多个固定值进行判断。
循环语句: 重复执行代码块。
- for: 最常用,适用于已知循环次数或有明确计数器的情况。
- while: 先判断条件,条件为真则执行循环体,适用于循环次数不确定的情况。
- do…while: 先执行一次循环体,再判断条件,至少执行一次。
- for…in: 遍历对象的可枚举属性名 (key)。
- for…of: 遍历可迭代对象 (如 Array, String, Map, Set) 的值 (value)。推荐用于遍历数组。
3.1 判断成绩等级,打印九九乘法表
// 判断成绩等级
let grade = 85;
if (grade >= 90) {
console.log("优秀");
} else if (grade >= 80) {
console.log("良好");
} else if (grade >= 60) {
console.log("及格");
} else {
console.log("不及格");
}
// switch 示例 (判断星期几)
let day = new Date().getDay(); // 获取当前星期几 (0=周日, 1=周一, ...)
let dayName;
switch (day) {
case 0: dayName = "星期日"; break;
case 1: dayName = "星期一"; break;
case 2: dayName = "星期二"; break;
// ... 其他 case
case 6: dayName = "星期六"; break;
default: dayName = "未知";
}
console.log(`今天是: ${dayName}`);
// 打印九九乘法表 (for 循环嵌套)
console.log("九九乘法表:");
for (let i = 1; i <= 9; i++) {
let row = '';
for (let j = 1; j <= i; j++) {
row += `${j} * ${i} = ${i * j}\t`; // \t 是制表符,用于对齐
}
console.log(row);
}
// for...of 遍历数组
const colors = ['red', 'green', 'blue'];
console.log("遍历颜色数组:");
for (const color of colors) {
console.log(color);
}
运行后的效果
3.2 练习
编写代码,找出 1 到 100 之间所有的质数(只能被 1 和自身整除的大于 1 的整数)并输出到控制台。
4 函数:封装指令的工具箱
函数就像工具箱里的特定工具(如"计算面积工具"、“发送问候工具”)。它将一系列操作打包封装起来,给它一个名字,需要时就可以通过名字调用它,可以传递参数(原材料)给它,它也可以返回结果(成品)。这让代码更有条理、可维护、可复用。
- 声明 vs 表达式: 声明的函数会被提升(可以在声明前调用),表达式定义的函数则不行。
- 箭头函数: ES6 引入的更简洁的函数语法,尤其适用于回调函数和匿名函数。它没有自己的 this 绑定(会继承外部作用域的 this)。
- 参数: 函数接收的输入值。
- 返回值: 函数执行后输出的结果,使用 return 关键字。如果函数没有 return,默认返回 undefined。
- 作用域: 变量可访问的范围。全局变量处处可访问,函数内变量只能在函数内访问,let/const 声明的变量还有块级作用域(如 if 或 for 的 {} 内)。
- 闭包: 一个强大的概念,允许函数"记住"它创建时的环境。简单理解:内部函数可以访问外部函数的变量,即使外部函数已经执行完毕。
4.1 小例子:创建计算两数之和的函数,创建问候用户的函数
// 函数声明
function add(num1, num2) {
return num1 + num2;
}
// 函数表达式
const greet = function(name) {
console.log(`你好, ${name}!`);
};
// 箭头函数
const multiply = (a, b) => {
return a * b;
};
// 如果箭头函数体只有一行且是返回值,可以省略 {} 和 return
const subtract = (a, b) => a - b;
// 调用函数
let sum = add(5, 3);
console.log("5 + 3 =", sum);
greet("张三");
let product = multiply(4, 6);
console.log("4 * 6 =", product);
let difference = subtract(10, 4);
console.log("10 - 4 =", difference);
// 作用域示例
let globalVar = "我是全局变量";
function scopeTest() {
let functionVar = "我是函数内变量";
console.log(globalVar); // 可以访问全局变量
if (true) {
let blockVar = "我是块级变量";
console.log(functionVar); // 可以访问函数变量
}
// console.log(blockVar); // 在这里访问块级变量会报错
}
scopeTest();
// console.log(functionVar); // 在这里访问函数变量会报错
运行后的效果
4.2 练习
编写一个名为 isLeapYear 的函数,接收一个年份作为参数,判断该年份是否为闰年(能被 4 整除但不能被 100 整除,或者能被 400 整除),返回 true 或 false。
5 数组 (Array):有序数据的货架
数组就像一个有序的货架,可以按顺序存放多个数据(可以是不同类型)。每个位置都有一个编号(索引,从 0 开始),可以方便地存取、添加、删除和遍历这些数据。JavaScript 提供了极其丰富的数组方法来高效地操作数据。
访问: myArray[0] 访问第一个元素。
修改: myArray[1] = ‘new value’;
常用方法:
- 增删: push/pop (末尾), unshift/shift (开头), splice (任意位置)。
- 截取/合并: slice, concat。
- 查找: indexOf, includes, find, findIndex。
- 遍历方法 (非常重要): 这些方法通常接收一个回调函数作为参数,对数组每个元素执行该函数。
- forEach(): 纯粹遍历,不返回值。
- map(): 对每个元素执行操作,返回一个新的、包含结果的数组。
- filter(): 根据条件筛选元素,返回一个新的、包含符合条件元素的数组。
- reduce(): 将数组元素累加或聚合为一个单一的值。
5.1 小例子:管理一个待办事项列表(增删改查)
let todos = ["学习 HTML", "学习 CSS"];
// 添加
todos.push("学习 JavaScript");
todos.unshift("准备开发环境"); // 开头添加
console.log("添加后:", todos);
// 删除
let removedLast = todos.pop(); // 删除最后一个
console.log("删除了:", removedLast);
let removedFirst = todos.shift(); // 删除第一个
console.log("删除了:", removedFirst);
console.log("删除后:", todos);
// 修改 (使用 splice)
// splice(起始索引, 删除数量, 要插入的元素1, 元素2, ...)
todos.splice(1, 1, "深入学习 CSS"); // 替换索引 1 的元素
console.log("修改后:", todos);
// 查找
let jsIndex = todos.indexOf("学习 JavaScript");
console.log("JavaScript 的索引:", jsIndex);
console.log("是否包含 '学习 HTML'?", todos.includes("学习 HTML"));
// 遍历 (forEach)
console.log("待办事项:");
todos.forEach(function(todo, index) {
console.log(`${index + 1}. ${todo}`);
});
// 映射 (map) - 创建一个包含任务长度的新数组
let todoLengths = todos.map(todo => todo.length);
console.log("任务长度:", todoLengths);
// 过滤 (filter) - 筛选包含 "学习" 的任务
let learningTasks = todos.filter(todo => todo.includes("学习"));
console.log("学习任务:", learningTasks);
运行后的效果
5.2 练习
- 给定一个数字数组,例如 [1, 5, 2, 5, 3, 1, 5],编写代码统计每个数字出现的次数。
- 给定一个数字数组,使用 filter 方法筛选出所有的偶数,并返回一个新的数组。
6 对象 (Object):描述事物的属性集合
对象是 JavaScript 中表示复杂事物的方式,它是一组无序的键值对 (key-value pairs) 的集合。键 (key) 是字符串(属性名),值 (value) 可以是任何数据类型(包括其他对象或函数)。就像描述一个"智能灯泡"对象,它有属性(键):color (颜色), brightness (亮度), isOn (是否开启),还有方法(作为值的函数):turnOn() (打开), changeColor() (改变颜色)。
- 创建: 字面量 {} 是最常用的方式。
- 访问: 点号 . 用于已知且合法的标识符属性名;方括号 [] 更灵活,可以用于包含特殊字符或变量值的属性名 (myObject[‘property-with-hyphen’] 或 let propName = ‘color’; myObject[propName])。
- 方法: 对象中的函数被称为方法。
- this: 在对象方法中,this 通常指向调用这个方法的那个对象实例。this 的指向比较复杂,后续会深入,目前先理解这个基本情况。
- 遍历: for…in 遍历键名。Object.keys/values/entries 提供更现代的遍历方式。
6.1 小例子:创建一个表示"用户"的对象
// 使用字面量创建对象
const user = {
firstName: "张",
lastName: "三",
age: 30,
email: "zhangsan@example.com",
address: { // 值可以是另一个对象
street: "人民路 123号",
city: "上海"
},
hobbies: ["编码", "阅读", "游戏"], // 值可以是数组
// 方法
getFullName: function() {
// 在方法中,this 指向 user 对象
return this.firstName + this.lastName;
},
// ES6 方法简写
greet() {
console.log(`你好,我是 ${this.getFullName()}!`);
}
};
// 访问属性
console.log("姓:", user.lastName);
console.log("城市:", user.address.city);
console.log("第一个爱好:", user.hobbies[0]);
console.log("邮箱(方括号访问):", user['email']);
// 调用方法
console.log("全名:", user.getFullName());
user.greet();
// 添加新属性
user.isAdmin = false;
console.log("是管理员吗?", user.isAdmin);
// 遍历对象属性 (for...in)
console.log("遍历用户信息:");
for (const key in user) {
// 检查属性是否是对象自身的,而不是继承来的 (可选但推荐)
if (Object.hasOwnProperty.call(user, key)) {
console.log(`${key}: ${user[key]}`); // 注意这里用方括号访问
}
}
// 使用 Object.keys/values/entries
console.log("所有键:", Object.keys(user));
console.log("所有值:", Object.values(user));
// console.log("所有键值对:", Object.entries(user));
运行后的效果
6.2 练习
- 创建一个表示"书籍"的对象,包含属性 title (书名), author (作者), pages (页数), isRead (是否已读 - Boolean)。
- 为该书籍对象添加一个 displayInfo 方法,调用时在控制台打印出书籍的标题和作者。
7 配置MCP
代码写好之后,我们需要发布到github上,我们来配置一个MCP来执行这个操作。切换到Builer with MCP
添加一下github
他要求一个token,我们按照要求生成一下
把token贴入trae里,github就变成了一个可用的状态
然后在聊天窗口输入发布命令他就会自动检查配置并发布
我感觉没啥用处,在终端直接打一个命令,用这个还得浪费token
代码地址
https://github.com/wedalowcode/my-first-web-project.git