Node.js(三)模块

2019-03-02  本文已影响0人  偶余杭

在Node.js模块系统中,每个文件都被视为一个独立的模块

导出和引用模块


比如,新建一个people.js作为一个模块:
编辑代码:

exports.sayMyName = (name) => {return '我的名字是'+name};

这个js文件就是一个模块,这个模块用exports.方法名导出了sayMyname这个函数。
在执行代码之前,Node.js会先执行一个步骤:
Node.js把模块(每一个文件)封装在一个函数中(模块封装器)

模块封装器

在执行模块(文件)代码之前,Node.js会使用一个函数封装器来封装代码

(function(exports, require, module, __filename, __dirname) {
// 模块的代码实际上在这里
});

通过在每个模块中添加了这样一层的包裹,Node.js实现了两>点:

  1. 使模块内的本地变量私有化,作用在模块范围内,而不是>暴露为全局对象。
  2. 提供了一些模块特定的变量:
    • exports:对于module.exports的更简短的引用形式
    • require:是一个函数,用于引入模块、 JSON、或本地文件。
    • module:对当前模块的引用, module.exports 用于指定一个模块所导出的内容,即可以通过 require() 访问的内容
    • __filename:当前模块已解析的绝对路径
    • __dirname:当前模块的目录名

exports是一个module.exports的更简短的引用形式,是一个对象,通过在此对象上指定额外的属性,可以将函数和对象添加到模块的根部。
在另一个模块(文件)中引用people模块,使用require语句来引用模块:

const people = require('./people.js')
console.log(`这位先生开始介绍自己,他说道:${people.sayMyName("Jack")}`)

注意:使用console时,使用${变量}来包裹变量,有变量时,使用``来作为输出语句的引号。
运行如下:


运行结果

exports 和 module.exports


exportsmodule.exports有什么不一样呢?通过上述介绍,可以知道exports 其实是module.exports 的引用,那么什么时候使用exports,什么时候使用module.exports 呢?
exports变量在模块内的作用域中是可用的,且在模块执行之前赋值给module.exports
故此,module.exports.f = ... 可以快捷地写成exports.f = ...,但是当给它赋值之后,它将不再绑定到module.exports,即,当你要使用赋值语句时,就不可再使用exports = ...,而要使用module.exports = ...

module.exports.hello = true;//从模块的引用中导出
exports.hello = true;//从模块的引用中导出
module.exports = exports = function Contructor(){};//导出模块
//module.exports被赋值时,也会重新赋值exports
exports = { hello: false };  // 不导出,仅在模块中可用。
//此时,exports 不与 module.exports绑定了。

通过require()的实现来说明他们之间的关系:

function require(/* ... */) {
  const module = { exports: {} };
  ((module, exports) => {
    // 模块代码在这。在这个例子中,定义了一个函数。
    function someFunc() {}
    exports = someFunc;
    // exports被赋值了,此时,exports 不再是一个 module.exports 的快捷方式,
    // 且这个模块依然导出一个空的默认对象。
    module.exports = someFunc;
    // module.exports被赋值了,此时,该模块导出 someFunc,而不是默认对象。
  })(module, module.exports);
  return module.exports;
}

综上,可以知道使用exportsmodule.exports的场景:

  1. 当希望模块导出一个空的默认对象,以及暴露一些外部可以通过这个对象访问的api或者变量时,使用exports
//模块中导出
exports.func = ...
exports.a = ...
//外界访问
const moduleName = require('module.js');//获取默认对象
moduleName.func();//访问对象中挂载暴露的函数
console.log(moduleName.a);
  1. 当希望模块导出一个变量或函数时,外部直接访问这个变量和函数,使用module.exports
//模块中导出
module.exports = function(){}
//外界访问
const moduleName = require('module.js');//获取默认对象
moduleName()

想要传参数到模块中动态配置的方法:
使用module.exports导出一个工厂函数,这个函数可以传入参数,在这个函数中,模块内就可以使用参数进行逻辑操作,从而达到动态配置的效果,如
设置一个模块,可以计算汇率,设置汇率会动态配置的参数:

let rate;
function rmbToDollar(rmb){
    return rmb/rate;
}

module.exports = function(r){
    rate = r
    return {rmbToDollar} 
}

在外部动态配置汇率,结构出我们要使用的函数:

const {rmbToDollar} = require('./currency')(6)
console.log(rmbToDollar(10))

访问主模块

主模块,即当前模块是不是直接运行的模块(文件)。
当Node.js直接运行一个文件时,require.main会被设置为其module,如果要判断一个文件是不是被直接运行,通过以下语句判断:

require.main === module

如果是通过node xxx.js运行,为true;
如果是通过require运行,为false。
要获取当前程序的入口点,可以通过以下代码获取:

require.main._filename

核心模块

Node.js有一些模块是核心模块,定义在lib/目录下,require()会优先加载核心模块,即使有模块与核心模块重名,也会先加载内置的模块。

require()查找目录

require中传入的参数有以下几种情况

{ "name" : "some-library",
  "main" : "./lib/some-library.js" }

如果这是在 ./some-library 目录中,则 require('./some-library') 会试图加载 ./some-library/lib/some-library.js。
如果目录中没有package.json文件,则Node.js会试图加载目录中的index.js或者index.node。

详解module对象

每个模块中都有一个module对象,表示当前模块的对象的引用。里面有一些关于本模块(文件)的信息。module对象是每个模块本地的。
在文件中输出module:

console.log(module)

可以得到如下结果:


module构成

组成解析:

npm


npm是Node.js的包管理器,通常在安装Node.js的时候一起安装了。
查看npm的版本

npm -v
上一篇 下一篇

猜你喜欢

热点阅读