跳转至

JavaScript 教程

JavaScript 是一种动态、弱类型的编程语言,可以为网页添加交互性。本教程将带你学习 JavaScript 的核心概念和用法。

第一章:JavaScript 基础

(一)JavaScript 简介

什么是 JavaScript? JavaScript 是一种脚本语言,主要用于网页开发,可以为网页添加交互性和动态效果。

JavaScript 的特点: - 动态类型:变量无需声明类型 - 弱类型:自动类型转换 - 解释执行:由浏览器解释执行 - 事件驱动:响应用户操作 - 与 HTML 和 CSS 配合使用

(二)JavaScript 引入方式

内联 JavaScript:

<button onclick="alert('Hello!')">点击我</button>

内部 JavaScript:

<head>
    <script>
        function showMessage() {
            alert('Hello, World!');
        }
    </script>
</head>

外部 JavaScript:

<head>
    <script src="script.js"></script>
</head>

第二章:JavaScript 语法

(一)变量和数据类型

// 变量声明
var name = "张三";          // 旧方式
let age = 20;               // 推荐
const PI = 3.14159;         // 常量

// 数据类型
let num = 123;              // 数字
let str = "Hello";          // 字符串
let bool = true;            // 布尔值
let arr = [1, 2, 3];        // 数组
let obj = {name: "张三"};   // 对象
let nothing = null;         // 空值
let undefined;              // 未定义

(二)运算符

// 算术运算符
let a = 10, b = 3;
console.log(a + b);  // 13
console.log(a - b);  // 7
console.log(a * b);  // 30
console.log(a / b);  // 3.333...
console.log(a % b);  // 1

// 比较运算符
console.log(a == b);   // false
console.log(a === b);  // false
console.log(a != b);   // true
console.log(a !== b);  // true

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

(三)条件语句

// if-else 语句
let score = 85;

if (score >= 90) {
    console.log("优秀");
} else if (score >= 80) {
    console.log("良好");
} else if (score >= 60) {
    console.log("及格");
} else {
    console.log("不及格");
}

// switch 语句
let day = 3;
let dayName;

switch (day) {
    case 1:
        dayName = "星期一";
        break;
    case 2:
        dayName = "星期二";
        break;
    case 3:
        dayName = "星期三";
        break;
    default:
        dayName = "未知";
}

(四)循环语句

// for 循环
for (let i = 0; i < 5; i++) {
    console.log(i);
}

// while 循环
let i = 0;
while (i < 5) {
    console.log(i);
    i++;
}

// for...in 循环(遍历对象)
let person = {name: "张三", age: 20};
for (let key in person) {
    console.log(key + ": " + person[key]);
}

// for...of 循环(遍历数组)
let fruits = ["苹果", "香蕉", "橙子"];
for (let fruit of fruits) {
    console.log(fruit);
}

第三章:函数

(一)函数定义

// 函数声明
function add(a, b) {
    return a + b;
}

// 函数表达式
const subtract = function(a, b) {
    return a - b;
};

// 箭头函数
const multiply = (a, b) => a * b;

// 调用函数
console.log(add(3, 5));        // 8
console.log(subtract(10, 3));  // 7
console.log(multiply(4, 6));   // 24

(二)默认参数和剩余参数

// 默认参数
function greet(name = "朋友") {
    return `你好,${name}!`;
}

// 剩余参数
function sumAll(...numbers) {
    return numbers.reduce((sum, num) => sum + num, 0);
}

console.log(greet());              // 你好,朋友!
console.log(greet("张三"));        // 你好,张三!
console.log(sumAll(1, 2, 3, 4));  // 10

第四章:数组和对象

(一)数组操作

// 创建数组
let fruits = ["苹果", "香蕉", "橙子"];

// 添加元素
fruits.push("葡萄");        // 添加到末尾
fruits.unshift("草莓");     // 添加到开头

// 删除元素
fruits.pop();               // 删除末尾元素
fruits.shift();             // 删除开头元素

// 数组方法
fruits.forEach((fruit, index) => {
    console.log(`${index}: ${fruit}`);
});

