Node.js基础


Node.js基础学习

个人学习笔记

一、fs模块

fs模块是node.js的文件操作模块

读取文件

const fs = require('fs');
fs.readFile('./files/kch.txt', 'utf8', (err, dataStr) => {
  if (err) {
    return console.log('读取文件失败' + err.message);
  }
  console.log('读取文件成功!' + dataStr);
});

写入文件

const fs = require('fs');
fs.writeFile('./kch.txt', 'ok123', err => {
  if (err) {
    return console.log('文件写入失败' + err.message);
  }
  console.log('文件写入成功!');
});

注意:写入文件时可以创建文件,但不能创建文件夹

二、path模块

path模块是node.js的路径处理模块

__dirname表示当前文件所在的目录
node执行程序时,会以当前执行路径作为参考路径,为避免这种问题,所以使用path模块动态生成绝对路径。

路径拼接

const path = require('path');
const pathStr = path.join('/a', '/b/c', '../', './d', 'e');
console.log(pathStr); // \a\b\d\e

const pathStr2 = path.join(__dirname, './files/1.txt');
console.log(pathStr2); // 输出绝对路径D:\fontstudy\node\files\1.txt

获取文件路径中文件名称部分

const path = require('path');
const fpath = '/a/b/c/index.html';

var fullName = path.basename(fpath);
console.log(fullName); // index.html

var nameWithoutExt = path.basename(fpath, '.html');
console.log(nameWithoutExt); // index

a/b/c会返回c;a/b/c/会返回c

获取文件路径中文件扩展名部分

const path = require('path');
const fpath = '/a/b/c/index.html';

const fext = path.extname(fpath);
console.log(fext);

a/b/c会返回空;a/b/c.会返回.

三、http模块

http模块是node.js的创建web服务器模块

const http = require('http');

const server = http.createServer();
server.on('request', (req, res) => {
  const url = req.url;
  const method = req.method;
  console.log(url, method);
  // 解决返回为中文时,乱码问题
  res.setHeader('Content-Type', 'text/html;charset=utf-8');
  res.end('服务器返回的结果');
});
server.listen(80, () => {
  console.log('server running at http://127.0.0.1');
});

http默认端口为80,即不加端口默认访问80端口
req.url为用户访问路径,127.0.0.1,req.url为/;127.0.0.1/index.html,req.url为/index.html
req.method为访问方法,直接从浏览器输入地址请求为GET方法

简单的路由

const http = require('http');

const server = http.createServer();
server.on('request', (req, res) => {
  const url = req.url;
  let content = '<h1>404 Not Found!</h1>';
  if (url === '/' || url == '/index.html') {
    content = '<h1>首页</h1>';
  } else if (url === '/about.html') {
    content = '<h1>关于页面</h1>';
  } else {
    content = '<h1>其他页面</h1>';
  }
  res.setHeader('Content-Type', 'text/html;charset=utf-8');
  res.end(content);
});
server.listen(80, () => {
  console.log('server running at http://127.0.0.1');
});

根据用户传入的url路径,选择读取的文件并返回给用户

const path = require('path');
const fs = require('fs');
const http = require('http');

const server = http.createServer();

server.on('request', (req, res) => {
  //前提是有
  // /clock/index.html
  // /clock/index.css
  // /clock/index.js
  const url = req.url;
  const fpath = path.join(__dirname, url);
  fs.readFile(fpath, 'utf8', (err, dataStr) => {
    if (err) {
      return res.end('404 Not Found.');
    }
    res.end(dataStr);
  });
});

server.listen(80, () => {
  console.log('server running at http://127.0.0.1');
});

通过上例也说明了通过读取文件生成的字符串返回给浏览器,浏览器也会正常解析成html界面

注意:在请求html页面时,html页面同时注入了css和js脚本,浏览器也会同时对注入的脚本进行请求。具体请求方式如下:根据浏览器当前的请求路径为基础路径进行请求。例如:请求127.0.0.1/index.html,注入的脚本路径为./index.css,那么会从与index.html同级目录去寻找index.css;如果注入的脚本路径为./css/index.css,那么会从与index.html同级的css目录下级寻找index.css

四、Node.js模块化

内置模块(fs,path,http)
自定义模块(用户定义的.js文件)
第三方模块(由第三方开发出的功能拓展模块,使用前需要先下载)

当使用require()方法加载其它模块时,会执行被加载模块中的代码
当使用require()方法加载自定义模块时,可以省略.js扩展名

1.模块作用域

和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问,这种模块级别的访问限制,叫做模块作用域。

01test.js

// 1.在模块作用域中定义常量username
const username = '张三';
// 2.在模块作用域中定义函数sayHello
function sayHello() {
  console.log(`我是${username}`);
}

02test.js

const test01 = require('./01test');

// 输出{}空对象
// 在02test.js模块中,无法访问到01test.js中的私有成员
console.log(test01); // {}

require和module.exports是一对一个导入一个导出,exports是module.exports的引用,而module.exports默认是一个{},01test.js没有使用export.module和export导出值,自然在02test.js中为{}

