JavaScript 高级教程:异步编程、面向对象与性能优化

在前两篇教程中,我们学习了 JavaScript 的基础和进阶内容。这篇文章将带领你进入更深层次,学习 JavaScript 的异步编程模型、面向对象编程(OOP),以及性能优化的技巧。这些内容对于构建复杂、流畅的前端应用至关重要。


一、异步编程

1. 异步编程模型简介

JavaScript 是单线程的,但它可以通过事件循环(Event Loop)机制实现异步操作。常见的异步方式包括:

  • 回调函数
  • Promise
  • async/await

2. Promise:优雅的异步解决方案

Promise 是异步操作的核心。它可以使代码从嵌套的回调地狱中解脱出来。

示例:

javascript 复制代码
const fetchData = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const success = true; // 模拟成功或失败
            if (success) {
                resolve("数据加载成功!");
            } else {
                reject("数据加载失败!");
            }
        }, 2000);
    });
};

fetchData()
    .then((data) => {
        console.log(data); // 输出:数据加载成功!
    })
    .catch((error) => {
        console.error(error); // 如果失败,输出:数据加载失败!
    });

要点:

  • resolve 表示成功,reject 表示失败。
  • then 用于处理成功,catch 用于捕获错误。

3. async/await:更直观的异步写法

async/await 是对 Promise 的语法糖,代码更简洁。

示例:

javascript 复制代码
const fetchData = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve("数据加载成功!"), 2000);
    });
};

const loadData = async () => {
    try {
        const data = await fetchData();
        console.log(data); // 输出:数据加载成功!
    } catch (error) {
        console.error(error); // 捕获错误
    }
};

loadData();

优点:

  • 更像同步代码,易读性高。
  • 用 try/catch 捕获错误。

4. 综合案例:加载用户数据

javascript 复制代码
const fetchUserData = async () => {
    try {
        const response = await fetch("https://jsonplaceholder.typicode.com/users");
        const users = await response.json(); // 转换为 JSON
        console.log(users); // 打印用户数据
    } catch (error) {
        console.error("数据加载失败:", error);
    }
};

fetchUserData();

二、面向对象编程(OOP)

1. JavaScript 中的类与对象

ES6 引入了 class 语法,使面向对象编程更简洁。

示例:

javascript 复制代码
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    introduce() {
        console.log(`我是 ${this.name},今年 ${this.age} 岁。`);
    }
}

const alice = new Person("Alice", 25);
alice.introduce(); // 输出:我是 Alice,今年 25 岁。

要点:

  • constructor 是构造函数,用于初始化对象属性。
  • 方法定义在 class 中,所有实例共享这些方法。

2. 继承

通过 extends 关键字实现类的继承。

示例:

javascript 复制代码
class Animal {
    constructor(name) {
        this.name = name;
    }

    speak() {
        console.log(`${this.name} 发出了声音!`);
    }
}

class Dog extends Animal {
    speak() {
        console.log(`${this.name} 说:汪汪!`);
    }
}

const dog = new Dog("小狗");
dog.speak(); // 输出:小狗 说:汪汪!

要点:

  • 子类可以重写父类的方法。
  • 子类中使用 super 调用父类方法或构造函数。

3. 封装与私有属性

通过私有属性隐藏内部实现细节,ES2021 引入了 # 作为私有属性的标志。

示例:

javascript 复制代码
class BankAccount {
    #balance = 0; // 私有属性

    deposit(amount) {
        this.#balance += amount;
        console.log(`存入:${amount},余额:${this.#balance}`);
    }

    withdraw(amount) {
        if (amount > this.#balance) {
            console.log("余额不足!");
        } else {
            this.#balance -= amount;
            console.log(`取出:${amount},余额:${this.#balance}`);
        }
    }
}

const account = new BankAccount();
account.deposit(100); // 输出:存入:100,余额:100
account.withdraw(50); // 输出:取出:50,余额:50
// console.log(account.#balance); // 报错:无法访问私有属性

三、性能优化

在开发大型应用时,性能优化非常重要。以下是几种常见的优化技巧。


1. 减少 DOM 操作

频繁的 DOM 操作会降低性能,建议批量更新 DOM 或使用虚拟 DOM。

示例:

javascript 复制代码
// 使用文档片段批量操作 DOM
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
    const div = document.createElement("div");
    div.textContent = `第 ${i + 1} 个元素`;
    fragment.appendChild(div);
}
document.body.appendChild(fragment);

