layout: post title: tips2-你不知道的nodeJS模块化 tags: [node] —

node如何引入模块

首先你已经安装了node。尝试新建两个文件,如下

index.js
test.js

当我想在index文件里面引入一个系统自带的模块”net”,我们需要成这个样子

var net = require"net"
net.function...

当我们想在index文件里面引入一个自己创建的test.js文件的时候,我们尝试按照上面的写法引入

var test = require"test.js"
test.function...

结果发现报错了。

原因是我们如果要引用自己创建的文件的话,必须加上./ 例如:

var test = require"./test.js"
test.function...

这样子就不会报错了

module.exports和exports的区别

node的模块化有三个关键词;第一个是require、第二个是module,第三个是exports

看下面的代码

// test.js

var a = 123
var b = "abc"

module.exports.a = a

// index.js

var test = require("./test.js")
console.log(test)

这时候会输出{ a: 123 }

简单说一下,module.exports是一个对象,通过这个对象,把对象上面的东西暴露给require的变量

其实module.exports有一个简写。将上面的test文件改一下: // test.js

var a = 123
var b = "abc"
exports.a = a

输出的结果还是{ a: 123 }

这是为什么呢?这里涉及到我们很久以前学过的知识:引用值

一开始的时候,exports和module.exports都是指向一个空对象,即{}。

突然有天exports.a 指向了 a,而module.exports.a = b 而最后导出的只会是module.exports。(实际上不管是先执行module.exports还是exports,导出的永远是module.exports,这个点很少人知道)

如何验证我们的猜测是正确的?

判断exports与module.exports是否相等,只需要console一下即可,原因是引用值的判断方式是根据地址判断,除非地址完全一致,否则返回的都不可能是true

console.log(exports == module.exports) // 结果为true 说明这俩哥们是完全一样的

为什么require、module、exports我们可以直接使用?

尝试写上以下代码

console.log(require)
console.log(module)
console.log(exports)
console.log(__dirname)
console.log(__filname)

你会惊奇的发现居然没有报错!为什么我们可以直接使用这几个变量???莫非他们就是传说中的系统变量吗?答案是:不是。

其实我们的node.js是运行在一个函数里面的

这个函数大概长这个样子:

function funName(module, require, exports, __dirname, __filname){
   // 中间的内容就是我们写的nodeJS代码
    
    return module.exports;
}

而我们写的代码,都会通过参数传到这个函数里面执行。

下面我们来验证一下是不是真的有这个函数

在js里面写上一个console.log(arguments)

你会惊奇的发现输出了下面这个东西:

{ '0': {}, // exports
  '1':  { [Function: require] // require
         resolve: { [Function: resolve] paths: [Function: paths] },
         main: 
          Module {
            id: '.',
            exports: {},
            parent: null,
            filename: 'E:\\Workers\\nodeDemo\\blog\\index.js',
            loaded: false,
            children: [],
            paths: [Array] },
         extensions: { '.js': [Function], '.json': [Function], '.node': [Function] },
         cache: { 'E:\\Workers\\nodeDemo\\blog\\index.js': [Object] } 
         },
  '2':  Module { // module
         id: '.',
         exports: {},
         parent: null,
         filename: 'E:\\Workers\\nodeDemo\\blog\\index.js',
         loaded: false,
         children: [],
         paths:   [ 'E:\\Workers\\nodeDemo\\blog\\node_modules',
                    'E:\\Workers\\nodeDemo\\node_modules',
                    'E:\\Workers\\node_modules',
                    'E:\\node_modules' 
                  ] 
        },
    '3': 'E:\\Workers\\nodeDemo\\blog\\index.js', // 文件名filname
    '4': 'E:\\Workers\\nodeDemo\\blog'  // 路径名dirname
  }

由此可见, 第一个参数就是exports,第二个是require,然后是 module filname dirname

如果你还不相信,你可以这样,在js里面验证一下

console.log(arguments[0] == exports)
console.log(arguments[1] == require)
console.log(arguments[2] == module)
console.log(arguments[3] == __filename)
console.log(arguments[4] == __dirname)

结果全部是true!!!

到了这里,你大概就能理解为什么exports和module.exports都能导出东西了:当你尝试以下代码的时候

var a = 123
var b = "aaa"
exports = a
module.exports = b

这时候在console.log(arguments)一下,你会发现:

{ '0': 123, // exports
  ...
  '2':  Module { // module
         id: '.',
         exports: aaa,
   ...
  }

exports和module.exports的值都改变了