前端模块的进化史
作为刚入门的前端开发人员,并不了解曾经的前端是如何进行开发的,更是在脚手架满天飞的现实中,对webpack打包,垫片等存在质疑,为什么打包成一个bundle.js就是合理的呢?import ('')与import '' 的区别在哪里?webpack是如何实现的?browersiry
阶段一:全局函数模式
function a() {}
function b() {}
function c() {}
function ...
- 开发人员在全局环境中定义变量多个函数,造成namespace污染,很容易命名冲突
阶段二:单例封装模式
let obj = {
msg2 : 'module2',
foo() {
console.log('xxxx)
}
}
- 减少了global的变量数量
- 本质还是对象,所有属性都是公开的,封装性差
阶段三 : 匿名闭包: IIFE模式
var module = (function(){
var a = 'name'
return {
return a
}
}())
阶段四 : 依赖引入
var module = (function($){
var Dom = {
a : $('#a')
}
return Dom
}(jQuery))
SMD(Synchronous Module Definition)
曾经的前端人员似乎有这样的困惑
// A工程师(创建导航)
var createNav = function() {
...
// B工程师(给导航添加引导图片)
...
// C工程师(对导航增加事件处理)
}
首先要吐槽的是 :
- 一个导航分三个人做,人员分配极其不科学
- 如果A永远的停留在创建导航过程,后面的人是不是要排队
为此,需要模块化的开发,即接口
``html
<script src="./A.js">
<script src="./B.js">
<script src="./C.js">
在A.js中
// IIFE
(function moduleA(window){
// 挂载到window对象中
window.moduleA = {
nav : document.getElementById('nav')
}
}(window))
然后,模块B也是通过window直接引用A暴露的接口
优缺点 :
- 优点 : 解决了开发人员开发功能的耦合,闭包使其模块内部更为安全
- 缺点 : 污染了window对象,当script标签多的时,http请求随之增多,影响首屏加载.
但是对于window对象来说,挂载到浏览器的原生对象上,也不是一个好的选择。
简单实现SMD
就是说,我想要实现以下数据结构,并用如下方法定义。
var modules = {
// a模块
a : {
name : 'aaaa'
},
b : {
name : 'cccccc'
}
}
F.defined('a.name',function(){
return 'aaaaa'
})
模块定义
var F = (function () {
// 模块缓存
var modules = {}
// 定义模块方法
var define = function (str, fn) {
var parts = str.split('.'),
pre,
current = modules
// 遍历路由模块
for (var i = 0; i < parts.length; i++) {
// 如果不存在当前模块,则声明当前模块
if (typeof current[parts[i]] === 'undefined') {
current[parts[i]] = {}
}
// 缓存上一级模块
pre = current
// 矫正当前模块
current = current[parts[i]]
}
if (fn) {
pre[parts[i - 1]] = fn()
}
// 打印当前模块
console.log(modules)
}
return {
define
}
}())
测试一下该方法
F.define('a.name', function () {
return 'aaaaaaa'
})
F.define('b.name', function () {
return 'bbbbbb'
})
打印成功
模块调用
对于模块的调用方法,参数分为两个部分,依赖模块与回调执行模块。如
F.module(['a','b'],function(a,b) {
console.log(a.name,b.name)
})
var module = function (depNames, callback) {
// 依赖模块名,统一作数组处理
var modNames = depNames instanceof Array ? depNames : [depNames],
deps = []
// 遍历模块
modNames.forEach(function (modName) {
var parts = modName.split('.'),
temp = modules
for (var i = 0; i < parts.length; i++) {
if (temp[parts[i]]) {
temp = temp[parts[i]]
} else {
console.log("Warnning : " + modName + 'not found')
return deps.push(undefined)
}
}
deps.push(temp)
})
callback && callback.apply(null, deps)
console.log('打印模块调用依赖', deps)
}
测试
F.module(['a', 'b'], function (a, b) {
console.log("回调了", a.name, b.name)
})
本章小结
模块化开发实际上是分治的思想,对系统功能进行分解,是系统随着功能增加而变得可控可维护。
实现模块化往往创建了大量的闭包,这会在内存中占用大量的资源。
但是,这种模式的最大缺点是,script标签必须依次加载,顺序不能乱,才能顺利进行。这对性能弱鸡的浏览器来讲,这是最大的痛点。
网友评论