2. 使用节流(throttle)和防抖(debounce)

节流 和防抖用于优化高频触发的事件(如滚动或输入)。

节流:限制触发频率

javascript 复制代码
const throttle = (func, delay) => {
    let last = 0;
    return (...args) => {
        const now = Date.now();
        if (now - last >= delay) {
            last = now;
            func(...args);
        }
    };
};

window.addEventListener("resize", throttle(() => {
    console.log("窗口大小变化!");
}, 500));

防抖:延迟执行

javascript 复制代码
const debounce = (func, delay) => {
    let timer;
    return (...args) => {
        clearTimeout(timer);
        timer = setTimeout(() => func(...args), delay);
    };
};

document.getElementById("search").addEventListener("input", debounce(() => {
    console.log("用户正在输入...");
}, 300));

3. 异步加载资源

通过异步加载外部资源(如脚本或图片)提升页面加载速度。

示例:

html 复制代码
<script src="large-script.js" async></script>
<script src="analytics.js" defer></script>
  • async:脚本异步加载并立即执行。
  • defer:脚本异步加载,但延迟到 DOM 完全解析后执行。

4. 使用 Web Workers

Web Workers 可将复杂计算移至后台线程,避免阻塞主线程。

示例:

javascript 复制代码
// worker.js
self.onmessage = (event) => {
    const result = event.data * 2;
    self.postMessage(result);
};

// 主线程
const worker = new Worker("worker.js");
worker.postMessage(5);
worker.onmessage = (event) => {
    console.log("计算结果:", event.data); // 输出:10
};

四、综合案例:简单搜索框

功能描述:

  • 用户输入内容时,动态搜索匹配结果。
  • 防止高频搜索请求。

HTML

html 复制代码
<input type="text" id="search" placeholder="搜索...">
<ul id="results"></ul>

JavaScript

javascript 复制代码
const results = document.getElementById("results");
const debounce = (func, delay) => {
    let timer;
    return (...args) => {
        clearTimeout(timer);
        timer = setTimeout(() => func(...args), delay);
    };
};

const search = async (query) => {
    const response = await fetch(`https://jsonplaceholder.typicode.com/users?name_like=${query}`);
    const users = await response.json();
    results.innerHTML = users.map(user => `<li>${user.name}</li>`).join("");
};

document.getElementById("search").addEventListener("input", debounce((event) => {
    const query = event.target.value.trim();
    if (query) {
        search(query);
    } else {
        results.innerHTML = "";
    }
}, 300));

五、总结与下一步

通过本文,你学习了:

  1. 异步编程的多种方式(回调、Promise、async/await)。
  2. 面向对象编程的核心概念(类、继承、封装)。
  3. 性

能优化的常见技巧(节流、防抖、Web Workers)。

下一步:

  • 学习如何使用 JavaScript 框架(如 React、Vue)构建复杂应用。
  • 探索服务端 JavaScript(Node.js)进行全栈开发。

掌握这些内容后,你将具备构建高效、健壮 Web 应用的能力!

相关推荐
懂点Tech25 分钟前
ctfshow MISC入门图片篇(信息附加):misc41解题思路
开发语言·python
catchadmin1 小时前
PHP 8.7 协程新提案 让跨协程代码共享请求身份
开发语言·php
念何架构之路2 小时前
go-grpc设计思想
开发语言·后端·golang
酷炫码神3 小时前
Day 10|Pinia 状态管理:把散落在各组件的数据,收进一个全局仓库
android·开发语言·javascript
Elastic 中国社区官方博客3 小时前
我们如何通过 70 多个拉取请求,将 OpenTelemetry Java agent 迁移到 invokedynamic
java·大数据·开发语言·elasticsearch·搜索引擎·全文检索·es
tyn1883 小时前
记录本地安装nacos服务的方法及异常
java·开发语言
步行cgn4 小时前
Spring MVC 视图机制的核心接口与类
java·开发语言·后端·spring·mvc
g3voip5 小时前
工业防水电话到底怎么选?隧道、管廊与码头的需求差异
服务器·网络·信息与通信·ip
传奇开心果编程5 小时前
【Rust入门练中学】第5课:引用与借用
开发语言·rust·引用·编程语言理论·通用编程语言·借用
qetfw5 小时前
Bash 变量:export、位置参数与默认值展开验证
linux·开发语言·chrome·bash