ES6之路之模块详解

简介: 一个模块只不过是一个写在文件中的 JavaScript 代码块。

简介


何为模块


一个模块只不过是一个写在文件中的 JavaScript 代码块。


模块中的函数或变量不可用,除非模块文件导出它们。


简单地说,这些模块可以帮助你在你的模块中编写代码,并且只公开应该被你的代码的其他部分访问的代码部分。


为什么要使用模块


  1. 增加可维护性:由于每个模块都是独立的,每个人写的代码是不会相互影响的,在维护代码的时候很好排查是哪个模块出错。


  1. 可复用性:在日常的开发中,特别是大点的项目,代码的可复用性就更重要了,也许你会用复制粘贴的形式,但是直接一个 import 命令就可以搞定,岂不快哉。


  1. 避免命名污染:在 javascript 脚本中,所有的 js 文件的顶级作用域创建的变量,会被添加到共享的全局作用域,这就会导致不同的人开发的代码可能会有相同的变量名,导致变量名污染。


如何使用


导出模块


导出模块所用的命令是 export。


前面也提到一个模块就是一个 javascript 文件,在这个模块中定义的变量,外部是无法获取到的,只有通过 export 导出的变量其他模块才可以用


最简单的导出方式就是在声明的变量、函数、类前面加一个 export


// export1.js 
// 导出变量
export let name = '桃翁';
// 导出函数
export function print() {
    console.log("欢迎关注公众号:前端桃园");
}
// 导出类
export class Person {
    constructor(name) {
        this.name = name;
    }
}
// 私有函数
function privateFunction () {
    console.log('我是私有函数,外部访问不了我');
}


注意


  1. 被导出的函数或者类,都必须要有名称,意思就是说不能用这种方式导出匿名函数或者匿名类。


  1. privateFunction 函数,没有加 export 命令,被当做这个模块的私有变量,其他模块是访问不到的。


除了上面那种导出方式,还有另外一种


// export2.js
// 导出变量
let name = '桃翁';
// 导出函数
function print() {
    return '欢迎关注公众号:前端桃园';
}
// 导出类
class Person {
    constructor(name) {
        this.name = name;
    }
}
// 私有函数
function privateFunction () {
    return '我是私有函数,外部访问不了我';
}
export { name, print, Person }


上面这种写法导入一组变量,与 export1.js 是等价的。


导入模块


导入的模块可以理解为是生产者(或者服务的提供者),而使用导入的模块的模块就是消费者。


导入模块的命令是 import, import 的基本形式如下:


import { var1, var2 } from './example.js'


import 语句包含两部分:一是导入需要的标识符,二是模块的来源。


注意:浏览器中模块来源要以「/」或者 「./」 或者 「../」开头 或者 url 形式,不然会报错。


例如我们导入 export1.js 模块,可以这么导入


// import1.js
import { name, print, Person } from './export1.js';
console.log(name); // 桃翁
console.log(print()); // 欢迎关注公众号:前端桃园
// 报错, 不能定义相同名字变量
let name = 2333; 
// 报错,不能重新赋值
name = "小猪";


可以看到导入绑定(这里不理解绑定,文章后面会解释)时,形式类似于对象解构,但实际上并无关联。


当导入绑定的时候,绑定类似于使用了 const 定义,意味着不能定义相同的变量名,但是没有暂时性死区特性(但是在 深入理解ES6 这本书里面说是有暂时性死区限制,我在 chrome 上测试了的,读者希望也去试下,到底受不受限制)。


let name = 2333;


上面这行代码会报错。


命名空间导入


这种导入方式是把整个生产者模块当做单一对象导入,所有的导出被当做对象的属性。


// import2.js
import * as namespace from './export1.js'
console.log(namespace.name); // 桃翁
console.log(namespace.print()); // 欢迎关注公众号:前端桃园


重命名导入导出


有时候你并不想导出变量的原名称,需要重新命名,这个时候只需要使用 as 关键字来制定新的名字即可。


重命名导出


// export3.js
function print() {
    return '欢迎关注公众号:前端桃园';
}
export { print as advertising }


导重命名入


拿上面导出的举例子


// import3.js
import { advertising as print } from './export3.js'
console.log(typeof advertising); // "undefined"
console.log(print()); // 欢迎关注公众号:前端桃园


此代码导入 advertising 函数并重命名为了 print ,这意味着此模块中 advertising 标识符不存在了。