在每个.js自定义模块中都有一个module对象,它里面存储了和当前模块有关的信息

console.log(module);

// Module {
//   id: '.',
//   path: 'D:\\fontstudy\\node',
//   exports: {},
//   filename: 'D:\\fontstudy\\node\\server.js',
//   loaded: false,
//   children: [],
//   paths: [
//     'D:\\fontstudy\\node\\node_modules',
//     'D:\\fontstudy\\node_modules',
//     'D:\\node_modules'
//   ]
// }

在自定义模块中,可以使用module.exports对象,将模块内的成员共享出去,供外界使用。
外界用require()方法导入自定义模块时,得到的就是module.exports所指向的对象。
注意:使用require()方法导入模块时,导入的结果,永远以module.exports指向的对象为准
m1.js

module.exports.username = 'zs';
module.exports.sayHello = function () {
  console.log('Hello!');
};

// 让module.exports指向一个全新的对象
module.exports = {
  nickname: 'kkk',
  sayHi() {
    console.log('Hi!');
  },
};

m2.js

const m1 = require('./m1');

console.log(m1); // 输出 {nickname: 'kkk', sayHi: [Function: sayHi]}

exports对象
由于module.exports单词写起来比较复杂,为了简化向外共享成员的代码,Node提供了exports对象。默认情况下,exports和module.exports指向同一个对象,且exports是module.exports的一个引用,所以最终共享的结果,还是以module.exports指向的对象为准。

案例一

m1.js

module.exports.username = 'zs';
module.exports.sayHello = function () {
  console.log('Hello!');
};

// 让exports指向一个全新的对象
// 但exports的指向改变了,不再与module.exports指向同一个对象,而require()导入的对象最终还是以module.exports为准
exports = {
  nickname: 'kkk',
  sayHi() {
    console.log('Hi!');
  },
};

m2.js

const m1 = require('./m1');

console.log(m1); // 输出 {username: 'zs', sayHello: [Function: sayHello]}

案例二
m1.js

exports.username = 'zs';

// 让module.exports指向一个全新的对象
// module.exports的指向改变了,不再与exports指向同一个对象,而require()导入的对象最终还是以module.exports为准
module.exports = {
  nickname: 'kkk',
  sayHi() {
    console.log('Hi!');
  },
};

m2.js

const m1 = require('./m1');

console.log(m1); // 输出 {nickname: 'kk', sayHi: [Function: sayHi]}

五、npm与包

1.npm简介

npm(node package management)node.js包管理工具
包的版本号是以“点分十进制”形式进行定义的,总共有三位数字,例如:2.24.0
其中每一位数字所代表的含义如下:
第一位数字:大版本;
第二位数字:功能版本;
第三位数字:Bug修复版本;

版本号提升规则:只要前面的版本号增长了,则后面的版本号归零

2.npm包管理配置文件

第三方包(node_modules)的体积过大,不方便团队成员之间共享项目源代码。
共享时剔除node_modules,在项目根目录中,创建一个叫做package.json的配置文件,可用来记录项目中安装了哪些包,在团队中共享项目的源代码。

快速创建package.json文件

npm init -y

npm一次性安装多个包

npm i 包名1 包名2

npm卸载包(会同时删除node_modules中的包和删除package.json中dependencies中相应的节点)

npm uninstall 包名

devDependencies和dependencies
如果某些包只在项目开发阶段会用到,在项目上线后不会用到,则建议把这些包记录到devDependencies节点中。
与之对应的,如果某些包在开发阶段和项目上线后都需要用到,则建议把这些包记录到dependencies节点中。

可以使用如下命令,将包记录到devDependencies节点中:

npm i 包名 -D

npm i 包名 --save-dev

可以使用如下命令,将包记录到dependencies节点中:

npm i 包名 -S

npm i 包名 --save

npm i 包名

npm镜像配置

# 查看当前的下包镜像源
npm config get registry
# 将下包的镜像源切换为淘宝镜像源
npm config set registry=https://registry.npm.taobao.org/
# 检查镜像源是否切换成功
npm config get registry

nrm工具
为了更方便的切换下包的镜像源,我们可以下载nrm这个小工具,利用nrm提供的终端命令,可以快速查看和切换下包的镜像源。

# 通过npm包管理器,将nrm安装为全局可用的工具
npm i nrm -g
# 查看所有可用的镜像源
nrm ls
# 将下包的镜像切换为淘宝镜像
nrm use taobao

包的分类

1.项目包
哪些被安装到项目的node_modules目录中的包,都是项目包

项目包又分为两类,分别是:

  1. 开发依赖包(被记录到devDependencies节点中的包,只在开发阶段会用到)
  2. 核心依赖包(被记录到dependencies节点中的包,在开发期间和项目上线后都会用到)

2.全局包
在执行npm install命令时,如果提供了-g参数,则会把包安装为全局包。
全局包会被默认安装到C:\Users\用户目录\AppData\Roaming\npm\node_modules目录下。

 # 全局安装指定的包
 npm i 包名 -g
 # 卸载全局安装的包
 npm uninstall 包名 -g

