FPS 게임을 해본 친구들은 완전히 조립된 M4 소총이 일반적으로 본체+소음기+돋보기+그립+스톡
으로 구성된다는 사실을 알아야 합니다. 枪身+消音器+倍镜+握把+枪托
。
如果把M4步枪看成是一个页面的话,那么我们可以做如下类比枪身 -> <main></main>
消音器 -> <header></header>
倍镜 -> <nav></nav>
握把 -> <aside></aside>
枪托 -> <footer></footer>
OK,你刚才做了一件事情,就是把m4步枪拆成了五个部分,你拆分的每一个部分就是一个模块【module】,你拆分的这个过程就是模块化【modularization】。
模块化是一种编程思想,其核心就是拆分任务,把复杂问题简单化,这样一来既方便多人分工协作,又可以帮助我们迅速定位问题
方便多人分工协作 —— 可以不同的人开发不同的模块,再组合,大大增加团队效率
帮助我们迅速定位问题 —— 后坐力太大,那八成是枪托或握把的问题;声音过大,那八成是消音器的问题。
下面用一个小栗子讲一讲模块化的发展史
龚先生和棚先生一起接了一个项目,他们俩需要分别实现一些功能,很简单,就是Console出来自己的变量a
于是他们俩一合计,安排龚先生的代码单独放在script1.js
里写,棚先生的代码单独放在script2.js
里写,然后用script标签分别引入
// script1.js文件 var a = 1 console.log(a)
// script2.js文件 var a = 2 console.log(a)
<!--HTML文件--> <script src="./script1.js"></script> <script src="./script2.js"></script>
很快他们遇到了第一个问题 —— 变量命名冲突
尤其是包含了异步的时候,会出现如下情况
// script1.js文件 var a = 1 setTimeout(()=>{ console.log(a) // 我们想console出来1,却console出了2 },1000)
// script2.js文件 var a = 2 console.log(a)
上面的问题明显是由于a是一个全局变量导致的,所以解决思路也很明确——造一个局部变量呗
ES5时代使用立即执行函数制造局部变量
// script1.js文件 !function(){ var a = 1 setTimeout(()=>{ console.log(a) // 这下是2了 },1000) }() // 下面有5000行代码
// script2.js文件 console.log(2)
ES6时代直接使用块级作用域+let
// script1.js文件 { let a = 1 setTimeout(()=>{ console.log(a) // 这下是2了 },1000) }
// script2.js文件 { let a = 2 console.log(a) }
后来公司招了一个前端大佬,说现在只能由他来控制什么时候console变量,于是他新建了一个control.js
文件
并通过window对象连接script1.js和scirpt2.js
// script1.js文件 { let a = 1 window.module1 = function() { console.log(a) } }
// script2.js文件 { let a = 2 window.module2 = function() { console.log(a) } }
// control.js文件 setTimeout(()=>{ window.module1() },1000) window.module2()
这个时候,非常重要的一点就是window是一个全局变量并且充当了一个公用仓库,这个仓库有两个关键作用,存【导出】
和取【依赖】
// script1.js文件 { let a = 1 // 把这个函数存放进window,就是导出到window window.module1 = function() { console.log(a) } }
// control.js文件 setTimeout(()=>{ // 我们从window里取出module1函数进行调用,就是依赖了script1.js文件 window.module1() },1000) window.module2()
烦人的产品对需求又进行了更改,给了一个name.js文件
// name.js文件 window.names = ['gongxiansheng','pengxiansheng']
要求现在龚先生和棚先生需要Console出自己的名字
这还不简单?几秒钟写好
// script1.js文件 { window.module1 = function() { console.log(window.names[0]) } }
// script2.js文件 { window.module2 = function() { console.log(window.names[1]) } }
// control.js文件 setTimeout(()=>{ window.module1() },1000) window.module2()
<!--HTML文件--> <script src="./script1.js"></script> <script src="./script2.js"></script>
但很快他们发现,console出来的都是undefined
前端大佬一眼看出了问题,对他们俩说你们依赖的代码一定要在你们自己的代码前引入,不然是取不到值的;你看我的control.js是不是在你们俩的代码后面引入的,因为我用到了你们俩的代码了呀
噢噢,原来是js文件加载顺序问题,改一下吧
<!--HTML文件--> <script src="./name.js"></script> <script src="./script1.js"></script> <script src="./script2.js"></script> <script src="./control.js"></script>
但是在人多了以后,我们到时候会搞不清楚到底谁依赖了谁,保险起见只能全部都加载,性能浪费了太多
총 본체-><main></main>
소음기-> ;header>
Multiplier-> <nav></nav>
그립->
Butt-> <footer></footer>
좋아요, 방금 m4 소총을 다섯 조각으로 분해하는 작업을 완료했습니다. 분할하는 부분은
모듈【모듈】입니다.
하는 것이 핵심인 프로그래밍 아이디어입니다. 이는 여러 사람 간의 작업 분담과 협업을 촉진할 뿐만 아니라 문제를 빠르게 찾는 데도 도움이 됩니다
1.2 모듈화의 피비린내 나는 역사다음은 모듈화의 개발 역사에 대해 이야기하는 작은 밤입니다.Gong 씨와 Sheng 씨는 함께 프로젝트를 맡았고 두 사람 모두 구현해야 했습니다. 몇몇 기능은 따로 간단해요.
콘솔이 자체 변수 a를 꺼내서 둘이서 공 선생님의 코드를 script1.js
에 따로 작성하도록 정리했는데, 그리고 Mr. Sheng의 코드는 script2.js로 작성된
에 별도로 작성하고 스크립트 태그를 사용하여 별도로 도입했습니다
// 命名导出 export { name1, name2, …, nameN }; export { variable1 as name1, variable2 as name2, …, nameN }; export let name1, name2, …, nameN; // also var export let name1 = …, name2 = …, …, nameN; // also var, const export function FunctionName() {...} export class ClassName {...} // 默认导出 export default expression; export default function (…) { … } // also class, function* export default function name1(…) { … } // also class, function* export { name1 as default, … }; // 将其它模块内的导出作为当前文件的导出 export * from …; export { name1, name2, …, nameN } from …; export { import1 as name1, import2 as name2, …, nameN } from …;
import defaultExport from "module-name"; // 导入默认默认变量 import * as name from "module-name"; // 将模块内所有变量导出,并挂载到name下【name是一个module对象】。什么要有as——为了防止export出来的变量命名冲突 import { export } from "module-name"; // 导入某一个变量 import { export as alias } from "module-name"; // 导入某一个变量并重命名 import { export1 , export2 } from "module-name"; // 导入两个变量 import { export1 , export2 as alias2 , [...] } from "module-name"; // 导入多个变量,同时可以给导入的变量重命名 import defaultExport, { export [ , [...] ] } from "module-name"; // 导入默认变量和多个其它变量 import defaultExport, * as name from "module-name"; // 导入默认变量并重新命名 import "module-name"; // 导入并加载该文件【注意文件内的变量必须要通过export才能被使用】 var promise = import(module-name); // 异步的导入
// name.js文件 let names = ['gongxiansheng','pengxiansheng'] export default names
변수 이름 충돌
특히 🎜async🎜가 포함된 경우 다음과 같은 상황이 발생합니다🎜// script1.js import names from './name.js' let module1 = function () { console.log(names[0]) } export default module1
// script2.js import names from './name.js' let module2 = function() { console.log(names[1]) } export default module2🎜위의 문제는 분명히 🎜a가 전역 변수🎜로 인해 발생하므로 해결 방법도 매우 명확합니다.
로컬 변수 만들기
🎜// control.js import module1 from './script1.js' import module2 from './script2.js' setTimeout(() => { module1() }, 1000) module2()
<!--HTML文件--> <script type="module" src="./control.js"></script> <!--注意一定要加上type="module",这样才会将这个script内的代码当做模块来对待-->🎜ES6 시대에는
블록 수준 범위+let
을 직접 사용했습니다🎜// module1.js export var foo = 'bar'; setTimeout(() => foo = 'baz', 500);
// module2.js import {foo} from './module1.js' console.log(foo) setTimeout(() => console.log(foo), 1000); // console的结果 // bar // baz
control.js
파일을 만들고 window 객체를 통해 script1.js와 scirpt2를 연결합니다. js🎜🎜// 报错 { export let foo = 'bar'; }
console.log(foo) import {foo} from './script1.js'rrreee🎜 이때 매우 중요한 점은 window가 🎜전역 변수🎜이며 🎜공용 창고🎜 역할을 한다는 점입니다. code>저장 [내보내기] 및 Get [종속성]🎜rrreeerrreee
정의되지 않음
이라는 것을 발견했습니다🎜프론트엔드 상사가 문제를 한눈에 보고 그들에게 말했습니다🎜코드 당신은 반드시 당신의 코드 앞에 삽입해야 합니다. 그렇지 않으면 내 control.js가 당신의 코드 뒤에 삽입되는지 확인하세요. 왜냐하면 내가 당신의 코드를 사용했기 때문입니다.
🎜 이런, 그렇군요. js 파일 로딩 순서에 문제가 있을 수 있으니 바꿔보겠습니다🎜rrreee🎜하지만 사람이 많아지면 누가 누구에게 의존하는지 알 수 없게 되니 안심하세요. 다 로드하면 성능낭비다
프론트엔드 사장이 고개를 저으며 한숨을 쉬었다🎜🎜2.ES6 모듈🎜🎜2.1 ES6 이전 모듈화의 문제점🎜🎜🎜🎜Variable 충돌🎜🎜🎜🎜각 모듈을 연결하려면 창을 사용해야 합니다🎜🎜🎜🎜 모든 종속 항목을 로드해야 합니다🎜🎜🎜🎜로딩 순서에도 주의해야 합니다🎜🎜🎜🎜모듈화는 이 게임의 가장 큰 특징 중 하나입니다. ES6, ES6🎜 이전에는 구문에 모듈식 시스템이 없었기 때문에🎜이 쌍 크고 복잡한 프로젝트를 개발하는 것은 큰 장애물🎜을 야기합니다. 프로젝트를 분할하여 더 나은 다중 사용자 공동 개발을 수행할 수 없기 때문입니다. 더 중요한 것은 🎜대부분의 다른 언어는 모듈성을 지원한다는 것입니다🎜. 🎜🎜언어가 지원하지 않는데 어떻게 JS에 모듈성을 도입할 수 있나요? 🎜🎜프런트 엔드 커뮤니티는 자체적으로 몇 가지 모듈 로딩 계획을 개발했습니다. 이는 CommonJS [서버]와 AMD 및 CMD [브라우저]의 기원이기도 합니다. 🎜🎜🎜但是现在ES6引入了模块化的功能,实现起来非常简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
import和export语法较为简单,大家去MDN可以看非常详细的讲解,笔者在这里知识用注释简单介绍一下
// 命名导出 export { name1, name2, …, nameN }; export { variable1 as name1, variable2 as name2, …, nameN }; export let name1, name2, …, nameN; // also var export let name1 = …, name2 = …, …, nameN; // also var, const export function FunctionName() {...} export class ClassName {...} // 默认导出 export default expression; export default function (…) { … } // also class, function* export default function name1(…) { … } // also class, function* export { name1 as default, … }; // 将其它模块内的导出作为当前文件的导出 export * from …; export { name1, name2, …, nameN } from …; export { import1 as name1, import2 as name2, …, nameN } from …;
import defaultExport from "module-name"; // 导入默认默认变量 import * as name from "module-name"; // 将模块内所有变量导出,并挂载到name下【name是一个module对象】。什么要有as——为了防止export出来的变量命名冲突 import { export } from "module-name"; // 导入某一个变量 import { export as alias } from "module-name"; // 导入某一个变量并重命名 import { export1 , export2 } from "module-name"; // 导入两个变量 import { export1 , export2 as alias2 , [...] } from "module-name"; // 导入多个变量,同时可以给导入的变量重命名 import defaultExport, { export [ , [...] ] } from "module-name"; // 导入默认变量和多个其它变量 import defaultExport, * as name from "module-name"; // 导入默认变量并重新命名 import "module-name"; // 导入并加载该文件【注意文件内的变量必须要通过export才能被使用】 var promise = import(module-name); // 异步的导入
// name.js文件 let names = ['gongxiansheng','pengxiansheng'] export default names
// script1.js import names from './name.js' let module1 = function () { console.log(names[0]) } export default module1
// script2.js import names from './name.js' let module2 = function() { console.log(names[1]) } export default module2
// control.js import module1 from './script1.js' import module2 from './script2.js' setTimeout(() => { module1() }, 1000) module2()
<!--HTML文件--> <script type="module" src="./control.js"></script> <!--注意一定要加上type="module",这样才会将这个script内的代码当做模块来对待-->
其实就是按照数据类型里的引用类型
的概念去理解。
这一点与 CommonJS 规范完全不同。
CommonJS 模块输出的是值的缓存
,不存在动态更新。
// module1.js export var foo = 'bar'; setTimeout(() => foo = 'baz', 500);
// module2.js import {foo} from './module1.js' console.log(foo) setTimeout(() => console.log(foo), 1000); // console的结果 // bar // baz
// 报错 { export let foo = 'bar'; }
console.log(foo) import {foo} from './script1.js'
参考资料:ECMAScript 6 入门
本文纯属原创,为了方便大家理解,小故事,小栗子都是笔者自己想的。如果您觉得对你有帮助,麻烦给个赞,给作者灰暗的生活挥洒挥洒积极向上的正能量,谢谢啦^_^。
相关推荐:
위 내용은 모듈이란 무엇입니까? ES6 모듈에 대한 깊은 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!