深入javascript计划八:深入浅出模块化

实现学生配对计划的JavaScript配对编程实践 在当今IT领域,技术的迅速进步和团队合作的重要性日益凸显,配对编程作为一种协同开发实践,已经在软件开发领域得到广泛应用。配对编程(Pair Programming)是一种由两名开发人员共同使用一台工作站的开发实践,其中一位负责编码,另一位负责审查代码。通过这种方式,可以充分利用两个人的技能和经验,以期提高代码质量、提高效率、分享知识和技能,并有助于打破信息孤岛。尽管这种实践在团队中可能会带来初始的协调和适应成本,但长期来看,它可以显著提升项目的开发速度和软件质量。 阅读详情

传统加载

HTML 网页中,浏览器通过<script>标签加载 JavaScript 脚本。

页面内嵌脚本:

<script type="application/javascript">
  // module code
</script>

由于浏览器脚本的默认语言是 JavaScript,因此type="application/javascript"可以省略。

外部脚本:

<script type="application/javascript" src="path/to/myModule.js"></script>

 异步脚本:

<script src="path/to/myModule.js" defer></script>
<script src="path/to/myModule.js" async></script>

defer与async有什么区别?

defer:要等到整个页面在内存中正常渲染结束(DOM 结构完全生成,以及其他脚本执行完成),才会执行(通俗来讲就是:(顺序加载,渲染完再执行)。

多个defer:会按照它们在页面出现的顺序加载。

async:一旦下载完,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染(通俗来讲就是:乱序加载,下载完就执行)。

多个async:脚本是不能保证加载顺序的。

浏览器是如何加载js脚本的?

默认情况下:浏览器是同步加载 JavaScript 脚本,即渲染引擎遇到<script>标签就会停下来,等到执行完脚本,再继续向下渲染(如果是外部脚本,还必须加入脚本下载的时间)。

所以我们经常把<script>标签放在后面。

如果脚本体积很大,下载和执行的时间就会很长,因此造成浏览器堵塞,用户会感觉到浏览器“卡死”了,没有任何响应。

这显然是很不好的体验,所以浏览器允许脚本异步加载,下面就是两种异步加载的语法:

<script src="path/to/myModule.js" defer></script>
<script src="path/to/myModule.js" async></script>

上面代码中,<script>标签打开defer或async属性,脚本就会异步加载。渲染引擎遇到这一行命令,就会开始下载外部脚本,但不会等它下载和执行,而是直接执行后面的命令。

模块化加载

为什么要使用模块化?

  • 解决命名冲突
  • 提供复用性
  • 提高代码可维护性

外部脚本:

type属性设为module,所以浏览器知道这是一个 ES6 模块。

<script type="module" src="./foo.js"></script>
<!-- 等同于 -->
<script type="module" src="./foo.js" defer></script>

如果网页有多个<script type="module">,它们会按照在页面出现的顺序依次执行。 

也可以设置成async,这时只要加载完成,渲染引擎就会中断渲染立即执行。执行完成后,再恢复渲染。

<script type="module" src="./foo.js" async></script>

页面内嵌脚本:

<script type="module">
  import utils from "./utils.js";

  // other code
</script>

注意点:

  1. 代码是在模块作用域之中运行,而不是在全局作用域运行。模块内部的顶层变量,外部不可见。
  2. 模块脚本自动采用严格模式,不管有没有声明use strict。
  3. 模块之中,可以使用import命令加载其他模块(.js后缀不可省略,需要提供绝对 URL 或相对 URL),也可以使用export命令输出对外接口。
  4. 模块之中,顶层的this关键字返回undefined,而不是指向window。也就是说,在模块顶层使用this关键字,是无意义的。
  5. 同一个模块如果加载多次,将只执行一次。

AMD 和 CMD

鉴于目前这两种实现方式已经很少见到,所以不再对具体特性细聊,只需要了解这两者是如何使用的。

AMD:

define(['./a', './b'], function(a, b) {
  // 加载模块完毕可以使用
  a.do()
  b.do()
})

CMD:

define(function(require, exports, module) {
  // 加载模块
  // 可以把 require 写在函数体的任意地方实现延迟加载
  var a = require('./a')
  a.doSomething()
})

CommonJS

CommonJS 最早是 Node 在使用,目前也仍然广泛使用,比如在 Webpack 中你就能见到它,当然目前在 Node 中的模块管理已经和 CommonJS 有一些区别了。

模块导出:

关键字:module.exports、exports

// foo.js

// 一个一个 导出
module.exports.age = 1
module.exports.foo = function() {}
exports.a = 'hello'

// 整体导出
module.exports = { 
    age: 1, 
    a: 'hello', 
    foo:function(){} 
}

// 整体导出不能用`exports` 用exports不能在导入的时候使用
exports = { 
    age: 1, 
    a: 'hello', 
    foo:function() {} 
}
// 这里需要注意 exports 不能被赋值,可以理解为在模块开始前exports = module.exports, 因为赋值之后exports失去了 对module.exports的引用,成为了一个模块内的局部变量。

模块导入:

关键字:require

const foo = require('./foo.js')
console.log(foo.age) //1

ES6 Module

由于 ES6 模块是编译时加载,使得静态分析成为可能。有了它,就能进一步拓宽 JavaScript 的语法,比如引入宏(macro)和类型检验(type system)这些只能靠静态分析实现的功能。

模块导出:

一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。

关键字:export

// a.js

// 声明命名导出
export var name= 'an';
export var year = 1998;

// 函数导出
export function multiply(x, y) {
  return x * y;
};

// 命名导出
var name= 'an';
var year = 1958;
export { name, year };

// 重命名导出
export { name as names, year as years };

需要特别注意的是,export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。

// 报错
export 1;

// 报错
var m = 1;
export m;

// 分割线

// 写法一
export var m = 1;

// 写法二
var m = 1;
export {m};

// 写法三
var n = 1;
export {n as m};

// 分割线

// 报错
function f() {}
export f;

// 正确
export function f() {};

// 正确
function f() {}
export {f};

另外,export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。

export var foo = 'bar';
setTimeout(() => foo = 'baz', 500);

这一点与 CommonJS 规范完全不同。CommonJS 模块输出的是值的缓存,不存在动态更新。

注意点:

export命令可以出现在模块的任何位置,只要处于模块顶层就可以。如果处于块级作用域内,就会报错,import命令也是如此。这是因为处于条件代码块之中,就没法做静态优化了,违背了 ES6 模块的设计初衷。

模块导入:

关键字:import

// main.js
import { name, year } from './a.js';

// 重命名
import { name as n, year as y } from './a.js';

import命令输入的变量都是只读的,因为它的本质是输入接口。也就是说,不允许在加载模块的脚本里面,改写接口。

import {a} from './xxx.js'

a = {}; // Syntax Error : 'a' is read-only;

上面代码中,脚本加载了变量a,对其重新赋值就会报错,因为a是一个只读的接口。但是,如果a是一个对象,改写a的属性是允许的。

import {a} from './xxx.js'

a.foo = 'hello'; // 合法操作

import后面的from指定模块文件的位置,可以是相对路径,也可以是绝对路径,.js后缀可以省略。

注意,import命令具有提升效果,会提升到整个模块的头部,首先执行。

foo();

import { foo } from 'my_module';

上面的代码不会报错,因为import的执行早于foo的调用。这种行为的本质是,import命令是编译阶段执行的,在代码运行之前。

由于import是静态执行,所以不能使用表达式和变量,这些只有在运行时才能得到结果的语法结构。

// 报错
import { 'f' + 'oo' } from 'my_module';

// 报错
let module = 'my_module';
import { foo } from module;

// 报错
if (x === 1) {
  import { foo } from 'module1';
} else {
  import { foo } from 'module2';
}

上面三种写法都会报错,因为它们用到了表达式、变量和if结构。在静态分析阶段,这些语法都是没法得到值的。

最后,import语句会执行所加载的模块,因此可以有下面的写法。

import 'xxx.js';

如果多次重复执行同一句import语句,那么只会执行一次,而不会执行多次。

import 'xxx.js';
import 'xxx.js';

整体加载

导出:

// a.js
export function area(radius) {
  return Math.PI * radius * radius;
}
export function circumference(radius) {
  return 2 * Math.PI * radius;
}

导入:

import * as circle from './a.js';

console.log('圆面积:' + circle.area(4));
console.log('圆周长:' + circle.circumference(14));

ES Module与CommonJS区别

  1. CommonJS 支持动态导入,也就是 require(${path}/xx.js),后者目前不支持,但是已有提案
  2. CommonJS 是同步导入,因为用于服务端,文件都在本地,同步导入即使卡住主线程影响也不大。而后者是异步导入,因为用于浏览器,需要下载文件,如果也采用同步导入会对渲染有很大影响
  3. CommonJS 在导出时都是值拷贝,就算导出的值变了,导入的值也不会改变,所以如果想更新值,必须重新导入一次。但是 ES Module 采用实时绑定的方式,导入导出的值都指向同一个内存地址,所以导入值会跟随导出值变化
  4. ES Module 会编译成 require/exports 来执行的

参考:

https://es6.ruanyifeng.com/#docs/module

https://segmentfault.com/a/1190000017878394?utm_source=tag-newest

https://juejin.im/book/5bdc715fe51d454e755f75ef/section/5bdd0d83f265da615f76ba57#heading-6

TeraTerm 使用技巧 ⏹TeraTerm 使用技巧 阅读详情

相关推荐

window下移动设备/硬盘报错位置不可用

移动硬盘指示灯亮,但电脑上不显示 报错信息 : 无法访问E:\。参数错误。 报错原因: 移动硬盘打不开提示参数错误,是因为这个H盘的文件系统内部结构损坏导致的。要怎么恢复里面的数据呢? https://jingyan.baidu.com/article/cb5d6105a80242005c2fe0c3.html 解决办法 : 不用格式化修复方法 方法一: 1、单击–开始–运行–输入cmd; 2、...

qq_40907977的博客 4928

CommonJS:Node.js 的模块化基石

摘要: CommonJS 是 JavaScript 模块化的重要规范,尤其广泛应用于 Node.js 开发。它通过 require 导入模块、module.exports 导出内容,实现代码的模块化管理,避免全局污染并提升可维护性。其同步加载机制适合服务端环境,但存在循环依赖和浏览器兼容性问题。虽然 ES6 模块已成为现代标准,CommonJS 仍在 Node.js 生态中占据核心地位,为开发者提供简单高效的模块化方案。理解其核心概念与优缺点,有助于在不同场景下合理选择模块化方案。

你若盛开,清风自来 1134

RTKLIB模糊度固定实战:三种模式对比与部分模糊度固定代码解析

本文深入解析RTKLIB中模糊度固定的三种核心模式(continuous、instantaneous、fix and hold),对比其性能与适用场景,并详细拆解了部分模糊度固定技术的源码实现。通过实战案例与代码级解析,为GNSS高精度定位开发者提供了在不同数据特性下提升固定成功率的优化思路与配置建议。

efc1234567的博客 473

Node.js从0.5到1学习计划

通过这个强化训练计划,你不仅能掌握Node.js核心开发能力,还能积累真实的项目经验。(Tip:学习完成后可尝试为开源项目提交PR,快速提升实战能力):配置Prometheus + Grafana仪表盘。:构建用户管理API(JWT认证+数据校验):使用ApacheBench进行压力测试对比。:编写异步文件处理程序(读取→修改→保存):开发图书管理系统(增删改查+分页查询):使用OWASP ZAP进行安全扫描。:用Stream实现大文件压缩传输。:构建订单处理微服务集群。:开发电商系统核心模块。

weixin_45825917的博客 700

IEEE Transaction期刊模板使用注意事项

本文将总结使用IEEE Transactions系列期刊的投稿模板时的一些注意事项,包括模板本身的使用规范、参考文献的正确格式等其他内容。

weixin_39529207的博客 2万+

基于C#的软PLC梯形图编辑器开发实战

本文详细介绍了基于C#开发软PLC梯形图编辑器的实战过程。文章从核心数据结构设计入手,阐述了如何利用C#的面向对象特性构建梯形图元素模型,并实现了图形编辑、指令表输入、逻辑连接拓扑重建等关键功能。重点剖析了模拟PLC执行引擎的扫描周期与能流传递算法,让梯形图逻辑在PC上“活”起来。最后探讨了定时器指令实现、性能优化及项目集成等进阶内容,为工业自动化软件集成提供了灵活高效的解决方案。

weixin_28314575的博客 404

JS两周学习计划

以下是一个为期两周的JavaScript学习计划,适合初学者或希望巩固基础的学习者。每天安排约2-3小时的学习时间,确保理论与实践结合。通过这个计划,你可以在两周内掌握 JavaScript 的基础知识,并具备一定的实战能力。坚持每天学习,多动手实践,效果会更好!

鸭梨的博客 804

SillyTavern本地AI聊天平台部署与调优全指南

大型语言模型(LLM)作为当前人工智能领域的核心技术,通过其强大的自然语言理解和生成能力,正在深刻改变人机交互方式。其工作原理基于Transformer架构,通过海量数据训练,学习语言的统计规律与语义关联。这项技术的核心价值在于,它能够作为通用基础,赋能于多样化的下游应用,实现个性化的智能对话与内容创作。在工程实践中,如何高效、灵活且低成本地部署和利用这些模型,成为开发者与爱好者的关键需求。本地化部署方案,特别是结合如Ollama、KoboldCPP等推理引擎,提供了数据隐私保障与可控的硬件成本。Silly

weixin_42520448的博客 431

我们如何为 JavaScript 客户端减半模块化 AWS SDK 的发布规模

原文地址:How we halved the publish size of modular AWS SDK for JavaScript clients 原文作者:Trivikram Kamat 译文出自:掘金翻译计划 原文链接:https://aws.amazon.com/cn/blogs/developer/how-we-halved-the-publish-s...

owenzhang的博客 382

OpenClaw界面操作手册:命令行与交互模式的正确打开方式

"test": {"description": "运行项目的测试套件","prompt": "请执行项目的测试命令,并分析测试结果。如果有失败的测试,请提供修复建议。},"lint": {"description": "运行代码检查","prompt": "请运行代码检查工具,分析所有警告和错误,并提供修复建议。},"doc": {"description": "为当前文件生成文档","prompt": "请为当前打开的文件生成完整的API文档,包括函数说明、参数描述、返回值类型和使用示例。

gaoxiang_120的专栏 3147

YOLOv11改进策略【模型轻量化】| 替换华为的极简主义骨干网络:VanillaNet

本文记录的是基于VanillaNet的YOLOv11轻量化改进方法研究。VanillaNet的极简主义在于无 shortcut 连接,并且在网络的每个阶段仅使用一层卷积,无额外复杂模块,仅通过自身简洁的架构设计和训练策略,实现有效地训练和优化。本文在替换骨干网络中配置了原论文中的、和11种模型,以满足不同的需求。

Limiiiing的博客 1724

GBA.js架构设计解析:模块化JavaScript模拟器的开发哲学

GBA.js是一个用纯JavaScript实现的Game Boy Advance浏览器模拟器,它展示了如何通过现代化的Web技术实现复杂的硬件模拟。这个项目采用了高度模块化的架构设计,将复杂的GBA硬件系统分解为多个独立的组件,每个组件负责特定的功能模块。这种设计不仅提高了代码的可维护性,还使得模拟器能够在浏览器环境中高效运行。 ## 🎯 核心架构设计理念 GBA.js的架构设计遵循了**模

gitblog_00821的博客 692

ArcGIS Pro 3.4 二次开发 - 知识图谱

本文介绍了在ArcGIS Pro SDK 3.4和.NET 8环境下操作知识图谱的方法。主要包含两大功能模块:1) 知识图谱数据存储操作,包括建立连接、获取图层、检索要素类与表定义、ID转换等;2) 知识图谱数据模型管理,如获取数据模型属性、标识符信息等。代码示例详细展示了如何使用C#通过QueuedTask异步任务与知识图谱服务交互,包括异常处理、数据转换等常见操作场景。所有示例均采用using语句确保资源释放,并遵循ArcGIS Pro SDK的最佳实践。

