commonjs

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

每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。

require方法用于加载模块

以上来自CommonJS规范-阮一峰

commonjs的详细:可以从node的使用中获悉

nodejs 模块化

导出:

提供一个exports对象用于导出当前模块的方法或变量,并且它是唯一导出的出口

在nodejs中,每一个文件当作一个模块,在模块中,还有一个module对象,exports是它的一个属性

两种导出方式:

1. exports.binary_search = binary_search;
2. module.exports = binary_search;

第一种方式:

const util = require('./binary_search');

使用需要util.binary_search(arr, 15)

第二种方式:

直接:util(arr, 15)

why?

测试1:

exports.binary_search = binary_search;
console.log(exports);
console.log(module);

// output
{ binary_search: [Function: binary_search] }
Module {
  id: '.',
  exports: { binary_search: [Function: binary_search] },
  parent: null,
  filename: 'E:\\Beginning_JavaScript\\testEloquentJs\\DataStrctrue\\binary_search.js',
  loaded: false,
  children: [],
  paths:
   [ 'E:\\Beginning_JavaScript\\testEloquentJs\\DataStrctrue\\node_modules',
     'E:\\Beginning_JavaScript\\testEloquentJs\\node_modules',
     'E:\\Beginning_JavaScript\\node_modules',
     'E:\\node_modules' ] }

// 对`exports`添加属性`binary_search`会影响到`module`对象(自动添加了)

测试2:

module.exports = binary_search;
console.log(exports);
console.log(module);

// output
{}
Module {
  id: '.',
  exports: [Function: binary_search],

// 对`module.exports`直接赋值不会影响到`exports`对象
// 而注意的是此时的require引用并不会因为`exports`对象为空,而是正常输出了

测试3:

module.exports.binary_search = binary_search;
console.log(exports);
console.log(module);

// output
{ binary_search: [Function: binary_search] }
Module {
  id: '.',
  exports: { binary_search: [Function: binary_search] },
  ...

// 对`module.exports`添加属性`binary_search`会影响到`exports`对象(自动添加了)

测试2:可知,require是关联的module.exports

测试1和3:正好验证了exportsmodule.exports是指向同一个内存块(初始时),但是实际改变exports的指向也不会改变module.exportsexports只是一个module.exports引用,参看知乎回答的第一个回答

推荐知乎回答第二个回答的debug过程和最后的issue博客:

Node.js模块里exports与module.exports的区别?--知乎

exports、module.exports 和 export、export default 到底是咋回事

「前端」import、require、export、module.exports 混合详解

以及查看深入浅出Nodejs2.2.3 模块编译1. JavaScript模块的编译

最后其中module对象的paths的那个数组显得神奇(被叫做模块路径)...,参看2.2.2 路径分析和文件定位

es6

es6的语法就变得更加简洁:

//导出
//util1
export default {
    a: 100
}
//util2
export const fn1 = function () {
    console.log('fn1');
}
export const fn2 = function () {
    console.log('fn2');
}
// 导入
import util from "./util1";
import { fn1, fn2 } from "./util2";

commonjs与es6互转的问题

主要是很奇怪的一种现象:一次在进行jest测试的时候,发现,

// utils.js
function fn1() {
    console.log('fn1');
}
function fn2() {
    console.log('fn2');
}   
// 如上述,改成了commonjs的导出风格
module.exports = {
    fn1,
    fn2
}
// 导入(es6的导入风格)
import {fn1, fn2} from "./util2";

fn1();
fn2();

同样的这段代码,rollup会报错,而webpack可以正常跑

报错:

[!] Error: 'fn1' is not exported by src\util2.js

[[name] is not exported by [module]](https://github.com/rollup/rollup/wiki/Troubleshooting#name-is-not-exported-by-module)

当改成:

export function fn1() {
    console.log("fn1");
}
export function fn2() {
    console.log("fn2");
}

rollup又可以正常运行。

这里很推荐阅读这篇文章:「前端」import、require、export、module.exports 混合详解

在文章里面就深度解析了,因为babel、webpack等会采用将es6的模块化转成commonJs的方式,所以在webpack里面的肯定是没有问题的,但rollup暂时我弄不懂哈哈哈

标签: none

添加新评论