1、模块的使用
1.1、为什么要模块化(了解)
在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。(一个js文件就是一个模块)
使用模块有什么好处:
-
最大的好处是大大提高了代码的可维护性。其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。我们在编写程序的时候,也经常引用其他模块,包括 Node.js 内置的模块和来自第三方的模块。
-
使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。
说重点:主要的原因是方便项目的开发和维护。
1.2、模块规范的定义(了解)
-
一个js文件就是一个模块,模块的作用域是
私有的
,内部定义的变量或者函数,只在当前的文件(模块)可以使用 -
如果别人需要使用我们模块里面的东西,那么有两点要做(以CommonJS 的 Modules 规范: Node.js为例)
-
自己编写的模块,由于模块作用域是私有的,默认情况下,外部是没办法使用的;如果希望别人可以使用,则需要导出
exports
或者module.exports
。 导出的时候,以对象的方式进行导出 -
别人要使用某个模块,则需要先引入该模块,使用
require
引入,引入后需要使用一个变量来接收导入的对象。
-
对书写格式和交互规则的详细描述,就是模块定义规范(Module Definition Specification):
-
AMD 规范: Require.js
-
CMD 规范: Sea.js
-
CommonJS 的 Modules 规范: NodeJs
-
ES6 模块化规范 import ... from ...
1.3、模块化使用
导出数据方式一:
exports.num = num; exports.sum = sum; exports.Animal = Animal;
导出数据方式二:
// 通过module.exports 等于一个对象,来导出数据 // 对象可采用es6简化对象的写法 module.exports = { num, sum, Animal };
导入数据:
注意1: 如果要使用某个模块里面的数据,则需要使用 require 关键字进行导入。 注意2:在导入用户自己开发的模块的时候,需要加上路径(1. 相对路径(多) 2. 绝对路径) 注意: 必须写上 注意3:模块文件的扩展名(后缀名)可以写,也可以不写 注意4:导出的模块一般需要使用一个变量来接收,一般把接收的量定义为常量 注意5: 定义常量的名称和文件的名称保持一致(这个不是必须,大家都这么做) const m1 = require("./modules/m1.js");
完整代码:
// m1.js中: let num = 10; function sum(a, b) { return a+b } class Animal{ constructor(){ this.age=0 } } // 导出数据方式1: // exports.num = num; // exports.sum = sum; // exports.Animal = Animal; // 导出数据方式2: // 通过module.exports 等于一个对象,来导出数据 // 对象可采用es6简化对象的写法 module.exports = { num, sum, Animal }; //01-模块的使用.js const m1 = require("./modules/m1.js"); console.log(m1); //{ num: 10, sum: [Function: sum], Animal: [Function: Animal] } console.log(m1.sum(10, 20)); const obj = new m1.Animal(); //30 console.log(obj.age); //0
2、模块里面this的指向问题
1、exports实际上是module.exports的引用,
2、exports是module.exports的引用,文件中才有exports,交互模式下没有exports(exports是引用了module.exports对象在文件中存在)
3、在 nodejs 里面的 this 代表当前的这个模块,也就是 exports 对象
4、this也是指向模块/文件导出的对象,因此在文件中(exports===module.exports===this)
5、而在交互环境中则不存在点4的这一等式,一切都来源自module.exports的引用,
6、this===global在交互模式下成立,this===exports在一个模块文件下也是成立的。不同的模式下各自不同
7、exports对象存在数据丢失问题,当我们利用第二种对module.exports进行数据导入方法时exports就存在数据丢失,为此利用第二种方式时需要对获取的数据进行赋值
console.log(exports); //{} console.log(module.exports); //{} console.log(exports === module.exports); //true exports实际上是module.exports的引用 console.log('this', this); // this {} console.log(this === exports);// true // 在 nodejs 里面的 this 代表当前的这个模块,也就是 exports 对象 并且,交互模式下,没有exports这个对象 console.log(global === this ); //false this不指向全局对象
3、nodejs常用内置模块
一般项目中模块分为3种,nodejs内置模块、自己书写的模块、第三方模块(使用一个专门的工具npm进行统一管理)
常用的内置模块如下:
-
fs :文件操作
-
http :网络操作
-
path :路径操作
-
querystring :查询参数解析
-
url :url 解析
const fs = require("fs"); const http = require('http'); const path = require('path'); const querystring = require('querystring'); const url = require('url');
nodejs内置模块的文档网址:API 文档 | Node.js 中文网
3.1、path内置模块
const path = require("path"); console.log(__dirname); // 当前执行的文件绝对路径,不包含文件名 console.log(__filename); // 当前执行的文件绝对路径,包含文件名 let extname = path.extname( __filename ); // 获取扩展名(后缀名) console.log(extname); let baseName = path.basename( __filename ); // 获取文件名(包含后缀名) console.log(baseName); let dirname = path.dirname(__filename); //获取目录(路径) console.log(dirname); let parse = path.parse(__filename); //获取路径字符串的对象 console.log(parse); //路径的拼接操作 join // join 默认相对路径的拼接 ,以当前操作系统路径分割符进行拼接 let fullPath1 = path.join('path.js'); // fullPath1 = path.join(__dirname,'path.js'); //带目录 // fullPath1 = path.join(__dirname,'a','path.js'); //带多级目录 console.log(fullPath1);