模块化发展历程

2019-11-06  本文已影响0人  dosher_多舍

什么是模块化?

模块化的理解

模块化是一种处理复杂系统分解为更好的可管理模块的方式。简单来说就是解耦,简化开发,一个模块就是实现特定功能的文件,可以更方便地使用别人的代码,想要什么功能,就加载什么模块。模块开发需要遵循一定的规范。

主要从IIFE、AMD、CMD、CommonJS、UMD、webpack(require.ensure)、ES Module 这几个角度考虑。

IIFE

IIFE( 立即调用函数表达式)是一个在定义时就会立即执行的 JavaScript 函数。特点:
在一个单独的函数作用域中执行代码,避免变量冲突

(function () {
    statements
})();
(function () { 
    var name = "Barry";
})();
// 无法从外部访问变量 name
name // 抛出错误:"Uncaught ReferenceError: name is not defined"


var result = (function () { 
    var name = "Barry"; 
    return name; 
})(); 
// IIFE 执行后返回的结果:
result; // "Barry"

AMD

AMD 即 Asynchronous Module Definition,中文名是“异步模块定义”的意思。在浏览器环境,要从服务器端加载模块,就必须采用非同步模式,因此浏览器端一般采用AMD规范。AMD是一个在浏览器端模块化开发的规范,而AMD规范的实现,就是require.js。特点:依赖必须提前声明好

// 定义
// 独立模块 es1.js
define({
    module1: function() {},
    module2: function() {},
});
// 等价写法
define(function () {
    return {
        module1: function() {},
        module2: function() {},
    };
});
// 非独立模块 只有先加载这两个模块,新模块才能正常运行 es2.js
define(['es1', 'es2'], function(m1, m2) {
       return {
        method: function() {
            m1.methodA();
            m2.methodB();
        }
    };
});

// 使用
require(['es1', 'es2'], function ( es1, es2) {
    es1.module1()
    es1.module2()
    es2.mothod()
});

CMD

CMD规范专门用于浏览器端,模块的加载是异步的,模块使用时才会加载执行。CMD规范整合了CommonJS和AMD规范的特点。在 Sea.js 中,所有 JavaScript 模块都遵循 CMD模块定义规范。特点:支持动态引入依赖文件。

// 定义
// 使用 exports 直接向外提供接口。
define(function(require, exports) { 
    // 对外提供 name属性
    exports.name = 'Tom'; 
    // 对外提供 say 方法
    exports.say= function(name) {
        console.log("hello"+name)
    };
});
// 使用 return 直接向外提供接口。
define(function(require) {  
    return {
        name : 'Tom',    
        say: function(name) {
            console.log("hello"+name)
        }
    };
});
// 使用 module.exports 直接向外提供接口。
define(function(require, exports, module) { 
    module.exports = {
        name: 'Tom', 
        say: function(name) {
            console.log("hello"+name)
        }
    };
});


// 使用
define(function (require) {
    var m1 = require('./module1')
    console.log(m1.name)      // Tom
    m1.say(m1.name)           // Hello Tom
})

// require.async 方法用来在模块内部异步加载模块,并在加载完成后执行指定回调。callback 参数可选。
define(function(require, exports, module) {  
    // 异步加载一个模块
    require.async('./module1', function(a) {
        a.doSomething();
    }); 

    // 异步加载多个模块,在加载完成时,执行回调
    require.async(['./module2', './module3'], function(b, c) {
        b.doSomething();
        c.doSomething();
    });
})

CommonJS

Node 应用由模块组成,采用 CommonJS 模块规范,前端的webpack也是对CommonJS原生支持的。每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。在服务器端,模块的加载是运行时同步加载的;在浏览器端,模块需要提前编译打包处理

// 定义

es1.js
var name = "Tom";
var age = 16;
function say(name,age){
   console.log(name+"is"+age+"years old")
}

// 语法1
module.exports.name = name;
module.exports.age = age;
module.exports.say = say;

// 语法2
exports.name = name;
exports.age = age;
exports.say = say;

// 语法3
module.exports = {
  name,
  age,
  say
}

// 语法4
module.exports = {
  name : "Tom",
  age : 16,
  say(name,age){
   console.log(name+"is"+age+"years old")
  }
}


// 引用
var module = require('./es1.js')
consolo.log(module.name)          //Tom
consolo.log(module.age)           //16
module.say(name,age)              //Tom is 16 years old

注:

UMD

UMD 叫做通用模块定义规范(Universal Module Definition)。也是随着大前端的趋势所诞生,它可以通过运行时或者编译时让同一个代码模块在使用 CommonJs、CMD 甚至是 AMD 的项目中运行。未来同一个 JavaScript 包运行在浏览器端、服务区端甚至是 APP 端都只需要遵守同一个写法就行了。是集结了 CommonJs、CMD、AMD 的规范于一身。

// UMD的实现
((root, factory) => {
    if (typeof define === 'function' && define.amd) {
        //AMD
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        //CommonJS
        var $ = requie('jquery');
        module.exports = factory($);
    } else {
        root.testModule = factory(root.jQuery);
    }
})(this, ($) => {
    //todo
});

不难发现,它在定义模块的时候回检测当前使用环境和模块的定义方式,将各种模块化定义方式转化为同样一种写法。它的出现也是前端技术发展的产物,前端在实现跨平台的道路上不断的前进,UMD 规范将浏览器端、服务器端甚至是 APP 端都大统一了

webpack(require.ensure)

webpack 2.x 版本中的代码分割

ES Module

ES6 在语言标准的层面上,实现了模块功能,而且非常简单,ES6到来,完全可以取代 CommonJS 和 AMD规范,成为浏览器和服务器通用的模块解决方案。ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。
注:由于ES6目前在部分版本的浏览器中无法执行,所以,我们需要通过babel将不被支持的import编译为当前受到广泛支持的 require。

// 定义

// 变量    es3.js
export var m = 1;
//函数
export function fn(x, y) {
  return x * y;
};
//类class
class Hello{
  test(){
    console.log("hello")
  }
}


// 也可以合并为一个出口暴露
var m = 1;
function fn(x, y) {
  return x * y;
};
class Hello{
  test(){
    console.log("hello")
  }
}
export {
  m,
  fn,
  Hello
}

// 在暴露模块时,可以通过 as 来进行重命名
export{
  num as m,
  foo as fn,
  Test as Hello
}


// 引用

//静态加载,只加载es3.js 文件中三个变量,其他不加载
import {m, fn, Hello} from './es3.js';
//import命令要使用as关键字,将输入的变量重命名。
import {fn as fn1} from './es3.js';
//整体加载模块
improt * as all from './es3.js'
console.log(all.m)              // 1
console.log(all.fn(3,4))        // 12
all.Hello.test()                // hello

特点:

模块化的好处

模块化的作用

上一篇下一篇

猜你喜欢

热点阅读