let numbers = [3, 1, 4, 1, 5];
let doubled = numbers.map(num => num * 2);  // [6, 2, 8, 2, 10]
let evens = numbers.filter(num => num % 2 === 0);  // [4]
let sum = numbers.reduce((acc, num) => acc + num, 0);  // 14

(二)对象操作

// 创建对象
let person = {
    name: "张三",
    age: 20,
    city: "北京",
    greet: function() {
        return `你好,我是${this.name}`;
    }
};

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

// 修改属性
person.age = 21;
person.city = "上海";

// 添加属性
person.email = "zhangsan@example.com";

// 删除属性
delete person.city;

// 对象方法
console.log(person.greet());  // 你好,我是张三

// 对象解构
const {name, age} = person;
console.log(name, age);  // 张三 21

第五章:DOM 操作

(一)选择元素

// 通过 ID 选择
let element1 = document.getElementById("myId");

// 通过类名选择
let elements1 = document.getElementsByClassName("myClass");

// 通过标签名选择
let elements2 = document.getElementsByTagName("div");

// 通过选择器选择
let element2 = document.querySelector(".myClass");
let elements3 = document.querySelectorAll("div.myClass");

(二)修改元素

// 修改内容
element.textContent = "新的文本内容";
element.innerHTML = "<strong>新的 HTML 内容</strong>";

// 修改样式
element.style.color = "red";
element.style.fontSize = "18px";

// 修改属性
element.setAttribute("class", "newClass");
element.id = "newId";

// 添加和删除类
element.classList.add("highlight");
element.classList.remove("oldClass");
element.classList.toggle("active");

(三)事件处理

// 添加事件监听
element.addEventListener("click", function() {
    console.log("元素被点击了");
});

// 移除事件监听
function handleClick() {
    console.log("处理点击事件");
}
element.addEventListener("click", handleClick);
element.removeEventListener("click", handleClick);

// 常用事件
element.addEventListener("mouseover", function() {
    // 鼠标悬停
});

element.addEventListener("mouseout", function() {
    // 鼠标离开
});

element.addEventListener("keydown", function(event) {
    // 键盘按下
    console.log(event.key);
});

第六章:ES6+ 新特性

(一)解构赋值

// 数组解构
let [a, b, c] = [1, 2, 3];
console.log(a, b, c);  // 1 2 3

// 跳过元素
let [x, , z] = [1, 2, 3];
console.log(x, z);  // 1 3

// 默认值
let [m = 10, n = 20] = [5];
console.log(m, n);  // 5 20

// 剩余元素
let [first, ...rest] = [1, 2, 3, 4, 5];
console.log(first);  // 1
console.log(rest);   // [2, 3, 4, 5]

// 对象解构
let {name, age, city = "未知"} = {name: "张三", age: 20};
console.log(name, age, city);  // 张三 20 未知

// 重命名
let {name: userName, age: userAge} = {name: "李四", age: 25};
console.log(userName, userAge);  // 李四 25

// 嵌套解构
let {address: {province, city: addr}} = {
    address: {province: "北京", city: "朝阳区"}
};
console.log(province, addr);  // 北京 朝阳区

(二)模板字符串

// 基本用法
let name = "张三";
let greeting = `你好,${name}!`;
console.log(greeting);  // 你好,张三!

// 多行字符串
let html = `
<div class="card">
    <h2>${name}</h2>
    <p>这是内容</p>
</div>
`;

// 表达式
let price = 99;
let result = `总价:${price > 50 ? '打折' : '原价'} ${price}元`;
console.log(result);  // 总价:打折 99元

// 标签模板
function highlight(strings, ...values) {
    return strings.reduce((result, str, i) => {
        return result + str + (values[i] ? `<mark>${values[i]}</mark>` : '');
    }, '');
}

let name2 = "JavaScript";
let output = highlight`学习${name2}很有意思`;
console.log(output);  // 学习<mark>JavaScript</mark>很有意思

(三)展开运算符和剩余参数

// 数组展开
let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
let merged = [...arr1, ...arr2];
console.log(merged);  // [1, 2, 3, 4, 5, 6]

// 对象展开
let obj1 = {a: 1, b: 2};
let obj2 = {b: 3, c: 4};
let mergedObj = {...obj1, ...obj2};
console.log(mergedObj);  // {a: 1, b: 3, c: 4}

