这是我参与「第四届青训营 」笔记创作活动的的第10天
本篇主要讲 node 的一些基础知识。
安装
//查询安装的node.js版本只需要在终端运行:
node -v
//即可查询到电脑所安装的版本号
fs文件系统模块
-
fs.writeFile()读取文件
fs.readFile(path[,options],callback)案例:
// 导入 fs 模块,来操作文件 const fs = require('fs') // 调用方法读取文件 // 参数1:读取文件的存放路径 // 参数2:读取文时采用的编码格式,一般默认指定 utf-8 // 参数3:回调函数,拿到读取失败和成功的结果 err datatStr fs.readFile('./11.txt','utf-8',(err,dataStr)=>{ // 打印失败的结果 console.log(err) console.log('-----------') console.log(dataStr) }) //如果成功,则err的值为null, //如果失败,则err打印的为错误对象,dataStr的值为 undefined判断文件是否读取成功
const fs = require('fs') fs.readFile('./1.txt','utf-8',(err,dataStr)=>{ if(err){ return console.log('文件读取失败'+err.message); }else{ console.log('文件读取成功'+dataStr); } }) -
fs.writeFile写入文件
fs.writeFile(path,data[,options],callback)案例:
const fs = require('fs') // 参数一:表示文件的存放路径 // 参数二:表示要写入的内容 // 参数三:回调函数 fs.writeFile('./2.txt','abcd',(e rr)=>{ // 如果文件写入成功,则 err 的值等于 null // 如果文件写入失败,则 err 的值等于一个错误对象 if(err){ console.log('文件写入失败',err.message); }else{ console.log('文件写入成功') } })练习:成绩管理
// 导入需要的 fs 文件系统模块 // 使用 readFile() 方法,读取素材目录下的 3.txt 文件 // 判断文件读取是否失败 // 文件读取成功后,处理成绩数据 const fs = require('fs') fs.readFile('./3.txt','utf-8',(err,dataStr)=>{ if(err){ return console.log('文件读取'+err.message) }else{ // console.log('文件读取读取成功'+dataStr) // 4.1先把成绩的数据,按照空格进行分隔 const arrOld = dataStr.split(' ') // 4.2循环分割后的数组,每一项数据,进行字符串的替换操作 const arrNew = [] arrOld.forEach(item=>{ arrNew.push(item.replace('=',':')) }) // 4.3把新数组中的每一项,进行合并,得到一个新的字符串 const newStr = arrNew.join('\r\n') // 4.4把处理完成的数据,写入到新文件当中 fs.writeFile('./4.txt',newStr,'utf-8',(err)=>{ if(err){ return console.log('文件写入失败'+err.message) } console.log('文件写入成功') }) } })
path模块处理路径模块
路径拼接时的问题
//我们在使用fs操作文件时,如果提供的路径是相对路径,浏览器会帮我们动态拼接这个文件路径,例如:
//根路径为 PS D:\前端workspace\笔记>
//然后fs模块中的路径为 ./01.txt
//此时,浏览器会帮我们拼接文件路径 D:\前端workspace\笔记\01.txt
//但如果路径拼接时搞错了根路径 比如D:\前端workspace
//此时拼接就会有问题
解决方式
-
使用绝对路径
这种方式的移植性非常的差,不利于后期的维护
-
使用__dirname
//__dirname表示当前文件的存放路径
const fs = require('fs')
fs.readFile(__dirname+'./1.txt','utf-8',(err,dataStr)=>{
if(err){
return console.log('文件读取失败'+err.message);
}else{
console.log('文件读取成功'+dataStr);
}
})
path模块的其他运用方法
-
path.join()
path.join([...paths])案例:
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,'./1.txt') console.log(pathStr2)//D:\前端workspace\笔记\你懂毛啊\node\code\内置path模块\1.txt -
path.basename()
// path.basename()获取路径中的文件名 //使用path.basename()方法,可以获取文件路径的最后一部分,经常通过这个方法获取路径中的文件名 //path.basename(path[,ext]) //path<string> 必选参数,标识一个路径的字符串 //ext<string>可选参数,表示文件的扩展名 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 //path.extname()可以获取路径中的扩展名部分 const fext = path.extname(fpath) console.log(fext)//输出.html
http模块
创建最基本的的服务器
// 1.导入 http 模块
const http = require('http')
// 2.创建 web 服务器实例
const server = http.createServer()
// 3.为服务器实例绑定 request 事件,监听客户端的请求
server.on('request',(req,res)=>{
console.log('Someone visit our web server.')
})
// 启动服务器
server.listen(8080,()=>{
console.log('server running at http://127.0.0.1:8080')
})
req和res对象
const http = require('http')
const server = http.createServer()
server.on('request',(req,res)=>{
// req.url 是客户端请求的 url 地址
const url = req.url
// req.method 是客户端请求的 method 类型
const method = req.method
const str = `你请求的 url 是 ${url} , 然后,你解决的方法是 ${method}`
// 调用 res.setHeader() 方法,设置 Content-type 响应头,解决中文乱码问题
res.setHeader('Content-Type','text/html;charset=utf-8')
// 调用 res.end() 方法,向客户端响应一些内容
res.end(str)
})
server.listen(8080,()=>{
console.log('server running at http://127.0.0.1:8080')
})
根据不同的url响应不同的html内容
const http = require('http')
const server = http.createServer()
server.on('request',function(req,res){
const url = req.url
let content = `<h1>404 NOT found!</h1>`//设置默认值为 404 NOT found
if(url==='/'||url==='/index.html'){
content = `<h1>首页</h1>`//用户请求的是首页
}else if(url==='/about.html'){
content = `<h1>关于页面</h1>`//用户请求的是关于页面
}
res.setHeader('Content-Type', 'text/html;charset=utf-8');
res.end(content)
})
server.listen(8888,()=>{
console.log('server running at http://127.0.0.1:8888');
})
模块化
模块的分类
- 内置模块:*内置模块是由Node.js官方提供的,例如fs,path,http等
- 自定义模块:*用户创建的每个js文件,都是自定义模块
- 第三方模块:*由第三方开发的模块,并非是官方提供的内置模块,也不是用户创建的自定义模块,使用前需要下载
加载模块
//1.加载内置的fs模块
const fs = require('fs')
//2.加载自定义模块
const custom = require('./custom.js')
//3.加载第三方模块
const monment = require('moment')
模块作用域
//1.js
const username = '张三'
function sayHello(){
console.log('大家好,我是'+username)
}
//2.js
const custom = require('./1.js')
console.log(custom)// {}
打印的对象是一个空对象,由此可以得出模块作用域的好处:防止全局污染,就是防止多个模块中定义相同的变量或者函数名,导致变量或者函数名之间相互覆盖,甚至会导致程序员不知道调用的到底是哪个变量或者函数名
向外共享模块作用域中的对象
CommonJS 规范
Nodejs 遵循了 CommonJS 模块化规范,CommonJS 规定了模块的特性和各模块之间呼和相互依赖。
- 每个模块内部,module 变量代表当前模块
- module 变量是一个对象,它的 exports 属性(即 module.exports) 是对外的接口。
- 加载某个模块,其实是加载该莫夸的 module.exports 属性。require 方法用于记载模块。
什么是module对象
每一个js自定义都有一个module对象,里面有很多属性,通过这些属性就能实现向外界共享数据
使用module.exports向外暴露对象
// 1.js
const username = '张三'
function sayHello(){
console.log('大家好,我是'+username)
}
module.exports = {
username,
sayHello
}
// 2.js
const custom = require('./1.js')
console.log(custom)
console.log(custom.username)
使用
require方法引入自定义模块的时候,实际上得到的就是module.exports对象且永远以module.exports为准。
module.exports.const username = '张三'
module.exports.function sayHello(){
console.log('大家好,我是'+username)
}
module.exports = {
name:'zs',
sayhi:()={
console.log('lalal')
}
}
//此时,该文件向外暴露的对象是 有name和sayhi 这两个变量的对象
使用 exports 向外暴露对象
由于 module.exports 单词写起来比较复杂,为了简化向外共享成员的代码,Node 提供了 exports 对象。默认情况下,exports 和 module.exports 指向同一个对象。
console.log(module.exports === exports) // ture
但是,最终共享的结果,还是以 module.exports 指向的对象为准。
const username = '张三'
function sayHello(){
console.log('大家好,我是'+username)
}
exports = {
username
}
上面这里,exports重新创建了一个对象并指向它,此时,exports 对象中的确有 username 这个属性,但是,module.exports对象中没有任何属性,所以引用过后是一个空对象
下面,我们可以进行一些小练习:
更多关于CommonJS具体的内容请参考CommonJS规范 -- JavaScript 标准参考教程(alpha) (ruanyifeng.com)
模块的加载机制
优先从模块中进行加载
模块在第一次加载之后会被缓存,这也意味着多次调用require()不会执行代码多次,注意,无论是内置模块,用户自定义模块,还是第三方模块,他们都会优先从缓存中加载,从而提高模块的加载效率。
//1.js
console.log('ok')
//2.js
require('./1.js')
require('./1.js')
require('./1.js')
//结果只会打印一次ok
内置模块的加载机制
内置模块是由node.js官方提供的模块,内置模块的加载优先级最高。
例如:require('fs')始终返回内置的fs模块,即使在node_modules目录下有名字相同的包也叫作fs
自定义模块加载机制
在使用require()加载自定义模块时,必须制定./或../开头的路径标识符。在加载自定义模块时,如果没有制定./或../这样的路径标识符,则node会把它当做内置模块或第三方模块进行加载。
同时,在使用require()导入自定义模块时,如果省略了文件的扩展名,则node.js会按照顺序分别尝试加载以下的文件:
- 按照确切的文件名进行加载
- 补全.js扩展名进行加载
- 补全.json扩展名进行加载
- 补全.node扩展名进行加载
- 加载失败,终端报错
第三方模块的加载机制
如果传递给require()的模块标识符不是一个内置模块,也没有以./或../开头,则node.js会从当前模块的父目录开始,尝试从/node_modules文件夹中加载第三方模块。
例如,假设在C:\User\code\project\foo.js文件里调用了require('tools'),则node.js会按以下的顺序查找。
C:\User\code\project\node_modules\toolsC:\User\code\node_modules\toolsC:\User\node_modules\toolsC:\node_modules\tools
目录作为模块
当把目录作为标识符,传递给require()进行加载的时候,有三种加载方式:
- 在被加载的目录下查找一个叫做
package.json的文件,并寻找main属性,作为require()加载的入口
一般来说,main节点中的入口是index.js
- 如果目录里没有
package.json文件,或者main入口不存在或无法解析,则Node.js将会尝试加载目录下的index.js - 如果以上两步都失败了,则Node.js会在终端打印错误消息,报告莫夸的缺失:
Error:Cannot find module 'xxx'
结语
文章如果有不正确的地方,欢迎指正,共同学习,共同进步。
若有侵权,请联系作者删除。