Winemonk 763

js中的模块化

生活: 这周是真充实,上年积极分子考试没考过,今年又花很长时间在那听,这周四就要考试,着实心理压力比较大,感觉那么多人都可以过,为啥自己就是那么的特殊,一个考试就过不了,然后这周天天早上就在背,背的自己都感动了,后来…然后这周开始我们就要恢复到正常学习模式了,周一学姐就发了任务,大二的第一次项目,我是视频项目,上回做的音乐项目的滚动条我做的到现在就印象深刻,如今视频这个项目…这一周我都在做主页,看住都是一样的,说弄一个就都出来了,但是他们的都是不一样的,还是交叉着的,所以,几乎每一个都要自己做,虽然有些样式

qq_53280805的博客 151

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

CommonJS vs ES6模块:JavaScript Modularization Journey带你深入理解模块化规范

JavaScript模块化是现代前端开发的核心技术,它解决了代码组织、作用域隔离和依赖管理等关键问题。GitHub加速计划中的js-module-7day项目(Slides: JavaScript Modularization Journey)通过丰富的示例和清晰的讲解,帮助开发者掌握CommonJS与ES6模块这两种主流规范的使用方法和核心差异。 ## 📚 模块化的前世今生:为什么我们需要模

gitblog_00913的博客 324

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

