跳至主要內容

模块化

狮子...大约 3 分钟面试JavaScript

参考文章open in new window

CommonJs

CommonJS 使用 module.exports、exports 导出;使用 require 导入

Node.js 是 commonJS 规范的主要实践者。Node 应用由模块组成,采用 CommonJS 模块规范。

每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。

// 在node环境直接打印 module 对象
console.log(module)

Module {
  id: '.',
  path: '',
  exports: {}, // 表示模块对外输出的值
  filename: '',
  loaded: false,
  children: [],
  paths: []
}

导出

c1.js文件

module.exports.a = 10

module.exports = {
  b: 20
}

为了方便,Node为每个模块提供一个 exports 变量,指向 module.exports。

module.exports.a = 10

console.log(module, module.exports, exports)

// module
Module {
  id: '.',
  path: '',
  exports: { a: 10 },
  filename: '',
  loaded: false,
  children: [],
  paths: []
}

// module.exports
{ a: 10 }

// exports
{ a: 10 }

因此可以写成

exports.a = 10

需要注意的是,不能将 exports 变量指向一个值,因为那样就等同于切断了exports 和 module.exports 的联系; 同样如果使用 module.exports = {} 的形式赋值,也会丢失 exports 导出的内容。看下面这种情况

module.exports.a = 10 // { a: 10 }

exports.b = 20 // { a: 10, b: 20 }

module.exports = { // { c: 30 }
  c: 30
}

导入

const a = require('./c1') // { c: 30 }
const c = require('./c1').c // 30

ESModule

ES Module 采用 export、export default 导出,使用 import 关键字导入

导出

// 第一种 export
export const func = () => {
  console.log('这是func')
}

const b = () => {
  return 20
}
// 第二种 export default
export default {
  a: 10,
  b
}

导入

// 第一种
import { func } from './e1.js'
func() // 这是func

// 第二种
import exdata from './e1.js'
console.log(exdata.a) // 10
console.log(exdata.b()) // 20

区别

  • CommonJS 模块是运行时加载,ES6 模块是编译时输出接口

运行时加载:commonjs模块就是对象;即在输入时先加载整个模块,生成一个对象,然后再从这个对象上读取属性和方法。也这样理解:Commonjs加载的是一个对象(module.exports属性),该对象只有在脚本运行时才能生成。

编译时加载(静态加载):ES6模块不是对象,而是通过export命令显式指定输入的代码,Import时可以指定加载某个导出的值,而不是加载整个模块。这种加载方式的好处在于加载效率高,能进一步拓展JavaScript的语法,比如引入宏和类型校验这些只能靠静态分析实现的功能。包括tree shaking的实现,也是依赖es6 module的静态加载。

  • commonjs是导出值的拷贝,es6 module是导出值的引用

commonjs导出值拷贝:commonjs的一个模块就是一个脚本文件。require命令第一次加载该脚本,就会执行整个脚本,然后在内存生成一个对象(拷贝)。

以后需要用到这个模块的时候,就会在exports属性上面取值,即使再次执行require命令,也不会再次执行该模块,而是到缓存之中取值,也就是说commonjs模块无论加载多少次,都只会在第一次加载时运行一次,以后再加载就返回第一次运行的结果。

es导出值引用:es模块遇到模块加载命令import,就会生成一个只读引用,等到脚本执行时,再根据这个只读引用,到被加载的那个模块里面去取值,原始值变了,import加载的值也会跟着变。因此,es6模块是动态引用,不会有缓存值,模块里的变量绑定其所在的模块。

评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.5