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></header>
Multiplier-> <nav></nav>
그립->
Butt-> <footer></footer>
좋아요, 방금 m4 소총을 다섯 조각으로 분해하는 작업을 완료했습니다. 분할하는 부분은
모듈【모듈】입니다.
하는 것이 핵심인 프로그래밍 아이디어입니다. 이는 여러 사람 간의 작업 분담과 협업을 촉진할 뿐만 아니라 문제를 빠르게 찾는 데도 도움이 됩니다</code ></p> <ul class=" list-paddingleft-2"></li><li>작업 분담과 여러 사람 간의 협업을 촉진합니다. - 여러 사람이 서로 다른 모듈을 개발한 다음 이를 결합하여 팀 효율성을 크게 높일 수 있습니다.<p></p></li></ol>빠르게 찾을 수 있도록 도와주세요. 문제 - 반동력이 너무 높습니다. 소리가 너무 크면 80%는 스톡이나 그립에 문제가 있고, 소리가 너무 크면 80%는 소음기에 문제가 있습니다. . <p><strong></ul></strong>1.2 모듈화의 피비린내 나는 역사<strong></strong>다음은 모듈화의 개발 역사에 대해 이야기하는 작은 밤입니다.<strong></strong>Gong 씨와 Sheng 씨는 함께 프로젝트를 맡았고 두 사람 모두 구현해야 했습니다. 몇몇 기능은 따로 간단해요. </p>콘솔이 자체 변수 a<blockquote></blockquote><p>를 꺼내서 둘이서 공 선생님의 코드를 <code>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
로컬 변수 만들기</code >🎜<h3>로컬 변수</h3>🎜ES5 시대에는 로컬 변수 생성을 위해 즉시 실행 함수를 사용했습니다🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">// control.js
import module1 from &#39;./script1.js&#39;
import module2 from &#39;./script2.js&#39;
setTimeout(() => {
module1()
}, 1000)
module2()</pre><div class="contentsignin">로그인 후 복사</div></div><div class="contentsignin">로그인 후 복사</div></div><div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;"><!--HTML文件-->
<script type="module" src="./control.js"></script>
<!--注意一定要加上type="module",这样才会将这个script内的代码当做模块来对待--></pre><div class="contentsignin">로그인 후 복사</div></div><div class="contentsignin">로그인 후 복사</div></div>🎜ES6 시대에는 <code>블록 수준 범위+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'
정의되지 않음
이라는 것을 발견했습니다🎜프론트엔드 상사가 문제를 한눈에 보고 그들에게 말했습니다🎜코드 당신은 반드시 당신의 코드 앞에 삽입해야 합니다. 그렇지 않으면 내 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!