33-js-concepts mentorship:技术导师与学员培养计划

在当今快速发展的前端技术生态中,JavaScript作为核心语言,其深度和广度都在不断扩展。许多开发者在学习过程中面临以下痛点: - **概念碎片化**:33个核心概念分散在不同资料中,缺乏系统化整合 - **实践指导缺失**:理论知识与实际项目脱节 - **学习路径模糊**:不知道从何开始,如何循序渐进 - **反馈机制缺乏**:无法获得专业的技术指导和代码审查 基于33-js-concep...

gitblog_00253的博客 1078

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

视频教程-npm与模块化开发-JavaScript

npm与模块化开发 5年前端开发经验,2年教学工作经验。曾就职于百度,前百度...

weixin_31052059的博客 295

关于js模块化prototype

最近打算向HTML5的canvas进发,还有nodejs,所以对js的模块化有必要弄懂,刚好找到篇很不错的文章,先转过来,熟练之后再写个读后感~~~ http://www.cnblogs.com/yjf512/archive/2011/06/03/2071914.html

204

nodejs学习计划--(五)模块化

什么是模块化与模块 ? 将一个复杂的程序文件依据一定规则(规范)拆分成多个文件的过程称之为 **模块化** 其中拆分出的 **每个文件就是一个模块** ,模块的内部数据是私有的,不过模块可以暴露内部数据以便其他模块使用 2. 什么是模块化项目 ? 编码时是按照模块一个一个编码的, 整个项目就是一个模块化的项目

