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 相关文章推荐
用nodejs实现PHP的print_r函数代码
Mar 14 NodeJs
Nodejs极简入门教程(二):定时器
Oct 25 NodeJs
nodejs搭建本地http服务器教程
Mar 13 NodeJs
Nodejs中Express 常用中间件 body-parser 实现解析
May 22 NodeJs
nodejs mysql 实现分页的方法
Jun 06 NodeJs
Mac 安装 nodejs方法(图文详细步骤)
Oct 30 NodeJs
NodeJS实现自定义流的方法
Aug 01 NodeJs
NodeJs 文件系统操作模块fs使用方法详解
Nov 26 NodeJs
基于Koa(nodejs框架)对json文件进行增删改查的示例代码
Feb 02 NodeJs
详解微信小程序-获取用户session_key,openid,unionid - 后端为nodejs
Apr 29 NodeJs
nodejs实现用户登录路由功能
May 22 NodeJs
nodejs中使用archive压缩文件的实现代码
Nov 26 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 常用类汇总 推荐收藏
2010/05/13 PHP
解析mysql 表中的碎片产生原因以及清理
2013/06/22 PHP
如何使用php脚本给html中引用的js和css路径打上版本号
2015/11/18 PHP
浅谈htmlentities 、htmlspecialchars、addslashes的使用方法
2016/12/09 PHP
PHP给前端返回一个JSON对象的实例讲解
2018/05/31 PHP
ThinkPHP5.0多个文件上传后找不到临时文件的修改方法
2018/07/30 PHP
JQuery打造PHP的AJAX表单提交实例
2009/11/03 Javascript
jquery蒙版控件实现代码
2010/12/08 Javascript
JS远程获取网页源代码实例
2013/09/05 Javascript
Iframe实现跨浏览器自适应高度解决方法
2014/09/02 Javascript
DEDECMS如何为文章添加HOT NEW标志图片
2015/08/14 Javascript
JS中作用域和变量提升(hoisting)的深入理解
2016/10/31 Javascript
vue使用keep-alive保持滚动条位置的实现方法
2019/04/09 Javascript
基于elementUI竖向表格、和并列的案例
2020/10/26 Javascript
python简单获取数组元素个数的方法
2015/07/13 Python
Python简单计算文件夹大小的方法
2015/07/14 Python
Python使用Scrapy保存控制台信息到文本解析
2017/12/27 Python
Python中实现变量赋值传递时的引用和拷贝方法
2018/04/29 Python
python 利用for循环 保存多个图像或者文件的实例
2018/11/09 Python
python爬虫 urllib模块反爬虫机制UA详解
2019/08/20 Python
python常用数据重复项处理方法
2019/11/22 Python
利用 PyCharm 实现本地代码和远端的实时同步功能
2020/03/23 Python
CSS3圆角和渐变2种常用功能详解
2016/01/06 HTML / CSS
html5构建触屏网站之网站尺寸探讨
2013/01/07 HTML / CSS
Sephora丝芙兰马来西亚官方网站:国际化妆品购物
2018/03/15 全球购物
猫咪家具:CatsPlay
2018/11/03 全球购物
香港网上花店:FlowerAdvisor香港
2019/05/30 全球购物
工程监理应届生求职信
2013/11/09 职场文书
数控专业大学生的自我鉴定
2013/11/13 职场文书
文化产业实施方案
2014/06/07 职场文书
北京申奥口号
2014/06/19 职场文书
团队拓展活动方案
2014/08/28 职场文书
倡议书格式
2014/08/30 职场文书
企业党员个人自我评价
2014/09/20 职场文书
开业典礼致辞
2015/07/29 职场文书
MySQL中的 inner join 和 left join的区别解析(小结果集驱动大结果集)
2023/05/08 MySQL