【深入学习JS】09_前端模块化

CommonJS

特点

只能用于服务端。脚本被require时就会执行模块中的代码,这个特性在服务端没有问题,但是如果引入一个模块就要等待他执行完才能执行后面的代码,在浏览器端就会有很大的问题。已加载的模块不会重复加载

声明

// 方式1
module.exports.add = function(){}

// 方式2
module.exports = {
    add: function(){}
}

// 方式3
exports.add = function(){}

// 默认导出
module.exports = function(){}

使用

// 方式1、2、3对应的导出方式
const math = require('./math');
math.add();

// 默认导出
const test = require('./math');
test();

循环依赖

  • require的模块会立即执行;
  • 已加载的模块不会重复加载。
// a.js
console.log('a starting');
exports.done = false;
const b = require('./b.js');
console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');

// b.js
console.log('b starting');
exports.done = false;
const a = require('./a.js');
console.log('in b, a.done = %j', a.done);
exports.done = true;
console.log('b done');

// main.js
console.log('main starting');
const a = require('./a.js');
const b = require('./b.js');
console.log('in main, a.done=%j, b.done=%j', a.done, b.done);
  • 执行main.js首先输出main starting
  • 引入a模块,立即执行,打印出a starting,此时a.done = false
  • a模块中引入b模块,立即执行,打印出b starting,此时b.done = false
  • 由于已经加载过a模块,所以被缓存,缓存的值是false,故打印in b, a.done = false
  • b模块导出done = true,并打印b done
  • 回到a模块,由于已经加载过b模块,所以b的值是true,即in a, b.done = true
  • a模块导出done = true,并打印a done
  • 回到maina b模块都已经被执行和缓存,直接打印in main, a.done=true, b.done=true

故最后的打印结果应该是:

main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
in main, a.done = true, b.done = true

module.exoprts 和 exports的区别

// module的实现
var module = {
    id: 'xxx',        // module的唯一识别,类似id
    exports: {}
}
var exports = module.exports;

从上面的例子可以看出, exports=module.exports,两者都指向了同一个内存地址,所以module.exports改变,exports也会改变;但是若是对exports直接赋值,两者就不会指向同一个内存地址,故修改不会对module.exports起效。

AMD

特点

用于浏览器的模块加载。它采用异步加载方式加载模块,加载的过程中不影响后面的语句。

声明

define(function(){
    return {
        add: function(){}
    }
})

使用

require(['math'], function(math){
    console.log(math.add());
})

循环依赖

当出现循环依赖时候,采用的是强制忽略。

当A依赖B,然后B依赖了A,此时B获取到的A是未定义状态。故B一定会被优先执行完成。

UMD

特点

解决跨平台的问题,即可以运行在服务端,也可以运行在浏览器上。

实现

// if the module has no dependencies, the above pattern can be simplified to
(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define([], factory);
    } else if (typeof exports === 'object') {
        // Node. Does not work with strict CommonJS, but
        // only CommonJS-like environments that support module.exports,
        // like Node.
        module.exports = factory();
    } else {
        // Browser globals (root is window)
        root.returnExports = factory();
  }
}(this, function () {

    // Just return a value to define the module export.
    // This example returns an object, but the module
    // can return a function as the exported value.
    return {};
}));

ES6 Module

特点

在编译时就可以确定模块的依赖关系。如果遇到import时不会执行模块,而是生成一个引用,等到真正需要时,才到模块里面执行语句取值。

声明

export function add(){}
// 或者
export default {
    add
}

使用

import { add } from './test';
add();

循环依赖

它并不关心有没有循环依赖,他并不需要产生结果,他只需要给你一个引用即可,至于是否能取到值,那么就需要开发者自己来保证了。

总结

  • commonJS的特点是在require时就会执行代码,会影响后续代码的执行,并且执行过的模块会被缓存,所以commonJS只适用于服务端;
  • AMD用异步加载方式加载模块,加载的过程中不影响后面的语句,所以适用于浏览器端;
  • UMD是一种结合CommonJSAMD两者的模块化规范;
  • ES6 Module会在编译的时候通过import确定引用关系,在真正需要的时候才会执行。

补充

  • commonJS支持动态导入,即require(${path}/xx.js),但是ES6 Module不支持;
  • Commonjs导出时时值拷贝,就算导出的值改变了,导入的值也不会改变,但是ES6 Module采用的是实时绑定的方式,导入导出的值都指向同一个内存地址,所以导出的值会随导出的值变化。

参考

小结AMD,CMD,UMD,CommandJS,ES Module


若有错误,欢迎指出,感谢~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值