作为初学前端的学习者,我们一直缺少一个系统学习es6中的模块化的时机,虽然它非常重要,但由于没有一个相对简单的可运行代码的环境导致初学者很难掌握它。
本文主要解决了两个问题:
教你在浏览器中直接跑ES6的模块化。
ES6模块化的最核心内容。
引入
历史上,javascript作为一门解释型的弱类型语言一直不被人看重。其中有很一个很重要的因素是它没有模块体系。模块体系说起来很高大上,其核心就是一句话:在一个.js中引用另一个.js文件。在正常情况下,你是无法实现一个js文件中引用另一个js文件的。
例如:有两个文件:a.js,b.js
// a.js 中定义了一个函数function f1() {}
b.js
// b.js// 如何去使用a.js中定义的f1?
这个问题在其它很多编程语言中都不是问题,例如java,php,c,c++,python..... 。
在es6出来之前,解决这个问题很痛苦,有如下曲线救国的方法:
1. 在.html中先引入a.js,再引入b.js。这样就可以直接在b.js中使用f1了。
2. 把要共享的方法挂载到window对象上,以window对象为中介来相互访问。
3. 借用第三方的模块工具:sea.js,require.js。
这些方式可以达到目标,但没有能从根上解决javascript不支持模块的苦楚(甚至css都有自已的@import可以导入另外的css)。
好了,es2015登场,带着自已强大的语法能力回来了,它的目标是成为一门企业级的开发语言,它带着基因中的模块化回来了。
下面我们来学习es6中的模块化吧。
如何搭建一个支持es6模块化的环境
学习import ,export
如何搭建一个支持es6模块化的环境
如何搭建一个支持es6模块化的环境?我们不是一直就在浏览器中跑js代码吗?难道浏览器中不支持es6的模块化吗?
先给你一个坏消息:浏览器目前(2020年10月)还不支持(或者说不能直接支持)!
是不是很惊喜?是不是很意外?一个NB的es6中自带一个NB的模块化机制,居然在浏览器中不能直接用。哈哈。就是这样!
浏览器不支持es6模块化
写一份代码试一试,让你被错误打击一下。
一共涉及三个文件如下:
1.index.html:在这里引入index.js2.tool.js:定义updateDom()3.index.js: 引入tool.js并使用updateDom()方法
显然, 我们希望在index.js和tool.js之间有相互引用关系。
代码如下:
index.html
<html lang="zh"> <head> <title>es6模块化title> head> <body> <div id="app"> div> <scriptsrc="./index.js">script> body> html>
tool.js
function updateDom (id,content){ document.getElementById(id).innerHTML =content}export default updateDom
index.js
import tool from "./tool.js"
tool("app",'es6模块化')
此时,你打开浏览器去访问index.html,肯定会报一个错误给你说"import 不认识" 。
至少我的chrome74.0.3729.131 是这么无情。号称程序员最喜欢的浏览器都不支持,那其它的浏览器就别想了。
现在你应该可以认同我的结论的了吧,如果你想尝试使用es6的模块化,需要自已有一个环境。
下面来说如何去搭建一个支持es6模块化的环境。我给你三个选择:
方法一:用webpack之类的打包工具来打包es6成es5,这样你可以先写es6再转成es5。
方法二:用前端框架中的脚手架工具创建项目(例如vue-cli),然后在这个项目里面写代码也是可以支持的。
方法三:直接使用chrome浏览器,但要设置一个开关,并稍稍改动一下代码。
好吧,我估计你会选择第三个。
让chrome浏览器支持es6模块化
需要两个步骤,就可以在chrome浏览器感受es6的模块化了,来,坐稳:
1. 启用es6的特性.
打开chrome浏览器,在地址栏中输入 chrome://flags; 找到 experimental javascript,启用它;最后重启chrome浏览器。(注,我的版本是:chrome74.0.3729.131)
2 .修改index.html中引入.js 的方式
<html lang="zh"><head> <title>es6模块化title>head><body> <div id="app"> div> <script type="module" src="./index.js">script> body>html>
注意到上面的type="module"
好吧,再去运行上面的代码
index.js
import tool from "./tool.js"tool("app",'es6模块化')
tool.js
function updateDom(id,content) { document.getElementById(id).innerHTML = content}export default updateDom
结果如下 :
到此,你有一个可以去尽情使用es模块化的环境,下面就可以开心地去学习export , import这些新东东了。
import和export
es6的模块功能由export 和import这两个命令来提供。模块就是一个独立的.js文件。一个.js就是一个模块。
export 命令。用来在模块内部导出你想要对外开放的功能。
import命令。用来输入其它模块提供的功能。
export
export 分批导出多个
下面修改tool.js中的内容如下:
export let name = "tool.js"export const version = "1.0.1"export function updateDom (id,content) { document.getElementById(id).innerHTML = content}
在上面的模块内部,我们通过export 命令导出了 三个 东东。
下面去index.js来试着导入它们:修改在index.js中的代码
import {name,version,updateDom} from "./tool.js"console.log(name,version,updateDom)
打印结果如下:
到这里,我们已经成功地跑通了导出,导入的过程了。
注意:
export在模块内部多次使用。
import要与export一一对应。
export 批量导出多个
下面两段代码是等价的:
export let name = "tool.js"export const version = "1.0.1"export function updateDom (id,content) { document.getElementById(id).innerHTML = content}
上面是多次export,下面是一个export,但是效果是一样的。
let name = "tool.js"const version = "1.0.1"function updateDom (id,content) { document.getElementById(id).innerHTML = content}export { name, version, updateDom}
在import时也是需要这样:
import {name,version,updateDom} from "./tool.js"
我觉得只使用一个export会比较好看一些,但是,如果我的团队里有人是写多个export,我也觉得ok,我这人比较好说话。哈哈
export 导出时给起别名
在模块内部,自已想起什么函数名,变量名都可以,因为在导出时可以起别名。
例如下面我给函数起名叫 updateDom
,但是导出时,我们换个名字 modifyDom
//tool.jslet name = "tool.js"const version = "1.0.1"function updateDom (id,content) { document.getElementById(id).innerHTML = content}export { name, version, updateDom as modifyDom}
那在另一个index.js中导入这个模块时,也必须用modifyDom这个名字了。
import {name,version,modifyDom} from "./tool.js"console.log(name,version,modifyDom)
import 整体导入
对于import来说,它要导入某个模块中的内容,在不确定知道模块中的方法名,函数名,变量时,是很痛苦的。
例如:在index.js中要导入tool.js,要这样写:
import {name,version,modifyDom} from "./tool.js"
其实这里有一个隐藏的前提:name,version,modifyDom ... 这些名字在index.js中要提前知道,如果tool.js是第三方提供的模块,你事先并不知道它内部导出了什么东东,则在index.js你也不知道要写什么。如果写错名字,就导入失败了。对于import来说,有没有方法可以不用提前去拘泥于tool.jsk 的各个名字呢?
有, 这个方法就是整体导入
// 把tool.js中所有导出的内容全装在obj中import * as obj from "./tool.js"// 然后把obj打印出来,慢慢看console.log(obj)console.log(obj.name)console.log(obj.version)
export default
在上面的例子,当用户要引入一个模块时,我们在index.js中的import的写法是:
// 按需逐个引入import { name, version } from "./tool.js"// 整体导入import * as obj from "./tool.js"
而你直接写
import obj from "./tool.js"
就挂了。错误提示是这样的:
Uncaught SyntaxError: The requested module './tool.js' does not provide an export named 'default'
其实使用引用别人模块的index.js来说, importobjfrom"./tool.js"
的意思是:我不管你的tool.js模块里面有什么,我直接就是想要把它们全导到obj中。
但是,es6的语法不支持你这么做(nodejs中的模块化在这一点就好的多)。
如果你是开发tool.js的人,也是就提供模块给他人来使用的人,你可以通过export default来给使用你模块的人一个结果,让他避免上述的错误。
基本使用
在tool.js中添加一句 exportdefaultname
let name = "tool.js"const version = "1.0.1"function updateDom (id,content) { document.getElementById(id).innerHTML = content}export default name; // 新加的。默认导出tool.jsexport { name, version, updateDom as modifyDom}
在index.js中使用:
// 把tool.js中默认导出的部分放在obj中import obj from "./tool.js"console.log(obj) // 输出tool.js
export default 只有一个
在tool.js中来两个export default,如下
let name = "tool.js"const version = "1.0.1"function updateDom (id,content) { document.getElementById(id).innerHTML = content}export default name; // 新加的export default {name, version}; // 再来一个,会报错export { name, version, updateDom as modifyDom}
一个模块中只能有一个默认导出,多了就会报错。
Uncaught SyntaxError: Identifier '.default' has already been declared
export default与export同时使用
在模块内部导出东东时,可以它们一起使用,如下
tool.js
let name = "tool.js"const version = "1.0.1"function updateDom (id,content) { document.getElementById(id).innerHTML = content}export default {version}; export { name, updateDom}
在导入模块时,分别去接收export default的内容 和export的内容。
在index.js中
import obj, {name, updateDom} from "./tool.js"console.log(obj) // 得到export default的内容 {version:'1.0.1'}console.log(name) // tool.jsconsole.log(updateDom) // function updateDom
小结
用一张表格来总结一下常见的用法
导出方式(a.js) | 导入方式 | |
export let name=''; export function f=function() | import {name,f} from './a.js' | 正确 |
export { name,f} | import {name,f} from './a.js' | 正确 |
export default {name,f} | import obj from './a.js' | 正确 |
export { name,f} | import obj from './a.js' | 错误 |
export {name,f}; export default {version}; | import obj, {name,f} from './a.js' | 正确 |
版权信息:凡人进阶。转载请标明出处。如果对您有帮助,您可以:
转发他人。
小额打赏。
关注本号。