module

Description

为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。在 Node 环境中,一个 js 文件就称之为一个模块(module)

使用模块可以避免函数名和变量名冲突,相同名字的函数和变量完全可以分别存在不同的模块中。

Code

hello 模块

'use strict'

var s = 'Hello'

function greet(name) {
  console.log(s + ', ' + name + '!')
}

module.exports = greet

函数 greet() 是我们在 hello 模块中定义的,你可能注意到最后一行是一个奇怪的赋值语句,它的意思是,把函数 greet 作为模块的输出暴露出去,这样其他模块就可以使用 greet 函数了

调用模块

'use strict'

// 引入 hello 模块
var greet = require('./hello')

var s = 'Michael'

greet(s) // Hello, Michael

require 引入的就是 hello 模块输出的 greet

CommonJS 规范

NodeJS 的模块加载机制被称为 CommonJS 规范。在这个规范下,每个 .js 文件都是一个模块,它们内部各自使用的变量名和函数名都互不冲突,例如,hello.jsmain.js 都申明了全局变量 var s = 'xxx',但互不影响

用法

在模块中对外输出变量,用:

module.exports = variable

输出的变量可以是任意对象、函数、数组等

要引入其他模块输出的对象,用:

var foo = require('other_module')

引入的对象具体是什么,取决于引入模块输出的对象

Node 模块原理

require

Node.js 加载模块时,会将代码包装:

(function () {
  // 读取的 hello.js 代码
  var s = 'Hello'
  var name = 'world'
  
  console.log(s + ' ' + name + '!')
  // hello.js 代码结束
})()

这样,模块中的变量都会变成匿名函数内部的局部变量,即使 NodeJS 继续加载其他模块,模块之间的变量也不会互相干扰

exports

NodeJS 输出模块时,会先准备一个对象 module

// 准备 module 对象
var module = {
  id: 'hello',
  exports: {}
}

var load = function (module) {
  // 读取的 hello.js 代码
  function greet(name) {
    console.log('Hello, ' + name + '!')
  }
  
  module.exports = greet
  // hello.js 代码结束
  
  return module.exports
}

var exported = load(module)
// 保存 module
save(module, exported)

通过把参数 module 传递给 load 函数,hello.js 就顺利地把一个变量传递给了 Node 执行环境,Node 会把 module 变量保存到某个地方。

由于 Node 保存了所有导入的 module,当我们用 require() 获取 module 时,Node 找到对应的 module,把这个 moduleexports 变量返回,这样,另一个模块就顺利拿到了模块的输出:

var greet = require('./hello')

以上是 Node 实现 javascript 模块的一个简单的原理

Last updated