// 浅拷贝
let copy = {...obj1};

// 剩余参数
function sum(...nums) {
    return nums.reduce((total, n) => total + n, 0);
}
console.log(sum(1, 2, 3, 4, 5));  // 15

// 解构中的剩余
let [head, ...tail] = [1, 2, 3, 4];
console.log(head);  // 1
console.log(tail);  // [2, 3, 4]

(四)Promise 和异步编程

// Promise 基础
function fetchData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const data = {name: "张三", age: 20};
            resolve(data);
            // reject(new Error("请求失败"));
        }, 1000);
    });
}

// 使用 Promise
fetchData()
    .then(data => console.log(data))
    .catch(error => console.error(error))
    .finally(() => console.log("完成"));

// Promise 链
function getUser() {
    return Promise.resolve({id: 1, name: "张三"});
}

function getPosts(userId) {
    return Promise.resolve([
        {id: 1, title: "文章1"},
        {id: 2, title: "文章2"}
    ]);
}

getUser()
    .then(user => getPosts(user.id))
    .then(posts => console.log(posts));

// Promise.all - 并行执行
let promise1 = Promise.resolve(1);
let promise2 = Promise.resolve(2);
let promise3 = Promise.resolve(3);

Promise.all([promise1, promise2, promise3])
    .then(results => console.log(results));  // [1, 2, 3]

// Promise.race - 竞争执行
Promise.race([promise1, promise2, promise3])
    .then(result => console.log(result));  // 1

// Promise.allSettled - 等待所有完成
Promise.allSettled([promise1, promise2, promise3])
    .then(results => console.log(results));

(五)async/await

// async 函数
async function getUserData() {
    try {
        let response = await fetch('https://api.example.com/user');
        let data = await response.json();
        return data;
    } catch (error) {
        console.error('请求失败:', error);
    }
}

// 并行执行多个 async
async function loadAllData() {
    const [users, posts] = await Promise.all([
        fetch('/api/users').then(r => r.json()),
        fetch('/api/posts').then(r => r.json())
    ]);
    return {users, posts};
}

// 循环中的 async
async function processItems(items) {
    for (let item of items) {
        await processItem(item);
    }
}

// 常见错误
// 错误1:在循环中使用 await(会串行执行)
async function wrong() {
    for (let i = 0; i < 5; i++) {
        await delay(1000);  // 会等待5秒
    }
}

// 正确:使用 Promise.all
async function correct() {
    await Promise.all(
        Array(5).fill().map(() => delay(1000))
    );  // 只等1秒
}

(六)Map 和 Set

// Map
let map = new Map();
map.set('name', '张三');
map.set('age', 20);
map.set(1, '数字键');

console.log(map.get('name'));  // 张三
console.log(map.size);         // 3
console.log(map.has('age'));    // true

// Map 迭代
for (let [key, value] of map) {
    console.log(`${key}: ${value}`);
}

// Map 与对象转换
let obj = {a: 1, b: 2};
let mapFromObj = new Map(Object.entries(obj));
let objFromMap = Object.fromEntries(map);

// Set
let set = new Set([1, 2, 3, 3, 4, 4, 5]);
console.log(set);  // Set {1, 2, 3, 4, 5}
console.log(set.size);  // 5

// Set 方法
set.add(6);
set.delete(1);
set.has(3);  // true

// Set 去重
let arr = [1, 2, 2, 3, 3, 4];
let unique = [...new Set(arr)];  // [1, 2, 3, 4]

// Set 迭代
for (let item of set) {
    console.log(item);
}

// Set 操作
let setA = new Set([1, 2, 3]);
let setB = new Set([3, 4, 5]);

// 并集
let union = new Set([...setA, ...setB]);

// 交集
let intersection = new Set([...setA].filter(x => setB.has(x)));

// 差集
let difference = new Set([...setA].filter(x => !setB.has(x)));

(七)类

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    greet() {
        return `你好,我是${this.name},今年${this.age}岁`;
    }

    // 静态方法
    static create(name, age) {
        return new Person(name, age);
    }

    // getter
    get info() {
        return `${this.name} (${this.age})`;
    }

    // setter
    set name(value) {
        this._name = value.toUpperCase();
    }
}

