脚本宝典收集整理的这篇文章主要介绍了

Web前端模块化方法

脚本宝典小编觉得挺不错的,现在分享给大家,也给大家做个参考,希望能帮助你少写一行代码,多一份安全和惬意。
<p><code></p> <h1 id="articleHeader0">前端模块化</h1> <h2 id="articleHeader1">1. 模块化优点</h2> <p>目前由于MVVM模式的流行,各种语言都更注重模块化。模块化设计的好处:</p> <ol> <li>作用域:避免全局变量污染;</li> <li>复用:可重复利用封装的模块为不同地方实现相同功能;</li> <li>解耦:减少不同功能代码相互关联性,让代码分工明确,也方便Debug;</li> <li>按需加载:加快加载速度、异步加载不必要的部分;</li> </ol> <h2 id="articleHeader2">2. 模块化方法整理</h2> <p>从最早的script标签开始,前端模块化经过了多种编程方案的演化,逐步完善。</p> <h3 id="articleHeader3">2.1 script标签</h3> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="<a href="http://www.js-code.com/tag/button" title="button" target="_blank">button</a>" <a href="http://www.js-code.com/tag/class" title="class" target="_blank">class</a>="copyCode code-tool" data-toggle="tooltip" data-placement="<a href="http://www.js-code.com/tag/top" title="top" target="_blank">top</a>" data-clipboard-<a href="http://www.js-code.com/tag/text" title="text" target="_blank">text</a>="<script src=&quot;module_a.js&quot;></script><br /> <script src=&quot;module_b.js&quot;></script><br /> <script src=&quot;main.js&quot;></script>" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs xml"><code><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"module_a.js"</span>&gt;</span><span class="undefined"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"module_b.js"</span>&gt;</span><span class="undefined"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"ma<a href="http://www.js-code.com/tag/in" title="浏览关于“in”的文章" target="_blank" class="tag_link">in</a>.js"</span>&gt;</span><span class="undefined"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre> <p>所有的js文件共享全局作用域,容易引起作用域污染。</p> <h3 id="articleHeader4">2.2 闭包函数(立即执行函数)</h3> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="(function(){ // xxx })()" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs clojure"><code>(<span class="hljs-name"><a href="http://www.js-code.com/tag/function" title="浏览关于“function”的文章" target="_blank" class="tag_link">function</a></span>(){ // xxx })()</code></pre> <p>这是笔者早年使用最多的js编程方式 0_0</p> <p>虽然避免了作用域污染的问题,但多个文件内的函数互相调用时,处理较为麻烦。常用方法是:</p> <ol> <li>在闭包内定义一个 <code>w<a href="http://www.js-code.com/tag/in" title="in" target="_blank">in</a><a href="http://www.js-code.com/tag/do" title="do" target="_blank">do</a>w.myFunc = <a href="http://www.js-code.com/tag/function" title="function" target="_blank">function</a>(){}</code> 的方法,在闭包外可以调用;</li> <li>使用事件监听,给需要外部调用的方法设置事件,从外部触发事件;介绍一种自定义事件来控制闭包函数间传值的方法:</li> </ol> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="<a href="http://www.js-code.com/tag/button" title="button" target="_blank">button</a>" <a href="http://www.js-code.com/tag/class" title="class" target="_blank">class</a>="copyCode code-tool" data-toggle="tooltip" data-placement="<a href="http://www.js-code.com/tag/top" title="top" target="_blank">top</a>" data-clipboard-<a href="http://www.js-code.com/tag/text" title="text" target="_blank">text</a>="// 利用闭包函数自定义一个事件监听触发机制<br /> // 自定义机制,不会受到默认的事件影响<br /> <a href="http://www.js-code.com/tag/var" title="var" target="_blank">var</a> EventManager = (<a href="http://www.js-code.com/tag/function" title="function" target="_blank">function</a>() {<br /> <a href="http://www.js-code.com/tag/var" title="var" target="_blank">var</a> <a href="http://www.js-code.com/tag/event" title="event" target="_blank">event</a>s = {}<br /> <a href="http://www.js-code.com/tag/return" title="return" target="_blank">return</a> {<br /> add: <a href="http://www.js-code.com/tag/function" title="function" target="_blank">function</a>(<a href="http://www.js-code.com/tag/name" title="name" target="_blank">name</a>, fn) {<br /> <a href="http://www.js-code.com/tag/if" title="if" target="_blank">if</a>(!<a href="http://www.js-code.com/tag/event" title="event" target="_blank">event</a>s[<a href="http://www.js-code.com/tag/name" title="name" target="_blank">name</a>]){<br /> <a href="http://www.js-code.com/tag/event" title="浏览关于“event”的文章" target="_blank" class="tag_link">event</a>s[<a href="http://www.js-code.com/tag/name" title="浏览关于“name”的文章" target="_blank" class="tag_link">name</a>] = [];<br /> }<br /> events[name].push(fn);<br /> },<br /> fire: <a href="http://www.js-code.com/tag/function" title="function" target="_blank">function</a>(name, args) {<br /> <a href="http://www.js-code.com/tag/var" title="浏览关于“var”的文章" target="_blank" class="tag_link">var</a> fnList = events[name];<br /> <a href="http://www.js-code.com/tag/if" title="if" target="_blank">if</a>(fnList){<br /> <a href="http://www.js-code.com/tag/for" title="for" target="_blank">for</a> (var i = 0, l = fnList.<a href="http://www.js-code.com/tag/length" title="length" target="_blank">length</a>; i < l; i++) { var fn = fnList[i]; if (fn &amp;&amp; typeof fn == 'function') { fn(args); } } } } } })() // 在闭包内监听,可调用闭包内方法 (function() { EventManager.add('user.login', function(data) { console.log('user.login', data) }) })() // 在任意位置触发 EventManager.fire('user.login', {name: 'lc'})" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs javascript"><code><span class="hljs-comment">// 利用闭包函数自定义一个事件监听触发机制</span> <span class="hljs-comment">// 自定义机制,不会受到默认的事件影响</span> <span class="hljs-keyword">var</span> EventManager = (<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">var</span> events = {} <span class="hljs-keyword"><a href="http://www.js-code.com/tag/return" title="浏览关于“return”的文章" target="_blank" class="tag_link">return</a></span> { <span class="hljs-attr">add</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">name, fn</span>) </span>{ <span class="hljs-keyword"><a href="http://www.js-code.com/tag/if" title="浏览关于“if”的文章" target="_blank" class="tag_link">if</a></span>(!events[name]){ events[name] = []; } events[name].push(fn); }, <span class="hljs-attr">fire</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">name, args</span>) </span>{ <span class="hljs-keyword">var</span> fnList = events[name]; <span class="hljs-keyword">if</span>(fnList){ <span class="hljs-keyword"><a href="http://www.js-code.com/tag/for" title="浏览关于“for”的文章" target="_blank" class="tag_link">for</a></span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>, l = fnList.<a href="http://www.js-code.com/tag/length" title="浏览关于“length”的文章" target="_blank" class="tag_link">length</a>; i &lt; l; i++) { <span class="hljs-keyword">var</span> fn = fnList[i]; <span class="hljs-keyword">if</span> (fn &amp;&amp; <span class="hljs-keyword"><a href="http://www.js-code.com/tag/typeof" title="浏览关于“typeof”的文章" target="_blank" class="tag_link">typeof</a></span> fn == <span class="hljs-string">'function'</span>) { fn(args); } } } } } })() <span class="hljs-comment">// 在闭包内监听,可调用闭包内方法</span> (<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ EventManager.add(<span class="hljs-string">'user.login'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">data</span>) </span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'user.login'</span>, data) }) })() <span class="hljs-comment">// 在任意位置触发</span> EventManager.fire(<span class="hljs-string">'user.login'</span>, {<span class="hljs-attr">name</span>: <span class="hljs-string">'lc'</span>})</code></pre> <p>自定义事件监听,相对于<a href="http://www.js-code.com/tag/window" title="window" target="_blank">window</a>下的函数,更加灵活,也更符合模块化的思想。举个例子:<br />通信系统中,用户登录后,需要获取聊天记录、通信录、个人信息,这些分别在不同的模块(闭包)中。<br />如果用函数的思想,需要在登录的地方进行不同的方法调用,这样就使得登录模块与多个业务模块产生了耦合;如果用自定义事件的方法,登录后只需要广播一个事件,同时在多个业务模块分别监听事件,各模块间就完全没有耦合,就算任意删掉一个模块也可以保证其他模块正常运行。</p> <p><strong>存在问题:</strong></p> <p>不论是全局函数、全局事件、自定义事件,在调用每个闭包中的方法时,斗需要确保该闭包先执行后调用。在复杂项目中,需要先执行大量闭包函数,会导致启动慢、逻辑复杂等各种问题。</p> <h3 id="articleHeader5">2.3 AMD - 异步模块定义</h3> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="define('myfunc', ['math'], function(math) { math.sum(1, 2) });" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs lisp"><code>define('myfunc', ['math'], function(<span class="hljs-name">math</span>) { math.sum(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>) })<span class="hljs-comment">;</span></code></pre> <p>通过 <code>def<a href="http://www.js-code.com/tag/in" title="in" target="_blank">in</a>e</code>函数引入需要的依赖包,每个模块所依赖的包/模块一目了然。</p> <h3 id="articleHeader6">2.4 CMD - 通用模块定义</h3> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="define(function(require, exports, module) { const math = require('math') math.sum(1, 2) })" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs lisp"><code>define(<span class="hljs-name">function</span>(<span class="hljs-name">require</span>, <a href="http://www.js-code.com/tag/export" title="浏览关于“export”的文章" target="_blank" class="tag_link">export</a>s, module) { <a href="http://www.js-code.com/tag/const" title="浏览关于“const”的文章" target="_blank" class="tag_link">const</a> math = require('math') math.sum(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>) })</code></pre> <p>CMD的原则是将引入模块尽量后置,在使用的时候才去引入。<br />这样使得js执行时效率更高,更符合lazy load的思维方式,但对代码管理确不是很方便。</p> <h3 id="articleHeader7">2.5. CommonJS</h3> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="const math = require('math') module.exports = function() { math.sum(1, 2) }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs lua"><code>const <span class="hljs-built_in">math</span> = <span class="hljs-built_in">require</span>(<span class="hljs-string">'math'</span>) module.exports = <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span></span> { <span class="hljs-built_in">math</span>.sum(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>) }</code></pre> <p>目前NodeJS的模块管理常用的就是这种方式,很多NPM的包也是这样处理的模块引入。</p> <h3 id="articleHeader8">2.6 ES6的模块化</h3> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="import { myFunc1, myFunc2 } from 'myFuncs'; import Vue from 'vue'; export function hello() {}; export default { // ... };" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs javascript"><code><span class="hljs-keyword">import</span> { myFunc1, myFunc2 } <span class="hljs-keyword">from</span> <span class="hljs-string">'myFuncs'</span>; <span class="hljs-keyword">import</span> <a href="http://www.js-code.com/tag/vue" title="浏览关于“Vue”的文章" target="_blank" class="tag_link">Vue</a> <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>; <span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">hello</span>(<span class="hljs-params"></span>) </span>{}; <span class="hljs-keyword">export</span> <span class="hljs-keyword"><a href="http://www.js-code.com/tag/default" title="浏览关于“default”的文章" target="_blank" class="tag_link">default</a></span> { <span class="hljs-comment">// ...</span> };</code></pre> <p><a href="http://www.js-code.com/tag/vue" title="Vue" target="_blank">Vue</a>、<a href="http://www.js-code.com/tag/react" title="React" target="_blank">React</a>等常用框架目前都在使用这种模块化方法。</p> <p>比如在vue中,配合vue-router,在组件中按需<a href="http://www.js-code.com/tag/import" title="import" target="_blank">import</a>模块或模块中的函数,可以通过webpack实现按需加载。同时,这种模块化方式使得模块间的方法调用更加方便,不需要考虑模块声明前后顺序,因为webpack会自动生成依赖树。</p> <h3 id="articleHeader9">2.7 样式文件模块化</h3> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="// util.less .common { color: pink; } // main.less @import 'util.less' .red { color: red; }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs scala"><code><span class="hljs-comment">// util.less</span> .common { color: pink; } <span class="hljs-comment">// main.less</span> <span class="hljs-meta">@import</span> <span class="hljs-symbol">'util</span>.less' .red { color: red; }</code></pre> <p>样式文件目前也支持模块化。</p> <hr> <p>参考:《深入浅出Webpack》</p> <p></code></p>

总结

以上是脚本宝典为你收集整理的

Web前端模块化方法

全部内容,希望文章能够帮你解决

Web前端模块化方法

所遇到的程序开发问题,欢迎加入QQ群277859234一起讨论学习。如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典网站推荐给程序员好友。 本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。

80%的人都看过