浏览器中有JavaScript解析引擎
不同的浏览器使用不同的JavaScript解析引擎
chrome 浏览器的 V8解析引擎性能最好
每个浏览器都内置了 DOM api BOM api Ajax api ,通过JavaScript解析引擎执行。浏览器中的JavaScript才可以调用他们
运行环境是指代码正常运行所需的必要环境
chrome 浏览器运行环境:V8引擎、内置api,然后就可以写JavaScript代码,然后交给 V8引擎解析
后端开发主要语言:Java python PHP
JavaScript可以借助node.js来做后端开发
node.js 是 一个基于 chrome V8 引擎 的JavaScript 运行环境
官网:https://node.js.org/zh-cn/
总之:node.js 是大前端时代的 大宝剑,有了node.js 这个超级 buff 的加持,前端程序员的行业竞争力会越来越强
node.js 内置 api 模块
第三方 api模板
LTS 和 Current 版本的不同
安装方法,一路 next 即可
打开终端,在终端输入命令 node -v 后,按下回车键,即可
终端是专门为开发人员设计的,用于实现人机交互的一种方式
作为一名合格的程序员,我们有必要识记一些常用的终端命令,来辅助我们更好的操作与使用计算机
注意: cd 是切换目录
F:\>cd F:\黑马年度班2020.8.30\四阶段前后端交 互\第四章node.js\代码 F:\黑马年度班2020.8.30\四阶段前后端交互\第四 章node.js\代码>node 01.js HEllo 你好
fs 模块是 node.js 官方提供的、用来操作文件的模块。它提供了一系列的方法和属性,用来满足用户对文件的操作需求
如果要在JavaScript代码中,使用 fs 模块来操作文件,则需要使用如下的方式导入它
const fs = require('fs') // 使用 require 函数 来导入 // fs 输出后 是一个对象,包含很多东西
fs.readFile() 的语法格式
fs.readFile(path[,options],callback)
const fs = require('fs') /* require就是一个引入函数,在此处引入的是fs模块 */ fs.readFile('./files/1.txt', 'utf8', function (err, dataStr) { /* 第一个参数 是路径 第二个参数 是编码格式,一般默认指定utf8 第三个参数中的第一个形参是失败的结果 第三个参数中的第一个形参是成功的结果 */ console.log(err); console.log('-------'); console.log(dataStr); // 如果读取成功则err的值为null,dataStr的值是文件的内容 // 如果读取失败则err的值为错误对象,dataStr的值是undefined /* 结果为: null ------- 111 */ })
const fs = require('fs') /* require就是一个引入函数,在此处引入的是fs模块 */ fs.readFile('./files/11.txt', 'utf8', function (err, dataStr) { if (err) { return console.log("文件读取失败!" + err.message); } console.log('文件读读取成功,内容是:' + dataStr); })
fs.writeFile(file,data[,options],callback) // 参数1:必选参数,需要指定一个文件路径的字符串,表示文件存放路径 // 参数2:必选参数,表示要写入的内容 // 参数3:可选参数,表示以什么格式写入文件内容,默认值是utf8 // 参数4:必选参数,文件写入完成后的回调函数
// 1、导入 fs 文件系统模块 const fs = require('fs') // 2、调用fs的writeFile方法 // 第一个参数是存放文件的路径,第二个是内容,第三个是回调函数 fs.writeFile('./files/2.txt', 'abcde', function (err) { // 文件写入成功则err的值等于null // 文件写入失败则err的值等于错误对象 console.log(err); })
// 1、导入 fs 文件系统模块 const fs = require('fs') // 2、调用fs的writeFile方法 // 第一个参数是存放文件的路径,第二个是内容,第三个是回调函数 fs.writeFile('./files/2.txt', 'abcdefg', function (err) { // 文件写入成功则err的值等于null // 文件写入失败则err的值等于错误对象 if (err) { return console.log('写入内容失败'); } console.log('写入内容成功'); })
数据没有整理前
小红=99 小李=100 呆呆=180 张三=59
数据整理后
小红:99 小李:100 呆呆:180 张三:59
const fs = require('fs') fs.readFile('./files/成绩.txt', 'utf8', function (err, dataStr) { if (err) { return console.log('读取成绩失败!'); } console.log('读取成绩成功!!!'); // 1、先按照空格,把这些数据分隔成数组 const dataOld = dataStr.split(' ') // [ '小红=99', '小白=100', '小黄=70', '小黑=66', '小绿=88' ] const arrNew = [] // forEach 循环遍历数组的每一项 dataOld.forEach((value) => { arrNew.push(value.replace('=', ':')) }) console.log(arrNew); // 2、循环分隔后的数组,对每一项的数据进行字符串的替换操作 // '\r\n' 就表示回车换行 console.log(arrNew.join('\r\n')); })
const fs = require('fs') fs.readFile('./files/成绩.txt', 'utf8', function (err, dataStr) { if (err) { return console.log('读取成绩失败!'); } console.log('读取成绩成功!!!'); // 1、先按照空格,把这些数据分隔成数组 const dataOld = dataStr.split(' ') // [ '小红=99', '小白=100', '小黄=70', '小黑=66', '小绿=88' ] const arrNew = [] // forEach 循环遍历数组的每一项 dataOld.forEach((value) => { arrNew.push(value.replace('=', ':')) }) console.log(arrNew); // 2、循环分隔后的数组,对每一项的数据进行字符串的替换操作 // '\r\n' 就表示回车换行 const newStr = arrNew.join('\r\n') console.log(arrNew.join('\r\n')); fs.writeFile('./files/成绩-ok.txt', newStr, function (err) { if (err) { return console.log('写入文件失败'); } console.log('写入文件成功'); }) })
在使用fs模块操作文件时,如果提供的操作路径是以 ./ 或 …/ 开头的相对路径时,很容易出现路径动态拼接错误的问题
原因:代码在运行的时候,会以执行 node 命令时所处的目录,动态拼接出被操作文件的完整路径
出现问题是因为提供了 ./ …/ 开头的相对路径
想要解决这个问题,可以直接提供一个完整的文件存放路径就行
// 1、导入 fs 文件系统模块 const fs = require('fs') // 注意在js中一个斜线表示转义,两个斜线才表示一个真正的斜线 // 移植性非常差,不利于维护 fs.readFile('F:\\黑马年度班2020.8.30\\四阶段前后端交互\\第四章node.js\\代码\\07-绝对路径.js', 'utf8', function (err, dataStr) { if (err) { return console.log('读取失败'); } console.log('读取成功'); })
__dirname表示当前文件所处的目录
// 1、导入 fs 文件系统模块 const fs = require('fs') // 注意在js中一个斜线表示转义,两个斜线才表示一个真正的斜线 // 移植性非常差,不利于维护 // __dirname 获得当前执行文件所在目录的完整目录名,这个值不会跟着node所在的执行目录改变 fs.readFile(__dirname + '/files/1.txt', 'utf8', function (err, dataStr) { if (err) { return console.log('读取失败'); } console.log('读取成功'); }) console.log(__dirname);//F:\黑马年度班2020.8.30\四阶段前后端交互\第四章node.js\代码
path 模块是 node.js 官方提供的、用来处理路径的模块。它提供了一系列的方法和属性,用来满足用户对路径的处理需求
1、path.join()的语法格式
使用path.join()方法,可以把多个路径片段拼接为完整的路径字符串,语法格式如下:
path.join([...paths])
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)// 输出 当前文件所在目录\files\1.txt
今后凡是涉及到路径拼接的操作,都要使用 path.join() 方法进行处理,不要直接使用 + 进行字符串的拼接
使用 path.basename()方法,可以获取路径中的最后一部分,经常通过找个方法获取路径中文件名,语法格式如下:
path.basename(path[,ext])
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
注意,如果写了两个参数,那么它的返回值,只有文件名,没有文件的格式,如果写了一个参数,那么它的返回值,会有文件名和文件的格式
path.extname(path)
const path = require('path') const fpath = '/a/b/c/index.html' // 路径字符串 const fext = path.extname(fpath) console.log(fext); // 输出 .html
案例要实现的功能
案例的实现步骤
// 导入 fs path 模块 const fs = require('fs') const path = require('path') // 匹配 <style></style> 标签的正则 // \s 表示空白字符,\S 表示非空白字符,*号表示匹配任意次 // style标签的 斜线会和正则的斜线冲突,需要转义 const regStyle = /<style>[\s\S]*<\/style>/ const regScript = /<script>[\s\S]*<\/script>/
// 导入 fs path 模块 const fs = require('fs') const path = require('path') // 匹配 <style></style> 标签的正则 // \s 表示空白字符,\S 表示非空白字符,*号表示匹配任意次 // style标签的 斜线会和正则的斜线冲突,需要转义 const regStyle = /<style>[\s\S]*<\/style>/ // 处理 css 样式 function resolveCSS(htmlStr) { // 提取到 style标签的所有内容 const r1 = regStyle.exec(htmlStr) // 将提取的内容做进一步处理 const newCSS = r1[0].replace('<style>', '').replace('</style>', '') // 写入到 index.css文件中 fs.writeFile(path.join(__dirname, './clock/index.css'), newCSS, err => { if (err) { return console.log('写入文件失败!'); } console.log('写入成功!'); }) }
// 导入 fs path 模块 const fs = require('fs') const path = require('path') const regScript = /<script>[\s\S]*<\/script>/ function resolveJS(htmlStr) { // 提取到 style标签的所有内容 const r2 = regScript.exec(htmlStr) // 将提取的内容做进一步处理 const newJS = r2[0].replace('<script>', '').replace('</script>', '') // 写入到 index.css文件中 fs.writeFile(path.join(__dirname, './clock/index.js'), newJS, err => { if (err) { return console.log('写入文件失败!'); } console.log('写入成功JavaScript!'); }) }
function resolveHTML(htmlStr) { const newHTML = htmlStr.replace(regStyle, '<link rel="stylesheet" href="./index.css">').replace(regScript, '<script src="./index.js"></script>') fs.writeFile(path.join(__dirname, './clock/index.html'), newHTML, err => { if (err) { return console.log('写入文件失败!'); } console.log('写入成功JavaScript!'); }) }
- writeFile 方法,的路径,中的那个文件必须先创建
- 重复调用writefile 方法 最新的会覆盖掉以前的
// 导入 fs path 模块 const fs = require('fs') const path = require('path') // 匹配 <style></style> 标签的正则 // \s 表示空白字符,\S 表示非空白字符,*号表示匹配任意次 // style标签的 斜线会和正则的斜线冲突,需要转义 const regStyle = /<style>[\s\S]*<\/style>/ const regScript = /<script>[\s\S]*<\/script>/ fs.readFile(path.join(__dirname, './index.html'), 'utf8', (function (err, dataStr) { // 读取文件失败的适合 if (err) { return console.log('读取HTML文件失败'); } // 读取成功后,调用对应的方法,拆解出 css js html 文件 resolveCSS(dataStr) resolveJS(dataStr) resolveHTML(dataStr) })) // 处理 css 样式 function resolveCSS(htmlStr) { // 提取到 style标签的所有内容 const r1 = regStyle.exec(htmlStr) // 将提取的内容做进一步处理 const newCSS = r1[0].replace('<style>', '').replace('</style>', '') // 写入到 index.css文件中 fs.writeFile(path.join(__dirname, './clock/index.css'), newCSS, err => { if (err) { return console.log('写入文件失败!'); } console.log('写入成功CSS!'); }) } function resolveJS(htmlStr) { // 提取到 style标签的所有内容 const r2 = regScript.exec(htmlStr) // 将提取的内容做进一步处理 const newJS = r2[0].replace('<script>', '').replace('</script>', '') // 写入到 index.css文件中 fs.writeFile(path.join(__dirname, './clock/index.js'), newJS, err => { if (err) { return console.log('写入文件失败!'); } console.log('写入成功JavaScript!'); }) } function resolveHTML(htmlStr) { const newHTML = htmlStr.replace(regStyle, '<link rel="stylesheet" href="./index.css">').replace(regScript, '<script src="./index.js"></script>') fs.writeFile(path.join(__dirname, './clock/index.html'), newHTML, err => { if (err) { return console.log('写入文件失败!'); } console.log('写入成功JavaScript!'); }) }
客户端就是负责消费资源的电脑,服务器:负责对外提供网络资源
http模块是 node.js 官方提供的、用来创建web服务器的模块,通过http模块提供的 http.createServer() 方法,就能方便的把一台普通的电脑,变成一台web服务器,从而对外提供web资源服务
如果希望使用 http 模块创建web服务器,则需要先导入它
const http=require('http')
服务器和普通电脑的区别在于,服务器安装了 web服务器软件,例如:IIS、Apache等。通过安装这些服务器软件,就能把一台普通的电脑编程一台web服务器。
在node.js中,我们不需要使用 IIS、Apache 等这些 第三方web服务器软件。因为我们可以基于node.js提供的 http 模块,通过几行简单的代码,就能轻松的手写一个服务器软件,从而对外提供 web 服务
IP地址就是互联网上每一台计算机的唯一地址,因为 IP地址具有唯一性,如果把 “个人电脑” 比作 “ 一台电话” ,那么 “IP地址” 就相当于 “ 电话号码” ,只有在知道对方 IP 地址的前提下,才能与对应的电脑之间进行数据通信
IP地址的格式:通常用 “点分十进制 ” 表示(a,b,c,d)的形式,其中a,b,c,d都是 0~255 之间的十进制整数,例如:用点分十进制表示的IP地址(192.168.1.1)
尽管 ip 地址能够唯一地标记网络上的计算机,但 IP 地址是一长串数字,不直观,而且不方便记忆,于是人们发明了另一套字符型的地址方案,即所谓的域名地址
IP 地址 和 域名 是 一 一 对应的关系,这份对应关系放在一种叫域名服务器(DNS)的电脑中,使用者只需要通过好记的域名访问对应的服务器即可,对应的转换工作由域名服务器实现。因此,域名服务器就是提供 IP 地址和域名之间的转换服务的服务器
计算机中的端口,就好像是现实生活中的门牌号一样,通过门牌号,外卖小哥可以在整栋大楼众多的房间中,准确把外卖送到你的手中
同样的道理,在一台电脑中,可以运行成百上千个web服务。每个web服务都对应一个唯一的端口号。客户端发送过来的网络请求,通过端口号,可以被准确的交给对应的web服务进行处理
// 1、导入http模块 const http = require('http') // 2、创建web服务器实例 const server = http.createServer() // 3、为服务器实例绑定 request 事件,监听客户端请求 // 只要有人请求这个地址,就会触发 request 事件 server.on('request', function (req, res) { console.log('Someone vist our web server.'); }) // 4、启动服务器 // listen的参数(端口号,回调函数) server.listen(80, function () { console.log('server running at http://127.0.0.1:80'); }) // 运行在 80 端口 可以省略,非80端口不可以省略
只要服务器接收到了客户端的请求,就会调用通过 server.on() 为服务器绑定的 request 事件处理函数
如果想在事件处理函数中,访问与客户端相关的数据或属性,可以使用如下的方式:
ctrl +c 终止服务器
// 1、导入http模块 const http = require('http') // 2、创建web服务器实例 const server = http.createServer() // 3、为服务器实例绑定 request 事件,监听客户端请求 // 只要有人请求这个地址,就会触发 request 事件 server.on('request', function (req, res) { console.log(req.method); console.log(req.url); console.log('Someone vist our web server.'); }) // 4、启动服务器 server.listen(80, function () { console.log('server running at http://127.0.0.1:80'); }) // 运行在 80 端口 可以省略,非80端口不可以省略 输出的结果 // 输出的URL 是从 斜线后面开始的 Someone vist our web server. GET /
在服务器的 request 事件处理函数中,如果想访问与服务器相关的数据或者属性,可以使用如下的方式
server.on('request', function (req, res) { console.log(req.method); console.log(req.url); console.log('Someone vist our web server.'); console.log(res.end('响应回去的数据')); })
res.setHeader('Content-Type', 'text/html;charset=utf-8')
server.on('request', function (req, res) { console.log(req.method); console.log(req.url); console.log('Someone vist our web server.'); res.setHeader('Content-Type', 'text/html;charset=utf-8') console.log(res.end('响应回去的数据')); })
在地址栏输入 127.0.0.1 后,会在页面显示 响应回去的数据
const http = require('http') const server = http.createServer(); server.on('request', (req, res) => { const url = req.url // 获取用户请求的url let content = `<h1>404 not found</h1>` 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(80, function () { console.log('server running at http://127.0.0.1:80'); })
把文件的实际存放路径,作为每个资源的请求url地址
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0KXG6ybV-1620388232597)(node.assets/image-20201003215051711.png)]
// 1、导入node三大模块 const http =require('http') const fs =require('fs') const path = require('path') // 2、创建web服务器 const server = http.createServer() server.on('request', (req, res) => { }) server.listen(80, () => { console.log('server running at http://127.0.0.1'); } )
server.on('request', (req, res) => { // 获取i请求的url 地址 /* /clock/index.html /clock/index.css /clock/index.js */ const url = req.url // 把请求的url地址映射为具体文件的存放路径 const fpath = path.join(__dirname, url) })
// http://127.0.0.1/clock/index.html // 1、导入node三大模块 const http = require('http') const fs = require('fs') const path = require('path') // 2、创建web服务器 const server = http.createServer() server.on('request', (req, res) => { res.setHeader('Content-Type', 'text/html;charset=utf-8') // 获取i请求的url 地址 /* /clock/index.html /clock/index.css /clock/index.js */ const url = req.url // 把请求的url地址映射为具体文件的存放路径 const fpath = path.join(__dirname, url) // 根据映射过来的文件路径读取文件 fs.readFile(fpath, 'utf8', (err, dataStr) => { // 若读取失败 if (err) { return res.end('404 Not fount!!') } // √ res.end(dataStr) }) }) server.listen(80, () => { console.log('server running at http://127.0.0.1'); })
// http://127.0.0.1/clock/index.html // 1、导入node三大模块 const http = require('http') const fs = require('fs') const path = require('path') // 2、创建web服务器 const server = http.createServer() server.on('request', (req, res) => { // res.setHeader('Content-Type', 'text/html;charset=utf-8') // 获取i请求的url 地址 /* /clock/index.html /clock/index.css /clock/index.js */ const url = req.url // 把请求的url地址映射为具体文件的存放路径 //const fpath = path.join(__dirname, url) let fpath = '' if (url == '/') { fpath = path.join(__dirname, './clock/index.html') console.log(fpath); } else { fpath = path.join(__dirname, '/clock', url) } // 根据映射过来的文件路径读取文件 fs.readFile(fpath, 'utf8', (err, dataStr) => { // 若读取失败 if (err) { return res.end('404 Not fount!!') } // √ res.end(dataStr) }) }) server.listen(80, () => { console.log('server running at http://127.0.0.1'); })
模块化是指解决一个复杂问题时,自顶向下逐层把系统划分成若干模块的过程,对于整个系统来说,模块时可组合、分解、更换的单袁
就是遵守固定的 规则,把一个大文件拆成独立并相互依赖的多个小模块
模块化规范就是对代码进行模块化的拆分和组合时,需要遵守的那些规则
- 使用什么样的语法格式来引用模块
- 在模块中使用什么杨的语法格式向外暴露成员
模块化规范的好处:大家都遵守同样的模块化规范写代码,降低了沟通的成本,极大方便了各个模块之间的相互调用,利人利己
使用强大的 require() 方法,可以加载需要的内置模块、用户自定义模块、第三方模块进行使用。
注意:使用 require()方法加载其他模块时,会执行被加载模块中的代码
// 加载内置的fs 模块 const fs = require('fs') // 加载用户的自定义模块 const custom = require('./01.js') // 加载第三方模块 const moment = require('moment')
const m1 =require('./06.m1.js') console.log(m1)// {}
注意:用require导入自定义模块的一瞬间,就会执行你整个自定义模块的所有代码,然后你的 m1 变量的输出是 { } 空对象
模块化作用域:和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内访问,这种模块级别的访问限制,叫做模块化作用域
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-whcepPvY-1620388232600)(node.assets/image-20201004171307617.png)]
模块作用域的好处
// 17-模块作用域 const username = "张三" function sayHello() { console.log('大家后' + username); } // 18-17测试 const custom = require('./17-模块作用域') console.log(custom); // 最后输出的是 {}
在每个 .js 自定义模块中都有一个module对象,它里面存储了和当前模块有关的信息,打印如下
Module { id: '.', path: 'F:\\黑马年度班2020.8.30\\四阶段前后端交互\\第四章node.js\\代码', exports: {}, parent: null, filename: 'F:\\黑马年度班2020.8.30\\四阶段前后端交互\\第四章node.js\\代码\\17-模块作用域.js', loaded: false, children: [], paths: [ 'F:\\黑马年度班2020.8.30\\四阶段前后端交互\\第四章node.js\\代码\\node_modules', 'F:\\黑马年度班2020.8.30\\四阶段前后端交互\\第四章node.js\\node_modules', 'F:\\黑马年度班2020.8.30\\四阶段前后端交互\\node_modules', 'F:\\黑马年度班2020.8.30\\node_modules', 'F:\\node_modules' ] }
我们可以通过 exports 向外共享成员
在自定义模块中,可以使用 module.exports 对象,将模块内的成员共享出去,供外界使用
外界用 require()方法导入自定义模块时,得到的就是 module.exports 所指向的对象
// 在一个自定义模块中,默认情况下,module.exports={} // 在外界使用 require导入自定义模块的时候,得到的成员,就是那个模块 中 module.exports 指向的那个对象 const m = require('./19-自定义模块.js') console.log(m);// {}
// 19-自定义模块 // 在一个自定义模块中,默认情况下,module.exports={} const age = 20 // 向module.exports 对象上挂载 username 属性 module.exports.username = '张三' // 向module.exports 对象上挂载 sayHello 方法 module.exports.sayHello = function () { console.log('Hello'); } // 向module.exports 对象上挂载 age 属性 module.exports.age = age //20-测试19 // 在外界使用 require导入自定义模块的时候,得到的成员,就是那个模块 中 module.exports 指向的那个对象 const m = require('./19-自定义模块.js') console.log(m);//{ username: '张三', sayHello: [Function], age: 20 }
使用require方法导入模块时,导入的结果,永远以module.exports指向的对象为准
即以 module.exports 最新的指向为准
// 21-共享成员的注意点 const age = 20 // 向module.exports 对象上挂载 username 属性 module.exports.username = '张三' // 向module.exports 对象上挂载 sayHello 方法 module.exports.sayHello = function () { console.log('Hello'); } // 向module.exports 对象上挂载 age 属性 module.exports.age = age // 让 module.exports 指向全新的对象 module.exports = { nickname: '小黑', sayHi: function () { console.log('hi'); } } // 22-测试21 const m = require('./21-共享成员的注意点.js') console.log(m);//{ nickname: '小黑', sayHi: [Function: sayHi] }
由于 module.exports 单词写起来比较复杂,为了简化向外共享成员的代码,Node 提供了 exports 对象。默认情况下,exports 和 module.exports 指向同一个对象。最终共享的结果,还是以 module.exports 指向的对象为准
时刻谨记,require()模块时,得到的永远是 module.exports 指向的对象
exports.username = 'zs' module.exports = { gender: '男', age: 22 } // 最后输出的是 {gender:'男',age:22}
module.exports.username='zs' exports={ gender:'男', age:22 } // 最后输出的结果是:{username:'zs'}
exports.username='zs' module.exports.gender='男' // 最终输出的结果是:{username:'zs',gender:'男'}
exports={ username:'zs', gender:'男' } module.exports=exports module.exports.age='22' // 最终输出的结果是:{username:'zs',gender:'男',age:'22'}
commonJS规定