ES6新特性:使用export和import实现模块化详解
发布时间 - 2026-01-11 02:34:56 点击率:次在ES6前, 前端就使用RequireJS或者seaJS实现模块化, requireJS是基于AMD规范的模块化库, 而像seaJS是基于CMD规范的模块化库, 两者都是为了为了推广前端模块化的工具, 更多有关AMD和CMD的区别, 后面参考给了几个链接;

现在ES6自带了模块化, 也是JS第一次支持module, 在很久以后 ,我们可以直接作用import和export在浏览器中导入和导出各个模块了, 一个js文件代表一个js模块;
现代浏览器对模块(module)支持程度不同, 目前都是使用babelJS, 或者Traceur把ES6代码转化为兼容ES5版本的js代码;
ES6的模块化的基本规则或特点:
ES6的模块化的基本规则或特点, 欢迎补充:
1:每一个模块只加载一次, 每一个JS只执行一次, 如果下次再去加载同目录下同文件,直接从内存中读取。 一个模块就是一个单例,或者说就是一个对象;
2:每一个模块内声明的变量都是局部变量, 不会污染全局作用域;
3:模块内部的变量或者函数可以通过export导出;
4:一个模块可以导入别的模块
运行下面代码
//lib.js
//导出常量
export const sqrt = Math.sqrt;
//导出函数
export function square(x) {
return x * x;
}
//导出函数
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
//main.js
import { square, diag } from './lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5
下面列出几种import和export的基本语法:
第一种导出的方式:
在lib.js文件中, 使用 export{接口} 导出接口, 大括号中的接口名字为上面定义的变量, import和export是对应的;
运行下面代码
//lib.js 文件
let bar = "stringBar";
let foo = "stringFoo";
let fn0 = function() {
console.log("fn0");
};
let fn1 = function() {
console.log("fn1");
};
export{ bar , foo, fn0, fn1}
//main.js文件
import {bar,foo, fn0, fn1} from "./lib";
console.log(bar+"_"+foo);
fn0();
fn1();
第二种导出的方式:
在export接口的时候, 我们可以使用 XX as YY, 把导出的接口名字改了, 比如: closureFn as sayingFn, 把这些接口名字改成不看文档就知道干什么的:
运行下面代码
//lib.js文件
let fn0 = function() {
console.log("fn0");
};
let obj0 = {}
export { fn0 as foo, obj0 as bar};
//main.js文件
import {foo, bar} from "./lib";
foo();
console.log(bar);
第三种导出的方式:
这种方式是直接在export的地方定义导出的函数,或者变量:
运行下面代码
//lib.js文件
export let foo = ()=> {console.log("fnFoo") ;return "foo"},bar = "stringBar";
//main.js文件
import {foo, bar} from "./lib";
console.log(foo());
console.log(bar);
第四种导出的方式:
这种导出的方式不需要知道变量的名字, 相当于是匿名的, 直接把开发的接口给export;
如果一个js模块文件就只有一个功能, 那么就可以使用export default导出;
运行下面代码
//lib.js export default "string"; //main.js import defaultString from "./lib"; console.log(defaultString);
第五种导出方式:
export也能默认导出函数, 在import的时候, 名字随便写, 因为每一个模块的默认接口就一个:
运行下面代码
//lib.js
let fn = () => "string";
export {fn as default};
//main.js
import defaultFn from "./lib";
console.log(defaultFn());
第六种导出方式:
使用通配符* ,重新导出其他模块的接口 (其实就是转载文章, 然后不注明出处啦);
运行下面代码
//lib.js
export * from "./other";
//如果只想导出部分接口, 只要把接口名字列出来
//export {foo,fnFoo} from "./other";
//other.js
export let foo = "stringFoo", fnFoo = function() {console.log("fnFoo")};
//main.js
import {foo, fnFoo} from "./lib";
console.log(foo);
console.log(fnFoo());
其他:ES6的import和export提供相当多导入以及导出的语法;
在import的时候可以使用通配符*导入外部的模块:
运行下面代码
import * as obj from "./lib"; console.log(obj);
ES6导入的模块都是属于引用:
每一个导入的js模块都是活的, 每一次访问该模块的变量或者函数都是最新的, 这个是原生ES6模块 与AMD和CMD的区别之一,以下代码修改自http://exploringjs.com/es6/ch_modules.html#_imports-are-read-only-views-on-exports
运行下面代码
//lib.js
export let counter = 3;
export function incCounter() {
counter++;
}
export function setCounter(value) {
counter = value;
}
//main.js
import { counter, incCounter ,setCounter} from './lib';
// The imported value `counter` is live
console.log(counter); // 3
incCounter();
console.log(counter); // 4
setCounter(0);
console.log(counter); // 0
在main.js中, counter一直指向lib.js中的局部变量counter, 按照JS的尿性, 像数字或者字符串类型或者布尔值的原始值要被复制, 而不是赋址;
循环依赖的问题:
NodeJS的循环依赖是这么处理的:打开;
循环依赖是JS模块化带来的问题, 在浏览器端, 使用RequireJS测试模块化, 比如有一个文件file0.js依赖于file1.js, 而file1.js又依赖于file0.js, 那么file0.js和file1.js到底谁先执行?
运行下面代码
//index.html
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8"/>
</head>
<body>
<script data-main="cyclic" src="//cdn.bootcss.com/require.js/2.2.0/require.min.js"></script>
<script>
//cyclic.js
require(["file0"], function(file0) {
console.log(file0)
})
//file0.js
define(["file1"], function(file1) {
console.log(file1)
return {
file0 : "file0"
}
})
//file1.js
define(["file0"], function(file0) {
console.log(file0);
return {
file1 : "file1"
}
})
</script>
</body>
</html>
在控制台的依次输出为:
运行下面代码
undefined
Object { file1: "file1" }
Object { file0: "file0" }
在执行file1.js的时候file0.js还没执行完, 所以输出了undefined, 这种输出结果和NodeJS输出的情况是一样的;
然后我又使用了司徒大神的mass-framework框架试了一下, 司徒大神的框架直接提示我: "模块与之前的某些模块存在循环依赖", 这样还比较好点, requireJS对于循环依赖是直接执行循环依赖的模块, 会导致在开发的时候给自己挖坑....;
接下来我又在babel-node下进行测试:下面是几个测试,可以无视:
我使用ES6的模块试一试, 只要每一个模块被引用, 无论模块是否执行完毕, 该模块的export已经被导出了, 如果导出的是函数:
运行下面代码
//cyclic.js
import fn0 from "./file0";
fn0();
//file0.js
import fn1 from "./file1";
fn1();
console.log("file0.js runs");
export default function() {console.log("file0 export runs")}
//file1.js
import fn0 from "./file0";
fn0();
console.log("file1.js runs");
export default function() {console.log("file1 export runs")}
如果导出的是字符串:
运行下面代码
//cyclic.js
import str from "./file0";
console.log(str);
//file0.js
import str1 from "./file1";
console.log(str1)
console.log("file0.js runs");
export default "str0";
//file1.js
import str0 from "./file0";
console.log(str0)
console.log("file1.js runs");
export default "str1";
如果导出的是对象:
那么第一行会先输出一个初始值{},在最后等待file0.js和file1.js执行完毕以后, 才输出file0.js导出的对象;
如果是数组:
那么第一行会输出一个被静态分析过的初始值undefined,在最后等待file0.js和file1.js执行完毕以后, 才输出file0.js导出的对象;
如果是布尔值:
那么第一行会输出一个被静态分析过的初始值undefined,在最后等待file0.js和file1.js执行完毕以后, 才输出file0.js导出的布尔值;
为什么会这样呢? 我好像在这边找到了答案:http://exploringjs.com/es6/ch_modules.html#_modules ,ES6的import和export被提前到js的最顶层, 在函数或者对象,或者基本值被导出去的时候提前被静态分析过,参考:http://www.ecma-international.org/ecma-262/6.0/#sec-parsemodule , http://www.ecma-international.org/ecma-262/6.0/#sec-toplevelmoduleevaluationjob
结论:用ES6的export导出数据接口的时候, 最好统一用函数, 避免在循环依赖的时候, 因为JS会把不同类型的对象静态解析成不同的初始值;
浏览器兼容:
- chrome浏览器目前不支持import,和export;
- 火狐的支持也有限, 比chrome好;
- 我都用babel;
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# es6
# import
# export
# js
# ES6中非常实用的新特性介绍
# JavaScript ES6的新特性使用新方法定义Class
# JavaScript中的Reflect对象详解(ES6新特性)
# 深入浅出ES6新特性之函数默认参数和箭头函数
# 简单谈谈ES6的六个小特性
# ES6新特性之Symbol类型用法分析
# ES6(ECMAScript 6)新特性之模板字符串用法分析
# ES6新特性之变量和字符串用法示例
# ES6新特性之模块Module用法详解
# ES6新特性之字符串的扩展实例分析
# ES6新特性二:Iterator(遍历器)和for-of循环详解
# ES6新特性六:promise对象实例详解
# ES6新特性七:数组的扩充详解
# ES6新特性八:async函数用法实例详解
# ES6新特性之类(Class)和继承(Extends)相关概念与用法分析
# 让微信小程序支持ES6中Promise特性的方法详解
# es6新特性之 class 基本用法解析
# ES6 13个新特性总结
# 都是
# 的是
# 司徒
# 几个
# 我又
# 大神
# 可以使用
# 布尔值
# 加载
# 还没
# 是基于
# 也能
# 很久
# 依赖于
# 要把
# 我们可以
# 可以通过
# 给了
# 给自己
# 要知道
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
郑州企业网站制作公司,郑州招聘网站有哪些?
C++时间戳转换成日期时间的步骤和示例代码
焦点电影公司作品,电影焦点结局是什么?
用yum安装MySQLdb模块的步骤方法
Python制作简易注册登录系统
Linux安全能力提升路径_长期防护思维说明【指导】
Python文件流缓冲机制_IO性能解析【教程】
简历在线制作网站免费版,如何创建个人简历?
Laravel Livewire是什么_使用Laravel Livewire构建动态前端界面
Laravel API路由如何设计_Laravel构建RESTful API的路由最佳实践
Chrome浏览器标签页分组怎么用_谷歌浏览器整理标签页技巧【效率】
JS经典正则表达式笔试题汇总
Laravel如何与Vue.js集成_Laravel + Vue前后端分离项目搭建指南
Laravel怎么实现模型属性转换Casting_Laravel自动将JSON字段转为数组【技巧】
Laravel如何实现本地化和多语言支持_Laravel多语言配置与翻译文件管理
网站制作免费,什么网站能看正片电影?
Laravel如何实现用户密码重置功能?(完整流程代码)
佐糖AI抠图怎样调整抠图精度_佐糖AI精度调整与放大细化操作【攻略】
如何在阿里云虚拟主机上快速搭建个人网站?
如何使用 Go 正则表达式精准提取括号内首个纯字母标识符(忽略数字与嵌套)
JS中对数组元素进行增删改移的方法总结
如何自定义safari浏览器工具栏?个性化设置safari浏览器界面教程【技巧】
高端企业智能建站程序:SEO优化与响应式模板定制开发
Laravel怎么配置不同环境的数据库_Laravel本地测试与生产环境动态切换【方法】
企业在线网站设计制作流程,想建设一个属于自己的企业网站,该如何去做?
北京网站制作的公司有哪些,北京白云观官方网站?
专业企业网站设计制作公司,如何理解商贸企业的统一配送和分销网络建设?
Win11怎么恢复误删照片_Win11数据恢复工具使用【推荐】
JavaScript如何实现错误处理_try...catch如何捕获异常?
网站制作壁纸教程视频,电脑壁纸网站?
如何获取免费开源的自助建站系统源码?
Laravel如何配置和使用队列处理异步任务_Laravel队列驱动与任务分发实例
韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐
Midjourney怎样加参数调细节_Midjourney参数调整技巧【指南】
如何用PHP工具快速搭建高效网站?
如何在香港服务器上快速搭建免备案网站?
如何用wdcp快速搭建高效网站?
微信小程序 scroll-view组件实现列表页实例代码
Laravel路由Route怎么设置_Laravel基础路由定义与参数传递规则【详解】
微信小程序制作网站有哪些,微信小程序需要做网站吗?
香港服务器选型指南:免备案配置与高效建站方案解析
在线ppt制作网站有哪些软件,如何把网页的内容做成ppt?
如何挑选最适合建站的高性能VPS主机?
Laravel如何配置中间件Middleware_Laravel自定义中间件拦截请求与权限校验【步骤】
Laravel Octane如何提升性能_使用Laravel Octane加速你的应用
Python数据仓库与ETL构建实战_Airflow调度流程详解
敲碗10年!Mac系列传将迎来「触控与联网」双革新
如何快速搭建高效简练网站?
南京网站制作费用,南京远驱官方网站?
油猴 教程,油猴搜脚本为什么会网页无法显示?

