听叔一句劝,这里面水太深,历数模块化开发,你把握的住吗?
Posted 贪吃ღ大魔王
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了听叔一句劝,这里面水太深,历数模块化开发,你把握的住吗?相关的知识,希望对你有一定的参考价值。
文章目录
闲言碎语
持续三天,肝爆了三篇的入门系博文,效果确是那么差强人意,勉强上了热榜,所以今后我还是打算从博文质量下功夫,相比大佬们的一篇一热门,我呢?三篇一热门,但、还是默默选择了肝。正如:深耕于技术写博,致力于前端开发。今后仍是每天一篇有意义的博文,持续更新中…
一、投石问路
1.1 模块化开发起始
⭐这里我先抛出一个问题:什么是模块化开发?
相信应该都知道的吧,哪怕知识入门者也会听说过。
那什么叫模块化开发嘞,一个js文件封装的一类内容,多个js文件之间互相配合完成功能。这种开发模式就是模块化开发了。
⭐为什么需要模块化开发?
我从来从这方面来开始分析:
当我们开发一个功能,需要用到很多函数的时候,会引入工具库文件,它里面会有很多的函数,但是我们在用的时候,却没有使用工具库文件中的所有函数,只是使用了它其中的一部分函数。这样的话就造成了一定的浪费了。
当然,为了解决不造成浪费这个问题,我们可以将其中操作一类型的函数放在一个单独的文件中,当我们需要进行这一类操作的时候,只引入这一个文件就可以了,就不需要引入它里面的所有函数了。
1.2 起始开发方式
⭐然后这里再聊一下 模块化的发展历史吧
1995年以后才有了前端这样的代码,最早期的开发者开发 写一个html文件 写css 再写一个js文件 引入一大堆文件。
但是这种开发有最大的弊端 ,一个文件引入十几个css js文件 ,这些文件先引入谁 后引入谁 ,中间有没有覆盖关系 ,其中有没有定义过全局变量 ,定义变量会不会影响原来的文件 , 因为只从两个文件中 到底是谁依赖谁 到底里面定义了哪些东西 我定义的话应该怎么去做 。
大家想 : 我什么也不知道 我以后每次定义变量 需要把每个文件打开 先分析一遍 变量会不会覆盖 有没有被定义。
最早期没有模块化 ,开发者都是一个html引入多个js文件操作,从这点来看 看不出什么优点
缺点呢?
- 不知道依赖了哪个文件
- 第二点是会造成全局变量的污染
- 最后就是依赖关系不够清晰
从文件描述中,很难看出来依赖关,每个文件中 全局污染情况不清晰,不知道哪些变量是否该定义,不该定义 。
1.3 IIFE伪模块化规范
⭐ 95-2000多年的开发者 比较厉害 打开每个源文件 把里面的文件都看懂以后再写 由于网景: 慢慢有了前端 好多后端工程师跳槽转做前端, 前端好做比较简单,忽然发现前端比较low 连模块化开发都没有,以后看代码还要一个一个打开看 还不如写后端去 他们希望前端具有模块化开发,他们开发了一个 IIFE的伪模块化开发,将js代码放在一个自调用函数中,形成私有作用于,来模拟模块化,(Immediately Invoked Function Expression)的伪模块化规范。
Immediately Invoked Function Expression,意为立即调用的函数表达式
使用自调用函数模拟模块,解决部分问题,全局污染问题解决了,但是:
缺点:依赖关系依然不清晰
后端工程师:我尽力了!~
自调用函数
⭐ 只要是函数 就会创建作用域 有a变量 再全局的话 暴露容易污染全局 函数定义a 和外面定义a 不会冲突,这就把依赖关系解决的差不多,把全局污染给解决了 但是再今后使用这些文件的时候 还是看不出来谁依赖谁
(function(){
let a = 10;
console.log(a);
function aa(){
console.log("这是a文件中的aa函数");
}
window.a = {
aa
}
})()
(function(a){
let b = 20;
console.log(b);
// 需要调用a.js中的aa函数
// aa()
a.aa()
function bb(){
console.log("这是b文件中的bb函数");
}
function bb2(){
console.log("这是b文件中的bb2函数");
}
function bb3(){
console.log("这是b文件中的bb3函数");
}
window.b = {
bb,
bb2,
bb3
}
})(a)
再到后面越来越多的人吐槽前端没有模块化开发规范,官方收到这些信息后 认为这些人小题大作,因为官方认为:js就这么一点代码,难道没有模块化开发就不能开发了吗? 他觉得这个东西不需要。
1.4 AMD模块化规范
⭐ 后来的话 有一个社区,提倡我们要开发一个模块化规范,它叫做AMD(Asynchronous Module Definition)
由社区发起的模块化标准。但由于不是官方,在js中不能添加关键字,所以写了一个叫做require.js
的第三方文件。2011年出现。
这个规范它做了这样一个事儿:
它提供了两个函数
define(function(){
return 对象
}) // 定义模块
/ 如果定义模块的文件也需要依赖别的文件
define(['依赖的文件路径'],function(自定义的模块名称){
return 对象
})
require(['引入的文件路径'],function(自定义的模块名称){
模块名称其实就引入的文件中return的对象
}) // 引入模块
一个叫做 define() 定义模块:
define方法定义独立模块,即不需要依赖其他文件的模块 - 参数是一个函数,需要向外暴露的内容,return出去即可,语法如下:
define(function(){
需要向外暴露的内容,return出去即可 - 导出内容
return {
num,
f1
}
})
define方法也可以定义依赖其他模块的模块,语法:
define(['依赖文件1','依赖文件2',...],function(模块1,模块2,...){
这里就可以使用依赖的模块中的内容了,每个模块变量就是导出的内容
需要向外暴露的内容,return出去即可
})
一个叫 require() 引入模块:
require方法,导入其他模块,将导入的文件路径组成一个数组,作为require的参数1,参数2是一个函数,函数中就能使用导入的模块中的内容,函数的参数是模块名称,语法如下:
require(['依赖文件1','依赖文件2',...],function(模块1,模块2,...){
})
这里就可以使用依赖的模块中的内容了,每个模块变量就是导出的内容
define(function(){
let a = 10;
console.log(a);
function aa(){
console.log("这是a文件中的aa函数");
}
for(var i=0;i<=10000;i++){
console.log(1);
}
// return 数据
return {
a,
aa
}
})
AMD
在这里引入a文件
require(['./18-a'],function(moduleA){
console.log(789789789789789789);
console.log("a文件中的变量a是"+moduleA.a);
console.log('------------');
console.log("调用a文件中的aa函数:");
moduleA.aa()
let b = 20;
console.log(b);
function bb(){
console.log("这是b文件中的bb函数");
}
bb()
})
最终,html只需要引入这个文件即可,其他依赖的模块不需要引入
多个文件依赖一个文件,这个文件只会执行一次。
需要向外暴露的内容,return出去即可,在html中只需要引入最后一个即可
这样的话,我用一个js函数就能引入两一个js中定义好的模块,也就解决了什么问题? 让js文件可以引入js文件了
依赖关系变得清晰了 define会定义模块再引入进来
但是它还是有一个遗憾吧: 它是由这个社区发起的 不是官方啊 所以js中没有给它设置关键字 所以就造成了 我们使用AMD规范 就必须先引入一个叫做 require.js的文件
缺点:
最终引入的这个index文件,它依赖于前面所有的文件,当你引入index文件是 需要先把以前的文件都加载一遍 最后再执行这个index, 这叫做依赖前置 ,这就造成了,我第一次打开页面的时候,好多文件才开始加载,我需要等待很长时间,我的第一屏的屏幕上的页面才展示出来,造成首屏加载特别满,但是后续的操作的话就特别流畅了,因为所有文件已经加载过了。
二、醍醐灌顶
2.1 CMD模块化规范
⭐ 后来呢,有一个当时特别nb的人 ,他说你们要开发就好好开发,一群人守在一起开发这样一个有缺点的东西,于是,这个人就开发了CMD。
⭐ 这个人是谁呢 在以前我们把他叫做 ‘玉伯’ 这是他的艺名 ,他是阿里的工程师,他在以前在IT界呢也是非常厉害 类似于现在大家都知道的 阮一峰 ,廖雪峰这些人的地位 ,经常会写一些博客,发表技术类的东西,以前的这些工程师上网看博客的话都是看玉伯的,玉伯的话就是金科玉律,所以还是很牛批的。
CMD规范 玉伯一个人开发的,由玉伯2011年书写了一个sea.js文件。
当然呢 玉伯也不是官方
使用方式:需要先引入sea.js的文件
通过define方法定义独立模块,语法:
define(function(require,exports,module){
require用来导入其他模块文件
module.exports用来导出当前文件中的数据
exports是modules.exports的引用
})
define方法也可以定义依赖其他模块的模块,语法:
define(function(require,exports,module){
require用来导入其他模块文件 - 如果有依赖模块,就使用require来导入
module.exports用来导出当前文件中的数据
exports是modules.exports的引用
})
通过seajs.use()来导入其他模块文件,语法:
seajs.use(['需要依赖的其他模块文件-可选项'],function(模块名称){
})
这里的依赖模块是可选项,可以有前置依赖,也可以没有
最终只需要引入这一个文件就好了
require用来引入文件 - 实现了按需加载
module.exports 就用来导出数据
define(function(require,exprts,module){
/ exports = module.exports
})
seajs.use(文件,function(模块名称){
/使用模块中数据
})
define(function(require,exports,module){
let a = 10;
console.log(a);
function aa(){
console.log("这是a文件中的aa函数");
}
// require实现按需加载
console.log( require('20-test.js').str)
for(var i=0;i<=10000;i++){
console.log(1);
}
module.exports = {
a,
aa
}
})
CMD
导入a文件
seajs.use('./18-a.js',function(a){
console.log(789789789);
a.aa()
})
解决了AMD的依赖前置,可以按需加载
解决了问题:
- 依赖前置
- 首屏加载很快
问题:后续操作不够流畅,因为CMD标准是什么时候需要,什么时候才加载。
⭐缺点的话,还是没有关键字啊 但是已经很完美了
三、九九归一
⭐⭐在以前的话,模块化开发火到什么程度呢 你只要敢说你是一个工程师,就不敢说自己没听说过CMD
AMD 和CMD 大概是在11年左右 ,官方后期有了ES6的时候,开发了es6的模块化规范,但是只能在服务器环境使用,也就是http协议使用它,因为初期官方对AMD和CMD的置之不理 ,大家对官方比较失望,虽然它开发出来的es6模块话开发还不错,但是却没有人去用,因为浏览器还是比较牛的,他们并不兼容这个es6模块化规范,所以es6也就一直不愠不火,一直到18年的时候 vue火到不行,vue内置的es6模块化开发,浏览器厂商不得不兼容es6了,谷歌最先兼容了这个es6模块化规范.
3.1 Commonjs
09年的时候呢 nodejs 出来了 nodejs也内置了模块化开发规范:CinnibJS规范 只能在nodejs中使用。
提供了导出和导入的语法:
导入注意:
require(要导入的文件路径)
- 导入的路径中, ./ 千万不能省略
- 文件的后缀可以省略
导出:
module.exports = {数据}
导出注意:
导出的方式
module.exports = {}
module.exports.a = a;
exports.a = a
模块的分类:
1.自定义模块
2.内置的模块 - nodejs自带的
3.内置模块
3.2 es6的模块化
🌙官方后期有了es6的时候,开发了es6的模块化规范 - 只能在服务器环境使用。
特点:
- 有了js关键字
- 依赖前置
- 服务器打开,浏览器支持不好
- script标签上添加type=“module”
#在服务器环境中使用es6的模块化规范,首先必须在script标签上添加type属性:
<script type="module"></script>
导出数据:
export default 数据 / 一个文件只能导出这样一个数据
export 定义数据 / 导出多个数据
export default { / 将多个数据组成一个对象,导出一次
数据 as 别名
}
导入:
import 变量名 from '模块文件路径'
import {解构具体数据} from '模块文件路径'
import * as 变量名 from '模块文件路径';
CSDN技术交流群: 不限萌新大佬,欢迎加入我们的技术圈。
QQ交流群:925570980
微信群:
博主快肝不动了,喜欢的朋友们可以收藏,一键三连,就是最大的鼓励和支持啊~ 巴适呆板!!
深耕于技术写博,致力于前端开发。
以上是关于听叔一句劝,这里面水太深,历数模块化开发,你把握的住吗?的主要内容,如果未能解决你的问题,请参考以下文章