ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

commonjs和ES Module

2021-09-22 14:03:23  阅读:138  来源: 互联网

标签:commonjs 导出 exports module Module 模块 ES 加载


commonjs导出方法exports和module.exports的区别?

commonjs实际导出的就是exports这个对象,可以把需要导出的变量、方法等绑定在exports这个对象上导出,例如:

//a.js
exports.name = '阿明先森'
console.log(require('./a.js') );

打印:

{
    "name": "amingxiansen"
}

小结:所以用exports导出的都是对象,导出内容包含在对象里。

module.exportsexports具有相同的引用。module.exports可以直接导出函数、变量等。例如:

module.exports  = '阿明先森'

打印:

小结:当然想要导出对象也没问题:module.exports = {};相比exports,更灵活也更容易理解,推荐使用module.exports进行导出。

如果使用exports = {name: '阿明先森'}导出对象会怎么样呢?
打印:

打印为空,原因是exports是导出函数传入的参数,exports = {}相当于在函数里面重新声明了一个exports变量,和原来的参数脱离了关系,所以打印出来的是原来的参数,为空。
举个例子:

const myExports  = {}
function Test(myExports) {
  myExports  = {name: 'amingxiansen'} //这里的myExports与参数脱离了关系,相当于在局部声明了let Exports
}
console.log(Test(myExports)) // {}

小结: 所以使用exports导出,必须要把导出内容绑定在exports上,作为它的一个属性导出。

module.exports ={
    name:'amingxiansen'
}
exports.name = 'alien' // 此时 `exports.name` 是无效的

此时exports会被module.exports覆盖
小结: module.exports优先级高于exports,应该避免两种导出混合使用。

commonjs实现原理?

在编译过程中,commonjs经过了收尾的包装,像下面这样:

(function(exports,require,module,__filename,__dirname){
   const sayName = require('./hello.js')
    module.exports = function say(){
        return {
            name:sayName(),
            author:'我不是外星人'
        }
    }
})

Commonjs 规范模块中,会形成一个包装函数,我们写的代码将作为包装函数的执行上下文,使用的 require ,exports ,module 本质上是通过形参的方式传递到包装函数中的。

require加载原理?

每个文件都是一个module,module上除了有模块的基本信息之外,还会有个loaded代表模块是否已经加载过。二次加载会直接使用缓存中的数据。
以nodejs为例,整个系统运行之后,会用 Module 缓存每一个模块加载的信息。
加入缓存的顺序是:先加入缓存再执行
require源码:

 // id 为路径标识符
function require(id) {
   /* 查找  Module 上有没有已经加载的 js  对象*/
   const  cachedModule = Module._cache[id]
   
   /* 如果已经加载了那么直接取走缓存的 exports 对象  */
  if(cachedModule){
    return cachedModule.exports
  }
 
  /* 创建当前模块的 module  */
  const module = { exports: {} ,loaded: false , ...}

  /* 将 module 缓存到  Module 的缓存属性中,路径标识符作为 id */  
  Module._cache[id] = module
  /* 加载文件 */
  runInThisContext(wrapper('module.exports = "123"'))(module.exports, require, module, __filename, __dirname)
  /* 加载完成 *//
  module.loaded = true 
  /* 返回值 */
  return module.exports
}

ES module

对模块化module的支持是从ES6以后开始的。ES module导入导出使用 importexport。可以导出函数、变量、对象等。
export default //默认导出 ===> import temp from './a.js'
export {a, b, c} ===> import {a, b, c} from './a.js'
也可以混合导入导出。

es module的特性

  1. ES6 module 的引入和导出是静态的,import 会自动提升到代码的顶层 ,import , export 不能放在块级作用域或条件语句中。
  2. ES6 module 和 Common.js 一样,对于相同的 js 文件,会保存静态属性。
    但是与 Common.js 不同的是 ,CommonJS 模块同步加载并执行模块文件,ES6 模块提前加载并执行模块文件,ES6 模块在预处理阶段分析模块依赖,在执行阶段执行模块,两个阶段都采用深度优先遍历,执行顺序是子 -> 父。
  3. es module import导入的属性是read only的,直接修改会报错;commonjs require导入的是属性的copy,可以更改导入属性。

总结

Commonjs 特性总结

  • CommonJS 模块由 JS 运行时实现。
  • CommonJs 是单个值导出,本质上导出的就是 exports 属性。
  • CommonJS 是可以动态加载的,对每一个加载都存在缓存,可以有效的解决循环引用问题。
  • CommonJS 模块同步加载并执行模块文件。

ES Module特性总结

  • ES6 Module 静态的,不能放在块级作用域内,代码发生在编译时。
  • ES6 Module 的值是动态绑定的,可以通过导出方法修改,可以直接访问修改结果。
  • ES6 Module 可以导出多个属性和方法,可以单个导入导出,混合导入导出。
  • ES6 模块提前加载并执行模块文件,
  • ES6 Module 的特性可以很容易实现 Tree Shaking 和 Code Splitting。

标签:commonjs,导出,exports,module,Module,模块,ES,加载
来源: https://www.cnblogs.com/amingxiansen/p/15319602.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有