default 关键字


default 关键字是用来做默认导入导出的。


默认导出


// defaultExport.js
// 第一种默认导出方式
export default function print() {
    return '欢迎关注公众号:前端桃园';
}
// 第二种默认导出方式
function print() {
    return '欢迎关注公众号:前端桃园';
}
export default print;
// 第三种默认导出方式
function print() {
    return '欢迎关注公众号:前端桃园';
}
export { print as default }


default 这个关键字在 JS 中具有特殊含义,既可以作为同命名导出,又标明了模块需要使用默认值。


注意: 一个模块中只能有一个默认导出。


默认导入


默认导入和一般的导入不同之处就是不需要写大括号了,看起来更简洁。


把上面 defaultExport.js 模块导出的作为例子


import print from './defaultExport.js'
console.log(print()); // 欢迎关注公众号:前端桃园


那如果既有默认的又有非默认的怎么导入呢?看例子就明白了


// defaultImport1.js
let name = '桃翁';
function print() {
    return '欢迎关注公众号:前端桃园';
}
export { name, print as default }


// defaultImport2.js
import print, { name } from './defaultImport1.js'
console.log(print()); // 欢迎关注公众号:前端桃园
console.log(name); // 桃翁


混合导入需要把默认导入的名称放在最前面,然后用逗号和后面非默认导出的分割开。


思考了很久是否应该加上进阶内容,本来是想写入门级系列的,但是想了想,还是都写进来吧,入门的看入门前面基础,深入理解的看进阶。


进阶


进阶部分主要介绍 模块的几个特性


  • 静态执行


  • 动态关联


  • 模块不会重复执行


静态执行


所谓静态执行其实就是在编译阶段就需要确定模块的依赖关系,那么就会出现 import 命令会优先于模块其他内容的执行,会提前到编译阶段执行。


// static1.js
console.log('佩奇');
import { nouse } from './static2.js'
// static2.js
export function nouse() {
    return '我是不需要的';
}
console.log('小猪');


可以看到最后输出的应该是「小猪」先输出,而「佩奇」后输出,可以得出虽然 static2.js 在后面引入,但是会被提升到模块的最前面先执行。


这也是我前面所说的不受暂时性死区原因之一,在这里可以写一个例子试试:


// static3.js
console.log(nouse());
import { nouse } from './static2.js'
// 结果:
// 小猪
// 我是不需要的


经检验确实是可以在 import 之前使用导入的绑定。


静态执行还会导致一个问题,那就是不能动态导入模块。


// 报错
if (flag) {
    import { nouse } from './static3.js'
}
// 报错
import { 'no' + 'use' } from './static3.js'


因为 import 是静态执行的,所以在静态(词法)分析阶段,是没法得到表达式或者变量的值的。


但是为了解决这个问题,因为了 import() 这个函数,这个算扩展内容吧,写太多了我怕没人看完了,后面会有扩展阅读链接。


动态关联


所谓的动态关联,其实就是一种绑定关系, 这是 ES6 非常重要的特性,一定仔细阅读。

在 ES6 的模块中,输出的不是对象的拷贝,不管是引用类型还是基本类型, 都是动态关联模块中的值。


// dynamic1.js
export let name = '桃翁';
export function setName(nam ) {
    name = nam ;
}
// dynamic2.js
import { name, setName } from './dynamic1.js'
console.log(name); // 桃翁
setName('不要脸');
console.log(name); // 不要脸


奇迹般的发现在 dynamic2.js 模块中可以修改 dynamic1.js 模块里面的值, 并且反应到 name 绑定上(这个是重点,这个反应到了消费者模块), 所以我们把导入的变量叫做绑定。


在生产者模块导出的变量与消费者模块导入的变量会有一个绑定关系,无论前者或者后者发生改变,都会互相影响。


注意区分在一个文件或模块中基本类型的赋值,两者是互不影响的。


模块不会重复执行


这个特性比较好理解,就是如果从一个生产者模块中分别导入绑定,而不是一次性导入,生产者模块不会执行多次。


// noRepeat1.js
export let name = '桃翁';
export let age = '22';
console.log('我正在执行。。。');
// noRepeat2.js
import { name } from './noRepeat1.js';
import { age } from './noRepeat1.js';
console.log(name);
console.log(age);
// 结果
// 我正在执行。。。
// 桃翁
// 22