把代码调成柠檬味 497

个人关于模块化的理解

个人对于模块化的探索 前一段时间我们前端的项目组有一个分兴趣小组的计划.因为那时候整个小组只有9个人,所以就分了三个小组,分别是 `性能优化`, `模块化`, `新技术` 三个小组. 而我那进了"模块化研究"小组.所以嘞.研究模块化以及如何让项目的模块化更加合理和高效是我们小组的主要目的. 首先,在实行模块化之前,得先巩固模块化开发的理论基础,因为理论是实践的基础。 只有这样,在过程中理论与实践相...

weixin_34008805的博客 1119

揭秘Anime.js核心开发团队:JavaScript动画引擎背后的创造者

Anime.js是一款快速、多用途且轻量级的JavaScript动画库,以其简洁而强大的API著称。它支持CSS属性、SVG、DOM属性和JavaScript对象的动画效果,为开发者提供了丰富的动画创作可能性。 ## 项目创始人Julian Garnier的愿景与贡献 🌟 Anime.js由Julian Garnier创立并主导开发。从项目结构可以看出其清晰的架构设计,核心代码组织在[src

gitblog_01012的博客 1003

web前端学习实施计划

希望这份学习计划对你有帮助!如果有任何问题,随时可以问我哦!目标:深入学习前端的核心技术,能够独立完成静态页面。从基础到进阶,适合零基础或有一定基础的学习者。目标:学习现代前端框架和工具,提升开发效率。目标:通过实际项目积累经验,提升综合能力。目标:学习更多高级技术,为职业发展做准备。目标:掌握前端开发的基本概念和工具。

