前端模块化对比

434 阅读3分钟

学习笔记

es5模块化

优点 :

1.不需要配置环境,纯靠原生JS(闭包)支持

2.解决了全局变量污染和命名冲突

缺点 :

1.依赖script标签的加载顺序

2.扩展方式略显麻烦

写法 :

// module1.js
window['es5module'].m1 = (() => {
  var name = 'JSmodule'
  return {
    name
  }
})()

// module2.js
window['es5module'].m2 = (() => {
  var int = 300
  return {
    int
  }
})()

// module3.js
// 先定义一个模块盒子对象,用来存储后续模块
Object.defineProperties(globalThis, {
  'es5module': {
    value: {} // 给window加个变量用来给扩展后续模块
  }
})
window['es5module'].m3 = ((m1, m2) => {
  var say = function () {
    return `我的名字是${m1['name']},我有${m2['int']}块钱`

  }
  return {
    say
  }
  // 引入依赖模块,其实就是给立即执行函数传winodw里面变量的参数
})(window['es5module'].m1, window['es5module'].m2) 

image.png

PS:立即执行函数有函数作用域,变量在里面定义只会在该函数内有效,不会提升到全局,同时return该变量会保持变量的引用,这样就不会触发JS引擎的垃圾回收机制啦

commonJS

优点 :

1.是nodeJS的模块规范

2.解决了加载顺序问题

3.一次加载即缓存模块,解决多次加载照成的资源浪费

4.模块作用域,模块内变量不会影响到全局

缺点 :

1.运行代码时才会加载

2.require(xxx)输出的值是浅拷贝值

3.无法直接在客户端使用,需要借助nodeJS环境和webpack

4.同步执行(在nodeJS环境没什么影响),但如果在客户端运行就会很吃网速

写法 :

// common1.js
var a = (() => {
  return ['js++module']
})()
module.exports = {
  a
}

// common2.js
var { a } = require('./commonjs1')
var b = (() => {
  var _b = [0xff, 0x11, 0x22, 0x33]
  return _b.concat(a)
})()
module.exports = {
  b
}

// common3.js //中需引入common3.js文件,require会自动帮我们找到依赖模块
var { b } = require('./commonjs2')
var { a } = require('./commonjs1')
var c = (() => {
  return {
    c: b.concat([10, 20, 30, 40]),
    log: function () {
      console.log(a, b)
    }
  }
})()
Object.defineProperty(globalThis, 'common', {
  value: {
    a,
    b,
    c
  }
})

image.png

PS:模块的加载实质上就是,注入exports、require、module三个全局变量,然后执行模块的源码,然后将模块的 exports 变量的值输出。

AMD ‘Asynchronous Module Definition’

优点 :

1.异步方法加载模块,可以不借助nodejs实现在客户端运行,适合在浏览器用

2.所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。

缺点 :

1.写法不太妙

2.仍然需要进行一些配置才能使用

写法 :

define('moduleA', function () {
  var a = [1, 2, 3, 4, 5]
  return {
    a
  }
})

require([module], callback);

PS:目前,主要有两个Javascript库实现了AMD规范:require.jscurl.js

CMD ’Common Module Definition’

优点 :

1.阿里巴巴出的

2.CMD是依赖就近,延迟执行,只有在用到某个模块的时候再去require,而AMD是依赖前置,提前执行

3.也是异步加载模块

缺点 : 不了解

写法 :不了解

PS:基于在 Sea.js,感兴趣的可以去看看

es6module

优点 :

1.是ECMA规范,语言层面实现模块化,nodeJS也可以用

2.输出的值是值引用

3.编译时执行

4.写法简单

5.也有缓存机制

缺点 :

1.老浏览器不支持

写法 :

// e6m1.js
export const name = '梅'
export function log() {
  console.log(arguments)
}
// export default就是没名字的导出
export default class {
  say() {
    console.log('你是好人')
  }
}

// e6m2.js
// 命名导出,import关键字会被提升
import { name as bar, log } from './es6module1'
// 全部导出再重命名
import * as m1 from './es6module1'
// 默认导出
import Hello from './es6module1'

// 还有个 import()写法,返回promise,可以自己去尝试
console.log(bar, log)
console.log(m1)
console.log(Hello)


四种模块导出方式的区别

  1. module.exports:nodeJs的默认导出,exports引用该变量。 image.png

  2. exports:引用module.exports,如果将该变量直接赋值为其他值,不会影响module.exports默认导出 image.png image.png image.png

  3. export default:发现是修改module.exports里面的default值. image.png 但并不全等于直接赋值default,export default导出可以直接在另一个文件import xxx from 'xxx',但直接赋值就会导致报错. image.png image.png

  4. export:与exports.xxx几乎一致 image.png image.png

PS: 上面这些导出指的只是使用形式上,底层做的处理没那么简单喔

PS: 年轻人就要跟随潮流