Nodejs中的require函数的具体使用方法


Posted in NodeJs onApril 02, 2019

说明

本文参考Node官网文档版本为v11.12.0。

本文主要分析了Nodejs中require导入JSON和js文件时得到的结果,同时简单涉及到了Nodejs中模块导出module.exports和exports的用法。

引言

在阅读webpack源码的过程当中,见到如下一行代码:

const version = require("../package.json").version

故引申出对Nodejs中require的学习。

require介绍

在Node.js的文档中,require的相关文档是在Modules目录下,属于Nodejs模块化系统的一部分。

require是一个函数。通过typeof或者Object.prototype.toString.call()可以验证这个结论:

console.log(require) // 输出:Function
console.log(Object.prototype.toString.call(require) // 输出:[object Function]

通过直接打印require,可以发现在require函数下还挂载着若干个静态属性,这些静态属性也可以在Nodejs的官方文档中直接找到相关的说明:

{ [Function: require]
 resolve: { [Function: resolve] paths: [Function: paths] },
 main:
  Module {
   id: '.',
   exports: {},
   parent: null,
   filename: '/Users/bjhl/Documents/webpackSource/index.js',
   loaded: false,
   children: [],
   paths:
   [ '/Users/bjhl/Documents/webpackSource/node_modules',
    '/Users/bjhl/Documents/node_modules',
    '/Users/bjhl/node_modules',
    '/Users/node_modules',
    '/node_modules' ] },
 extensions:
  [Object: null prototype] { '.js': [Function], '.json': [Function], '.node': [Function] },
 cache:
  [Object: null prototype] {
   '/Users/bjhl/Documents/webpackSource/index.js':
   Module {
    id: '.',
    exports: {},
    parent: null,
    filename: '/Users/bjhl/Documents/webpackSource/index.js',
    loaded: false,
    children: [],
    paths: [Array] } } }

require函数静态属性

这里之后再详细补充。

require使用

在官网文档中可以看到如下关于require的说明:

require(id)#  Added in: v0.1.13  id module name or path  Returns: exported module content  Used to import modules, JSON, and local files. Modules can be imported from node_modules. Local modules and JSON files can be imported using a relative path (e.g. ./, ./foo, ./bar/baz, ../foo) that will be resolved against the directory named by __dirname (if defined) or the current working directory.

同时还给出了三种require的使用方法:

// Importing a local module:
const myLocalModule = require('./path/myLocalModule');

// Importing a JSON file:
const jsonData = require('./path/filename.json');

// Importing a module from node_modules or Node.js built-in module:
const crypto = require('crypto');

从以上文档中可以得出以下信息:

  1. require接受一个参数,形参名为id,类型是String。
  2. require函数return的是模块到处的内容,类型是任意。
  3. require函数可以导入模块、JSON文件、本地文件。模块可以通过一个相对路径从node_modules、本地模块、JSON文件中导出,该路径将针对__dirname变量(如果已定义)或者当前工作目录。

require实践

在这里将分类讨论require的实践结论。

require导入JSON

JSON 是一种语法,用来序列化对象、数组、数值、字符串、布尔值和 null 。

在文章的开头就提到了通过require("./package.json")文件来读取package.json文件中的version属性。这里将尝试导入info.json文件并查看相关信息。

文件结构目录如下:

.
├── index.js
└── info.json

将info.json文件的内容修改为:

{
  "name": "myInfo",
  "hasFriend": true,
  "salary": null,
  "version": "v1.0.0",
  "author": {
    "nickname": "Hello Kitty",
    "age": 20,
    "friends": [
      {
        "nickname": "snowy",
        "age": 999
      }
    ]
  }
}

在info.json当中,包含了字符串、布尔值、null、数字、对象和数组。

将index.js的内容修改如下并在当前terminal运行命令 node index.js ,得到如下结果:

const info = require("./info.json")
console.log(Object.prototype.toString.call(info)) // [object Object]
console.log(info.version) // v1.0.0
console.log(info.hasFriend) // true
console.log(info.salary) // null
console.log(info.author.nickname) // Hello Kitty
console.log(info.author.friends) // [ { nickname: 'snowy', age: 999 } ]

可以看到,require导入一个JSON文件的时候,返回了一个对象,Nodejs可以直接访问这个对象里的所有属性,包括String、Boolean、Number、Null、Object、Array。个人猜测这里可能用到了类似于JSON.parse()的方法。

通过这个结论也得出了一种思路,即通过require方法传入JSON文件来读取某些值,如在文章开头中,webpack通过读取package.json文件获取到了version值。

require导入本地js文件

文件结构目录如下:

.
├── index.js
├── module_a.js
└── module_b.js

index.js文件中,分别按顺序导入了module_a和module_b并赋值,然后将这两个变量打印,内容如下:

console.log("*** index.js开始执行 ***")
const module_a = require("./module_a")
const module_b = require("./module_b")
console.log(module_a, "*** 打印module_a ***")
console.log(module_b, "*** 打印module_b ***")
console.log("*** index.js结束执行 ***")

module_a文件中,未指定module.exports或者exports,但是添加了一个异步执行语句setTimeout,内容如下:

console.log("** module_a开始执行 **")
let name = "I'm module_a"
setTimeout(() => {
  console.log(name, "** setTimeout打印a的名字 **")
}, 0)
console.log("** module_a结束执行 **")

module_b文件中,指定了module.exports(也可以换成exports.name,但是不能直接使用exports等于某个对象,因为exports和module.exports其实是指向了一个地址,引用了相同的对象,如果使用exports等于其他的引用类型,则不再指向module.exports,无法改变module.exports里的内容),内容如下:

console.log("** module_b开始执行 **")
let name = "I'm module_b"
console.log(name, "** 打印b的名字 **")
module.exports = {
  name
}
console.log("** module_b结束执行 **")

在当前目录terminal下运行 node index.js 运行得到如下输出:

*** index.js开始执行 ***
** module_a开始执行 **
** module_a结束执行 **
** module_b开始执行 **
I am module_b ** 打印b的名字 **
** module_b结束执行 **
{} '*** 打印module_a ***'
{ name: 'I am module_b' } '*** 打印module_b ***'
*** index.js结束执行 ***
I am module_a ** setTimeout打印a的名字 **

通过以上执行结果可以得出结论:

  1. require某个js文件时,如果未通过exports或者module.exports指定导出内容,则require返回的结果是一个空对象;反之可以通过module.export或者给exports属性赋值来导出指定内容。
  2. require某个js文件时,该文件会立即sync执行。

require导入模块

我们先选择一个npm包——cors。 进入文件夹,运行一下命令:

npm init -y // 初始化
echo -e "let cors = require(\"cors\")\nconsole.log(cors)" > index.js // 生成index.js文件
npm install cors --save // 安装cors包

文件结构如下(...处省略了其他的模块):

.
├── index.js
├── node_modules
│  ├── cors
│  │  ├── CONTRIBUTING.md
│  │  ├── HISTORY.md
│  │  ├── LICENSE
│  │  ├── README.md
│  │  ├── lib
│  │  │  └── index.js
│  │  └── package.json
│  │  ...
├── package-lock.json
└── package.json

index.js中的内容如下:

let cors = require("cors")
console.log(cors)

运行 node index.js ,得出以下结果:

[Function: middlewareWrapper]

找到node_modules下的cors模块文件夹,观察cros模块中的package.json文件,找到main字段: "main": "./lib/index.js" ,找到main字段指向的文件,发现这是一个IIFE,在IIFE中的代码中添加,console.log("hello cors"),模拟代码结构如下:

(function () {
  'use strict';
  console.log("hello cors"); // 这是手动添加的代码
  ...
  function middlewareWrapper(o) {
    ...
  }
  module.exports = middlewareWrapper;
})()

再次运行 node index.js ,得出以下结果:

hello cors
[Function: middlewareWrapper]

为什么会打印出 hello cors 呢?因为require模块的时候,引入的是该模块package.json文件中main字段指向的文件。而这个js文件会自动执行,跟require引用本地js文件是相同的。

packjson文档

在npm的官方网站中可以找到关于package.json中的main字段定义。

main   The main field is a module ID that is the primary entry point to your program. That is, if your package is named foo, and a user installs it, and then does require("foo"), then your main module's exports object will be returned.   This should be a module ID relative to the root of your package folder   For most modules, it makes the most sense to have a main script and often not much else.

在以上说明中可以得出以下结论:

  1. main字段是一个模块ID,是程序的主入口。
  2. 当使用require("xxx")的时候,导入的是main字段对应的js文件里的module.exports。

所以require导入模块的时候,是运行的对应模块package.json中main字段指定的文件。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

NodeJs 相关文章推荐
抛弃Nginx使用nodejs做反向代理服务器
Jul 17 NodeJs
nodejs中操作mysql数据库示例
Dec 20 NodeJs
Nodejs中解决cluster模块的多进程如何共享数据问题
Nov 10 NodeJs
nodejs redis 发布订阅机制封装实现方法及实例代码
Dec 15 NodeJs
windows 下安装nodejs 环境变量设置
Feb 02 NodeJs
解决nodejs中使用http请求返回值为html时乱码的问题
Feb 18 NodeJs
nodejs入门教程三:调用内部和外部方法示例
Apr 24 NodeJs
深入理解nodejs中Express的中间件
May 19 NodeJs
nodejs模块学习之connect解析
Jul 05 NodeJs
NodeJs实现简单的爬虫功能案例分析
Dec 05 NodeJs
nodejs基础之常用工具模块util用法分析
Dec 26 NodeJs
通过Nodejs搭建网站简单实现注册登录流程
Jun 14 NodeJs
NodeJs之word文件生成与解析的实现代码
Apr 01 #NodeJs
详解nodejs http请求相关总结
Mar 31 #NodeJs
详解Nodejs get获取远程服务器接口数据
Mar 26 #NodeJs
nodejs微信开发之自动回复的实现
Mar 17 #NodeJs
nodejs微信开发之接入指南
Mar 17 #NodeJs
nodejs微信开发之授权登录+获取用户信息
Mar 17 #NodeJs
详解nodejs 开发企业微信第三方应用入门教程
Mar 12 #NodeJs
You might like
php+dojo 的数据库保存拖动布局的一个方法dojo 这里下载
2007/03/07 PHP
写php分页时出现的Fatal error的解决方法
2011/04/18 PHP
PHP中使用foreach和引用导致程序BUG的问题介绍
2012/09/05 PHP
PHP函数strip_tags的一个bug浅析
2014/05/22 PHP
基于PHP实现短信验证码接口(容联运通讯)
2016/09/06 PHP
Laravel 实现添加多语言提示信息
2019/10/25 PHP
php加速缓存器opcache,apc,xcache,eAccelerator原理与配置方法实例分析
2020/03/02 PHP
PHP基于array_unique实现二维数组去重
2020/07/14 PHP
js 异步处理进度条
2010/04/01 Javascript
jquery 删除cookie失效的解决方法
2013/11/12 Javascript
javascript打印html内容功能的方法示例
2013/11/28 Javascript
利用JS解决ie6不支持max-width,max-height问题的方法
2014/01/02 Javascript
NodeJS学习笔记之Connect中间件模块(二)
2015/01/27 NodeJs
浅析JavaScript作用域链、执行上下文与闭包
2016/02/01 Javascript
AngularJS教程之环境设置
2016/08/16 Javascript
老生常谈javascript变量的命名规范和注释
2016/09/29 Javascript
微信小程序 出现错误:{"baseresponse":{"errcode":-80002,"errmsg":""}}解决办法
2017/02/23 Javascript
jQuery响应滚动条事件功能示例
2017/10/14 jQuery
JS中Object对象的原型概念基础
2018/01/29 Javascript
Vue精简版风格指南(推荐)
2018/01/30 Javascript
微信小程序实现页面监听自定义组件的触发事件
2020/11/01 Javascript
使用Python的Supervisor进行进程监控以及自动启动
2014/05/29 Python
Python如何通过subprocess调用adb命令详解
2017/08/27 Python
Win10下用Anaconda安装TensorFlow(图文教程)
2020/06/18 Python
Python自定义sorted排序实现方法详解
2020/09/18 Python
AmazeUI 按钮交互的实现示例
2020/08/24 HTML / CSS
Laura Geller官网:美国彩妆品牌
2018/12/29 全球购物
英国绿色商店:Natural Collection
2019/05/03 全球购物
盛大二次面试题
2016/11/18 面试题
解释一下ruby中的特殊方法与特殊类
2013/02/26 面试题
工业设计专业自荐书
2014/06/05 职场文书
2014公司年终工作总结
2014/12/19 职场文书
婚礼女方父母答谢词
2015/01/04 职场文书
《槐乡的孩子》教学反思
2016/02/20 职场文书
导游词之河北滦平金山岭长城
2019/10/16 职场文书
8个JS的reduce使用实例和reduce操作方式
2021/10/05 Javascript