常见的模块化

前言

过去项目中会经常因为打包配置的问题而头疼,也有出现重复问题没有进行及时的总结而再次处理的时候找不到切入点,当然也为了能够更多的对webpack的掌握。所以在此做个简单的记录。

一、模块化
(一)、CommonJS
        1.简介

        CommonJS最初只为服务端而设计,直到有了Browserify——一个运行在Node.js环境下的模块打包工具,它可以将CommonJS模块打包为浏览器可以运行的单个文件。这意味着客户端的代码也可以遵循CommonJS标准来编写了。

        2.使用


// 导出方式一
exports.name = 'calculater';
exports.add = function(a, b) {
    return a + b;
};

// 导出方式二
module.exports = {
    name: 'calculater',
    add: function(a, b) {
        return a + b;
    }
};

/*
    在实现效果上,这段代码和上面的module.exports没有任何不同。
    其内在机制是将exports指向module.exports,而module.exports在初始化时是一个空对象。
    我们可以简单地理解为,CommonJS在每个模块的首部默认添加了以下代码
*/
var module = {
    exports: {},
};
var exports = module.exports;

// 导入方式一
require('./calculator.js');
// 导入方式二
const add = require('./calculator.js').add;
const name = require('./calculator.js').name;


// 注意
//在导出时容易犯的错误是不恰当地把module.exports与exports混用.
exports.add = function(a, b) {
    return a + b;
};
module.exports = {
    name: 'calculater'
};
/*
    上面的代码先通过exports导出了add属性,然后将module.exports重新赋值为另外一个对象。
    这会导致原本拥有add属性的对象丢失了,最后导出的只有name。
*/
        3. 特点
                a.缓存

                 我们前面提到,模块会有一个module对象用来存放其信息,这个对象中有一个属性loaded用于记录该模块是否被加载过。loaded的值默认为false,在模块第一次被加载和执行过后会置为true,后面再次加载时检查到module.loaded为true,则不会再次执行模块代码。

                b.动态

                 require函数可以接收表达式,借助这个特性我们可以动态地指定模块加载路径。

const moduleNames = ['foo.js', 'bar.js'];
moduleNames.forEach(name => {
    require('./' + name);
});
                c.值复制
(二)、ES6模块化
        1.简介

         ES6 Module也是将每个文件作为一个模块,每个模块拥有自身的作用域,不同的是导入、导出语句。ES6 Module会自动采用严格模式,该模式在ES5(ECMAScript 5.0)中只是一个可选项。

        2.使用
// 导出方式一
export const name = 'calculator';
export const add = function(a, b) { return a + b; };

// 导出方式二
const name = 'calculator';
const add = function(a, b) { return a + b; };
export { name, add };

// 导出方式三
export default {
    name: 'calculator',
    add: function(a, b) {
        return a + b;
    }
};

// 导出方式四
// 导出字符串
export default 'This is calculator.js';
// 导出 class
export default class {...}
// 导出匿名函数
export default function() {...}

// 导入方式一
import { name, add } from './calculator.js';

// 导入方式二
import { name, add as calculateSum } from './calculator.js';

// 导入方式三(默认导出)
import * as calculator from './calculator.js';

// 导入方式四(默认导出)
import calculator from './calculator.js';

// 导入方式五(默认导出)
import { default as myCalculator } from './calculator.js';

// 导入方式六
import React, { Component } from 'react';

// 复合写法(在工程中,有时需要把某一个模块导入之后立即导出,比如专门用来集合所有页面或组件的入口文件。此时可以采用复合写法)
export { name, add } from './calculator.js';

// 复合写法目前只支持被导入模块(这里的calculator.js)通过命名导出的方式暴露出来的变量,默认导出则没有对应的复合形式,只能将导入和导出拆开写。
import calculator from "./calculator.js ";
export default calculator;

        3.特点
                a.静态

                ES6 Module的导入、导出语句都是声明式的,它不支持将表达式作为导入路径,并且导入、导出语句必须位于模块的顶层作用域(比如不能放在if语句中)。

                b.动态映射
        4. 优势

        ·死代码检测和排除。我们可以用静态分析工具检测出哪些模块没有被调用过。比如,在引入工具类库时,工程中往往只用到了其中一部分组件或接口,但有可能会将其代码完整地加载进来。未被调用到的模块代码永远不会被执行,也就成了死代码。通过静态分析可以在打包时去掉这些未曾使用过的模块,以减小打包资源体积。

        ·模块变量类型检查。JavaScript属于动态类型语言,不会在代码执行前检查类型错误(比如对一个字符串类型的值进行函数调用)。ES6 Module的静态模块结构有助于确保模块之间传递的值或接口类型是正确的。

        ·编译器优化。在CommonJS等动态模块系统中,无论采用哪种方式,本质上导入的都是一个对象,而ES6 Module支持直接导入变量,减少了引用层级,程序效率更高。

(三)、AMD
        1.简介

        AMD(Asynchronous Module Definition,异步模块定义)是由JavaScript社区提出的专注于支持浏览器端模块化的标准。

        2.使用

        

// 定义
define('getSum', ['calculator'], function(math) {
    return function(a, b) {
        console.log('sum: ' + calculator.add(a, b));
    }
});

/*
    在AMD中使用define函数来定义模块,它可以接收3个参数。第1个参数是当前模块的id,相当于模块名;
    第2个参数是当前模块的依赖,比如上面我们定义的getSum模块需要引入calculator模块作为依赖;
    第3个参数用来描述模块的导出值,可以是函数或对象。
    如果是函数则导出的是函数的返回值;如果是对象则直接导出对象本身。
*/
// 使用
require(['getSum'], function(getSum) {
    getSum(2, 3);
});
/*
    require的第1个参数指定了加载的模块,第2个参数是当加载完成后执行的回调函数。
*/
(四)、UMD
        1.简介

        严格来说,UMD并不是一种模块标准,而是一组模块形式的集合。UMD的全称是Universal Module Definition,也就是通用模块标准,它的目标是使一个模块能运行在各种环境下,不论是CommonJS、AMD,还是非模块化的环境(当时ES6Module还未被提出)。

        2.使用
// calculator.js
(function (global, main) {
    // 根据当前环境采取不同的导出方式
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(...);
    } else if (typeof exports === 'object') {
        // CommonJS
        module.exports = ...;
    } else {
        // 非模块化环境
        global.add = ...;
    }
}(this, function () {
    // 定义模块主体
    return {...}
}));

/*
    可以看出,UMD其实就是根据当前全局对象中的值判断目前处于哪种模块环境。
    当前环境是AMD,就以AMD的形式导出;当前环境是CommonJS,就以CommonJS的形式导出。
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值