2020-11-26

JS模块化

模块化是一个语言膨胀的必经之路,它能够帮助开发者拆分和组织代码。

module模块

在模块化之前

  1. 函数方式:一个函数就相当于一个模块,通过调用函数来引用模块

    这种做法的缺点很明显:"污染"了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关系。

  2. 对象方式:可以把模块写成一个对象,所有的模块成员都放到这个对象里面。

     var module1 = new Object({
    
        _count : 0,
    
        m1 : function (){
          //...
        },
    
        m2 : function (){
          //...
        }
    
      });
    

    样的写法会暴露所有模块成员,内部状态可以被外部改写。比如,外部代码可以直接改变内部计数器的值。

  3. 立即执行函数写法:可以达到不暴露私有成员的目的。

      var module1 = (function(){
    
        var _count = 0;
    
        var m1 = function(){
          //...
        };
    
        var m2 = function(){
          //...
        };
    
        return {
          m1 : m1,
          m2 : m2
        };
    
      })();
    

    module1就是Javascript模块的基本写法。下面,再对这种写法进行加工。

  4. 放大模式

      var module1 = (function (mod){
    
        mod.m3 = function () {
          //...
        };
    
        return mod;
    
      })(module1);
    

    以module1为参数,给他添加新的属性,方法,返回一个新的模块给module1

  5. 宽放大模式(Loose augmentation)

    在浏览器环境中,模块的各个部分通常都是从网上获取的,有时无法知道哪个部分会先加载。如果采用上一节的写法,第一个执行的部分有可能加载一个不存在空对象,这时就要采用"宽放大模式"。

    
    
      var module1 = ( function (mod){
    
        //...
    
        return mod;
    
      })(window.module1 || {});
    
  6. 输入全局变量

     var module1 = (function ($, YAHOO) {
    
        //...
    
      })(jQuery, YAHOO);
    

    上面的module1模块需要使用jQuery库和YUI库,就把这两个库(其实是两个模块)当作参数输入module1。这样做除了保证模块的独立性,还使得模块之间的依赖关系变得明显。

模块化规范

1. CommonJS

CommonJS主要用在Node开发上,每个文件就是一个模块,没个文件都有自己的一个作用域。通过module.exports暴露public成员。例如:

// 文件名:1.js
let a = 0;
function add(x, y) {
    return x + y
}
module.exports.a = a;
module.exports.add = add
//文件名:2.js
let x = require("./1");
console.log(x);
//{ a: 0, add: [Function: add] }

此外,CommonJS通过require()引入模块依赖,require函数可以引入Node的内置模块、自定义模块和npm等第三方模块。

从上面代码我们可以看出,require函数同步加载了1.js,并且返回了module.exports输出字面量的拷贝值。可能有人会问module.exports.x = x;不是赋值吗,怎么肥事呢?我们说,Module模式是模块化规范的基石,CommonJS也是对Module模式的一种封装。我们完全可以用Module模式来实现上面的代码效果:

let xModule = (function (){
  let x = 1;
  function add() {
    x += 1;
    return x;
  }
  return { x, add };
})();
let xm = xModule;
console.log(xm.x);  // 1
console.log(xm.add());  // 2
console.log(xm.x);   // 1

通过Module模式模拟的CommonJS原理,我们就可以很好的解释CommonJS的特性了。因为CommonJS需要通过赋值的方式来获取匿名函数自调用的返回值,所以require函数在加载模块是同步的。然而CommonJS模块的加载机制局限了CommonJS在客户端上的使用,因为通过HTTP同步加载CommonJS模块是非常耗时的。

2. AMD和CMD

AMD 推崇依赖前置,异步加载,CMD 推崇依赖就近。

AMD

基本语法

定义暴露模块

//定义没有依赖的模块
define(function(){
    return module
})
//定义有依赖的模块
define(['module1','module2'],function(m1,m2){
    return module
})

定义引入模块

CMD(不重要)
define(function(require, exports, module) {
  //  同步加载模块
  var a = require('./a');
  a.doSomething();
  // 异步加载一个模块,在加载完成时,执行回调
  require.async(['./b'], function(b) {
    b.doSomething();
  });
  // 对外暴露成员
  exports.doSomething = function() {};
});
// 使用模块
seajs.use('path');

CMD集成了CommonJS和AMD的的特点,支持同步和异步加载模块。CMD加载完某个依赖模块后并不执行,只是下载而已,在所有依赖模块加载完成后进入主逻辑,遇到require语句的时候才执行对应的模块,这样模块的执行顺序和书写顺序是完全一致的。因此,在CMD中require函数同步加载模块时没有HTTP请求过程。

ES6 module(很重要)

有两大特点:

  • 模块化规范输出的是一个值的拷贝,ES6 模块输出的是值的引用。
  • 模块化规范是运行时加载,ES6 模块是编译时输出接口。

模块化规范输出的是一个对象,该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,ES6 module 是一个多对象输出,多对象加载的模型。从原理上来说,模块化规范是匿名函数自调用的封装,而ES6 module则是用匿名函数自调用去调用输出的成员。
ES6模块化编译时就会确定依赖与输出,其他的模块化规范在运行时才会确定依赖和输出。

引入 import

暴露:export

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值