虽然导入了两次,但是 noRepeat1.js 只有执行一次。若同一个应用(注意是同一个应用不是模块)中导入同一个模块,则那些模块都会使用一个模块实例,意思就是说是一个单例。

目录
相关文章
|
9天前
|
人工智能 开发工具 iOS开发
Claude Code 新手完全上手指南:安装、国产模型配置与常用命令全解
Claude Code 是一款运行在终端环境中的 AI 编程助手,能够直接在命令行中完成代码生成、项目分析、文件修改、命令执行、Git 管理等开发全流程工作。它最大的特点是**任务驱动、终端原生、轻量高效、多模型兼容**,无需图形界面、不依赖 IDE 插件,能够深度融入开发者日常工作流。
3111 8
|
12天前
|
Shell API 开发工具
Claude Code 快速上手指南(新手友好版)
AI编程工具卷疯啦!Claude Code凭借任务驱动+终端原生的特性,成了开发者的效率搭子。本文从安装、登录、切换国产模型到常用命令,手把手带新手快速上手,全程避坑,30分钟独立用起来。
3183 20
|
5天前
|
人工智能 Linux BI
国内用 Claude Code 终于不用翻墙了:一行命令搞定,自动接 DeepSeek
JeecgBoot AI专题研究 一键脚本:Claude Code + JeecgBoot Skills + DeepSeek 全平台接入 一行命令装好 Claude Code + JeecgBoot Skills + DeepSeek 接入,无需翻墙使用 Claude Code,支持 Wind
2103 3
国内用 Claude Code 终于不用翻墙了:一行命令搞定,自动接 DeepSeek
|
24天前
|
人工智能 JSON 供应链
畅用7个月无影 JVS Claw |手把手教你把JVS改造成「科研与产业地理情报可视化大师」
LucianaiB分享零成本畅用JVS Claw教程(学生认证享7个月使用权),并开源GeoMind项目——将JVS改造为科研与产业地理情报可视化AI助手,支持飞书文档解析、地理编码与腾讯地图可视化,助力产业关系图谱构建。
23588 15
畅用7个月无影 JVS Claw |手把手教你把JVS改造成「科研与产业地理情报可视化大师」
|
1天前
|
人工智能 自然语言处理 文字识别
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
Qwen3.7-Max是阿里云百炼面向智能体时代推出的新一代旗舰模型,对标GPT-5.5、Claude Opus 4.7等闭源旗舰。该模型支持百万级token上下文窗口,具备顶级推理能力、多模态搜索与视觉理解增强、流式输出低延迟响应等核心优势,覆盖编程、办公、长周期自主执行等复杂场景。同时支持OpenAI接口兼容,便于系统快速迁移。用户可通过Token Plan团队版、Coding Plan或节省计划等订阅方式灵活调用,适合企业级高要求场景使用。
|
11天前
|
人工智能 JSON BI
DeepSeek V4-Pro 接入 Claude Code 完全实战:体验、测试与关键避坑指南
Claude Code 作为当前主流的 AI 编程辅助工具,凭借强大的代码理解、工程执行与自动化能力深受开发者喜爱,但原生模型的使用成本相对较高。为了在保持能力的同时进一步降低开销,不少开发者开始寻找兼容度高、价格更友好的替代模型。DeepSeek V4 系列的发布带来了新的选择,该系列包含 V4-Pro 与 V4-Flash 两款模型,并提供了与 Anthropic 完全兼容的 API 接口,理论上只需简单修改配置,即可让 Claude Code 无缝切换为 DeepSeek 引擎。
2603 3
|
3天前
|
人工智能 自然语言处理 安全
Claude Code 全攻略:命令大全+三种模式+记忆体系+实战工作流完整手册
Claude Code 是当前最流行的终端级 AI 编程助手,能够直接在命令行中完成代码生成、项目理解、文件修改、命令执行、错误修复等全流程开发工作。它不依赖图形界面、不占用额外资源,却能深度理解项目结构,自动生成规范代码,大幅提升研发效率。
751 2
|
10天前
|
人工智能 安全 开发工具
Claude Code 官方工作原理与使用指南
Claude Code 不是传统代码补全工具,而是 Anthropic 推出的终端 AI 代理,具备代理循环、双驱动架构(模型+工具)、全局项目感知、6 种权限模式等核心能力,本文基于官方文档系统解析其工作原理与高效使用技巧。
1430 0