第25题 谈谈模块化的发展历程以及各自的特点

题目

谈谈模块化的发展历程以及各自的特点。

解析

Javascript不是一种模块化编程语言,但是随着前端的发展,对模块需求越来越大。
如今最常见的模块规范就是CommonJS、AMD、CMD

模块化的作用
  • 抽离公共代码,提高代码复用性
  • 隔离作用域,避免污染全局作用域
  • 避免变量冲突
立即执行函数(IIFE)

这是最早期的模块化手段。
特点:在一个单独的函数作用域中执行代码,避免变量冲突,污染全局作用域

(function(globalVariable) {
	globalVariable.test = function() {}
	// ... 声明各种变量、函数都不会污染全局变量
}) (globalVariable)
CommonJS

Node中自带的模块化,采用CommonJS模块规范。

  • 一个文件就可以是一个模块,使用require来引入、加载第三方模块;
  • 每个模块都有一个module对象,代表当前模块。其属性如下:
    在这里插入图片描述
  • module.exports属性是当前模块对外输出的接口,其他文件加载该模块,就是读取module.exports变量。(下面会有例子详解)
CommonJS实例

1、引入第三方模块并调用其方法:这里引用的是http模块。

 const http = require('http');
 const hostname = '127.0.0.1';
 const port = 8080;
 // 创建一个服务器对象
 const server = http.createServer((req, res) => {
 ...
 })
 server.listen(console.log(`运行http://${hostname}:${port}`))

2、CommonJS模块例子

  • 创建一个myModule.js文件

    //模块定义 myModule.js
    var name = 'Byron';
    function printName(){
        console.log(name);
    }
    function printFullName(firstName){
        console.log(firstName + name);
    }
    module.exports = {
        printName: printName,
        printFullName: printFullName
    }
    console.log(module);
    

    执行命令node myModule.js,可以看到模块自带的module对象:
    在这里插入图片描述

  • 再创建一个mk.js

    	//加载模块
    		var myModule = require('./myModule.js');
    		myModule.printName();
    

    这里的myModule就是对myModule.js文件中的module.exports对象的引用。

  • 执行命令 node mk.js,输出结果:Byron
    在这里插入图片描述

CommonJS特点
  • 主要用作服务端(node应用主要用于服务端)
  • 模块加载时同步的,即资源加载完在执行。(模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用)
  • 导出的值都是拷贝。就算导出的值变了,导入的值也不变。
AMD

AMD诞生原因:
因CommonJS是同步加载模块,对于服务端是友好的,但对于浏览器端是不能使用“同步加载”的。以免出现浏览器“假死”现象,所有有了AMD的诞生。

AMD规范(require.js使用的规范):采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。

  • AMD要想定义一个模块,必须使用define方法定义模块。

    如果该模块不依赖其他模块:

     // 无依赖时,定义模块
     define(function(){
     	...
     }
     return {
     	...
     }
     )
    

    如果该模块依赖其他模块:

     // 依赖其他模块
     // 第一个参数为数组,要指明其依赖
     define(['module1','module2'], function(m1, m2) {
     	...
     }
     return {
     	...
     }
     )
    

    上面的例子要想定义myModule.js模块就要像下面这样:

    // 定义模块myModule.js
    define( function() {
    	var name = 'Byron';
    	function printName(){
    	    console.log(name);
    	}
    	 return {
    	 	printName: printName
    	 }
    	})
    
  • AMD也采用require加载模块,但与CommonJS不同的是,require有两个参数:

    require([module], callback);
    

    第一个参数[module]是一个数组:它表示要加载的模块

    第二个参数callback:是一个回调函数,当模块加载完之后,所有依赖加载模块的语句就会在这个回调函数中执行。

    要想加载上面的myModule.js模块就像下面一样:

     // 加载myModule.js 模块
     require(['myModule'], function(myModule) {
     	myModule.printName();
     })
    
AMD特点:
  • 是Require.js的规范
  • 主要用于浏览器端
  • 必须使用define方法定义模块
  • 先定义所有的依赖,再加载完成后的回调函数中执行
  • 模块加载是异步的
CMD

CMD规范(Sea.js使用的规范)。同样用于浏览器端,也是异步加载模块。
与AMD不同的是,CDM是就近依赖,想用哪个模块时就加载哪个模块;而AMD 在定义模块的时候就要声明其依赖的模块。

  • CMD模块的定义:使用define方法定义模块

    	  define(function(require, exports, module){
    	  // ...
    	  // 可以在函数体内部任意地方使用require加载其所依赖的模块
    	  })
    

    第一个参数require: 可用来加载该模块所依赖的模块
    第二个参数exports与第三个参数module:都是作为暴露接口

    实例: 使用sea.js创建一个模块:myModule.js(关于sea.js这里不详说)

    define(function(require, exports) {
        // 对外提供name属性
        exports.name = 'myModule';
        // 对外提供hello方法
        exports.hello = function() {
          console.log('Hello myModule');
        };
    });
    
  • CMD模块的加载:
    创建一个html页面,其内部加载并调用myModule.js这个模块

    <!DOCTYPE html>
    <html>
        <head>
            <script type="text/javascript" src="sea.js"></script>
            <script type="text/javascript">
              //加载一个模块,在加载完成时,执行回调
              seajs.use('myModule', function(a) {
              	console.log(a.name);
                a.hello();
              });
            </script>
        </head>
        <body>
        </body>
    </html>
    
CMD的特点

从上面的例子中,我们可以看到CMD整合了AMD与CommonJS的特点 ,与AMD的模块定义和加载机制有些不同,但两者都用于浏览器。下面说说它的特点。

  • 是Sea.js的规范
  • 异步加载模块
  • 用于浏览器
  • 与AMD的区别:模块定义方式与加载模块机制不同。
  • CMD整合了AMD与CommonJS的特点
ES6模块

这个我们应该不陌生把,ES6实现了模块功能,完全可以取代CommonJS和AMD的规范,是浏览器与服务器通用的模块解决方式。

  • 采用import 导入模块

  • 采用export default 或者 export 导出模块

    // 引入模块 API
    import XXX from './a.js'
    import { XXX } from './a.js'
    // 导出模块 API
    export function a() {}
    export default function() {}
    
ES6模块特点
  • 浏览器与服务器通用
  • 异步导入
  • es6导出的是一个值的引用。导入值会跟随导出值变化
  • 该模块所依赖的模块都要先用import声明在顶部

最后附上一张超级经典的模块化发展的图,看完上面的讲解,下面的图就很清晰了。
详图点击 ->模块化
在这里插入图片描述

参考链接:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值