注意:1.只有工具性质的包,才有全局安装的必要性。因为它们提供了好用的终端命令
2.判断某个包是否需要全局安装后才能使用,可以参考官方提供的说明即可,即npm官网搜索该包

i5ting_toc工具

i5ting_toc是一个可以把md文档转化为html页面的小工具,使用步骤如下:

# 将i5ting_toc安装为全局包
npm install -g i5ting_toc
# 调用i5ting_toc,轻松实现md转html的功能
i5ting_toc -f 要转换的md文件路径 -o

规范的包结构

一个规范的包,它的组成结构,必须符合以下3点要求:
① 包必须以单独的目录而存在;
② 包的顶级目录下要必须包含package.json这个包管理配置文件;
③ package.json中必须包含name,version,main这三个属性,分别代表包的名字,版本号,包的入口。

在这里插入图片描述
定义转义HTML的方法

function htmlEscape(htmlStr) {
  return htmlStr.replace(/<|>|"|&/g, match => {
    switch (match) {
      case '<':
        return '&lt;';
      case '>':
        return '&gt;';
      case '"':
        return '&quot;';
      case '&':
        return '&amp;';
    }
  });
}

定义还原HTML的方法

function htmlUnEscape(str) {
  return str.replace(/&lt;|&gt;|&quot;|&amp;/g, match => {
    switch (match) {
      case '&lt;':
        return '<';
      case '&gt;':
        return '>';
      case '&quot;':
        return '"';
      case '&amp;':
        return '&';
    }
  });
}

发布包

1.注册npm账号,https://www.npmjs.com/

2.登录npm账户,根据提示操作即可

npm login

2.查看登录状态

npm whoami

3.到当前的插件项目的根目录,执行命令,完成发布

npm publish

发布npm包常见问题:
1.每次更新发布需要进行更新版本号;
2.发布的包名字不可以和已有的包库重复;
package.json 里边的name 是你的npm包发布的名称,keywords 是搜索你的包的关键字,description 是你的包描述,version 是你的版本号
3.需要将npm的源地址切换到npm最初的源地址上;

删除包

npm unpublish 包名 --force

删除npm包常见问题:
1.npm unpublish命令只能删除72小时以内发布的包;
2.npm unpublish删除的包,在24小时内不允许重复发布;

六、模块的加载机制

1.优先从缓存中加载

模块在第一次加载后会被缓存,这也意味着多次调用require()不会导致模块的代码被执行多次。
注意:不论是内置模块,用户自定义模块,还是第三方模块,它们都会优先从缓存中加载,从而提高模块的加载效率。
例:
m1.js

console.log('Hello');

m2.js

const m1 = require('./m1');
const m1 = require('./m1');
const m1 = require('./m1');
const m1 = require('./m1');

// 不管执行多少次require()方法,控制台只会打印一次"Hello"

2.内置模块的加载机制

内置模块是由Node.js官方提供的模块,内置模块的加载优先级最高;
例如,require(‘fs’);始终返回内置的fs模块,即使在node_modules目录下有名字相同的包也叫做fs。

3.自定义模块的加载机制

使用require()加载自定义模块时,必须指定以”./“或“…/”开头的路径标识符。在加载自定义模块时,如果没有指定./或…/这样的路径标识符,则node会把它当作内置模块或第三方模块进行加载。

同时,在使用require()导入自定义模块时,如果省略了文件的扩展名,则Node.js会按顺序分别尝试加载以下的文件:
① 按照确切的文件名进行加载;
② 补全.js扩展名进行加载;
③ 补全.json扩展名进行加载;
④ 补全.node扩展名进行加载;
⑤ 加载失败,终端报错;

若有test,test.js,test.json,test.node4个文件,那么会按以下顺序加载
test > test.js > test.json > test.node > 终端报错

4.第三方模块的加载机制

如果传递给require()的模块标识符不是一个内置模块,也没有以”./“或“…/”开头,则Node.js会从当前模块的父目录开始,尝试从/node_modules文件夹中加载第三方模块。
如果没有找到对应的第三方模块,则移动到再上一层父目录中,进行加载,直到文件系统的根目录。
例如:假设在‘C:‘\Users\kch\project\foo.js’文件中调用了require(‘tools’),则Node.js会按以下顺序查找:
① C:’\Users\kch\project\node_modules\tools
② C:‘\Users\kch\node_modules\tools
③ C:’\Users\node_modules\tools
④ C:'\node_modules\tools
直到盘符根目录找不到,就会报错,找不到模块。

5.目录作为模块

当把目录作为模块标识符,传递给require()进行加载的时候,有三种加载方式:
① 在被加载的目录下查找一个叫做package.json的文件,并寻找main属性,作为require()加载的入口;
② 如果目录里没有package.json文件,或者main入口不存在或无法解析,则Node.js将会试图加载目录下的index.js文件;
③ 如果以上两步都失败了,则Node.js会在终端打印错误消息,报告模块的缺失:Error:Cannot find modele ‘xxx’

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值