// 继承
class Student extends Person {
    constructor(name, age, grade) {
        super(name, age);
        this.grade = grade;
    }

    study() {
        return `${this.name}正在学习`;
    }

    greet() {
        return `${super.greet()},我是${this.grade}学生`;
    }
}

let student = new Student("张三", 20, "大二");
console.log(student.greet());  // 你好,我是张三,今年20岁,我是大二学生
console.log(student.study());  // 张三正在学习

(八)模块化

// math.js - 导出
export const PI = 3.14159;

export function add(a, b) {
    return a + b;
}

export default class Calculator {
    add(a, b) { return a + b; }
    subtract(a, b) { return a - b; }
}

// app.js - 导入
import Calculator, {PI, add} from './math.js';

const calc = new Calculator();
console.log(calc.add(1, 2));  // 3
console.log(PI);              // 3.14159
console.log(add(3, 4));       // 7

// 动态导入
async function loadModule() {
    const module = await import('./math.js');
    console.log(module.add(1, 2));
}

(九)可选链和空值合并

// 可选链 ?. 访问嵌套属性
let user = {
    name: "张三",
    address: {
        city: "北京"
    }
};

console.log(user?.address?.city);      // 北京
console.log(user?.phone?.number);      // undefined
console.log(user?.address?.zipCode);   // undefined

// 可选链调用方法
user.greet?.();  // 如果greet存在就调用

// 空值合并 ??
let value1 = null ?? "默认值";    // "默认值"
let value2 = undefined ?? "默认值"; // "默认值"
let value3 = 0 ?? "默认值";       // 0
let value4 = "" ?? "默认值";      // ""

// 与 || 的区别
let v1 = 0 || "默认值";   // "默认值"
let v2 = 0 ?? "默认值";   // 0

// 组合使用
let config = {
    host: "localhost",
    port: null
};

let host = config.host ?? "127.0.0.1";  // "localhost"
let port = config.port ?? 3000;          // 3000

(十)Array 方法扩展

let numbers = [1, 2, 3, 4, 5];

// Array.from
let arr = Array.from({length: 5}, (_, i) => i + 1);  // [1, 2, 3, 4, 5]

// Array.of
let arr2 = Array.of(1, 2, 3);  // [1, 2, 3]

// find 和 findIndex
let found = numbers.find(n => n > 3);      // 4
let index = numbers.findIndex(n => n > 3);  // 3

// includes
numbers.includes(3);  // true

// flat 和 flatMap
let nested = [1, [2, 3], [4, [5, 6]]];
nested.flat();     // [1, 2, 3, 4, [5, 6]]
nested.flat(2);    // [1, 2, 3, 4, 5, 6]
nested.flat(Infinity);  // [1, 2, 3, 4, 5, 6]

let sentences = ["hello world", "foo bar"];
sentences.flatMap(s => s.split(' '));  // ["hello", "world", "foo", "bar"]

// at 方法
let arr3 = ['a', 'b', 'c', 'd'];
arr3.at(0);    // 'a'
arr3.at(-1);   // 'd' (支持负索引)

// entries, keys, values
for (let [index, value] of numbers.entries()) {
    console.log(`${index}: ${value}`);
}

第七章:练习题目

基础练习

  1. 变量和数据类型
  2. 创建不同类型的变量
  3. 进行类型转换

  4. 条件语句

  5. 判断数字的正负
  6. 判断成绩等级

  7. 循环语句

  8. 计算 1 到 100 的和
  9. 打印九九乘法表

进阶练习

  1. 函数
  2. 定义函数计算阶乘
  3. 定义函数判断质数

  4. 数组操作

  5. 找出数组中的最大值
  6. 筛选数组中的偶数

  7. 对象操作

  8. 创建对象表示学生信息
  9. 遍历对象属性

综合练习

  1. DOM 操作
  2. 创建动态导航栏
  3. 创建待办事项应用

  4. 事件处理

  5. 创建简单的计算器
  6. 创建猜数字游戏

  7. 综合应用

  8. 创建完整的个人网站
  9. 创建产品展示网站

恭喜你完成了 JavaScript 教程的学习!现在你已经掌握了 HTML、CSS 和 JavaScript,可以开始创建动态网页了!