Program Han 3206

python3.7对应的tensorflow版本_TensorFlow.js 更新计划

文 /Yannick Assogba, 软件工程师, Google Research随着 TensorFlow.js 越来越多地在生产环境中使用,我们团队意识到需要为在浏览器端使用 TensorFlow.js 的开发者,开发小型、对生产环境优化的小型打包工具。我们一直在为此作出努力,现在此与您分享我们的更新计划。对于即将发布的 TensorFlow.js,我们的主要目标是在保持对初学者...

weixin_39715460的博客 3236

从 AMD 到 ES6 模块化:前端模块化的演进之路

摘要: 前端模块化经历了从AMD到ES6的演进过程。AMD规范(如RequireJS)通过异步加载解决早期全局变量污染和依赖混乱问题,但存在语法冗余和服务器端支持不足的缺点。ES6模块化作为原生方案,凭借import/export的简洁语法、静态分析能力及工具链(Babel、Webpack)的支持,成为主流选择。两者的对比凸显了技术发展趋势:ES6模块化在开发体验、生态系统和兼容性优化上更胜一筹,标志着前端模块化向高效、标准化方向的成熟演进。

你若盛开,清风自来 776

js-pptx:使用纯JavaScript操作PowerPoint文件的开源工具

js-pptx是一个基于纯JavaScript的PowerPoint文件读取、编辑和生成工具,专为Node.js环境设计。该项目旨在提供一个简洁高效的API,让开发者能够轻松操作PPTX文件,包括添加文本、形状、图表以及进行XML级别的精细操作。 ## 项目技术架构 js-pptx采用模块化设计,核心依赖包括: - **JSZip**:用于解压缩和重新压缩PPTX文件 - **xml2js*

gitblog_00015的博客 521

log4js-node未来路线图:2024年新特性与改进计划

log4js-node作为Node.js生态中最受欢迎的日志记录库之一,正在积极规划未来的发展方向。根据最新的版本趋势和社区反馈,log4js-node将带来一系列令人期待的新特性和改进计划。🎉 ## 🔮 即将推出的核心功能 ### 增强的TypeScript支持 log4js-node计划进一步加强TypeScript类型定义,提供更完善的类型安全保证。目前types/log4js.d.

gitblog_01031的博客 855
上一篇: 深入javascript计划七:深入浅出Event loop
下一篇: 前端框架通识:MVVM是什么?
An_s
博客等级 码龄10年 665粉丝 363原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

An_s

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值