一、什么是 node?
一个基于 Chrome V8 解析引擎的 JavaScript 运行时环境
1、由来 :
- 把浏览器内的 JS 解析引擎拿出来, 和其他的内容进行组装
- 变成一个 新的内容, 叫做 NodeJS
2、前端 JS 和 NodeJS 的区别
1、
- 前端 JS
- 当 JS 被引入到 HTML 文件中, 放在浏览器中执行的时候 (JS 的组成: BOM + DOM + ECMAScript)
- 他在这个时候, 才会有所谓的 BOM 和 DOM
- BOM: 浏览器对象模型 浏览器提供给我们的
- DOM: 文档对象模型 HTML 提供给我们的
- 当 JS 被引入到 HTML 文件中, 放在浏览器中执行的时候 (JS 的组成: BOM + DOM + ECMAScript)
- NodeJS
- 把 JS 从 HTML 文件中拿出来, 放在 电脑系统中直接运行
- 此时没有所谓的 DOM 和 BOM
- 但是因为是在 电脑系统中运行
- 可以操作 文件/文件夹 (I/O; input/output)
- 可以操作电脑系统
- 可以操作数据库
- ...
2、
- 前端 JS
- 运行时可以操作模块发开发(ES6 模块化), 也可以采用非模块开发
- 为什么可以采用非模块化
- 因为我们把所有的 JS 文件, 引入到某一个 HTML 文件中, 去使用
- NodeJS
- 运行时 必须采用 模块化开发
- 因为他是直接执行 JS 文件, 没有一个统一的 html 文件去引入所有的 JS 文件
- 使用的 模块化语法 是 CommonJS
3、JS 中 代码是没有错误的
- 关键是我们要把 JS 运行在那个环境(要把代码运行在哪里)
- 假设 将来需要把这个 JS 文件放在前端使用(引入到 HTML, 并运行在浏览器中)
- 那么可以在 JS 中书写 BOM 和 DOM 相关的东西
- 假设 将来需要把这个 JS 文件放在 NODEJS 中使用
- 那么就不能在 JS 中书写 DOM 和 BOM 相关的 东西
- 但是 此时可以书写 操作 文件/文件夹相关的代码
4、NodeJS 的作用
- 按照 CommonJS 模块化开发语法的规范进行书写代码
- 能够 使用 JS 这个语言 进行后端代码的开发
二、命令行基本操作
注意: 此处仅为了能够满足使用 nodejs
-
什么是 命令行
- 个人喜欢叫: "小黑窗/黑窗口"
- win: cmd / powerShell
-
打开 小黑窗
- win
- 方式 1
- 然下 win + r 键
- 输入 cmd 后按下回车 注意: 打开的是电脑系统个人目录
- 方式 2
- 进入某个文件夹
- 在地址栏位置输入 cmd 按下回车 注意: 打开的是 当前文件夹下的
- 方式 1
- win
-
认识小黑窗
- 最开始的位置有一个东西 表明的是文件结构, 就是当前这个小黑窗是在那个文件夹内的
-
黑窗口的指令
- 查看当前目录下的内容
- 输入指令: dir
- 切换目录
- 输入指令: cd 文件夹名称
- 退回上一级目录
- 输入指令: cd ..
- 清屏
- win: cls
- mac: clear
- 查看当前目录下的内容
三、如何利用 node 执行 js 代码
- 因为 node 是直接在电脑操作系统上进行 JS 代码的执行
- 其实就是 在 小黑窗 内直接执行 JS 文件
- 小黑窗内执行 JS 代码
- 方式 1:
- 打开 小黑窗, 目录无所谓
- 输入命令: node 按下回车
- 会进入 JS 代码编辑模式
- 此时是不能执行 cmd 命令的, 只能书写 JS 代码
- 按下 ctrl + c 退出当前环境
- 缺点: 书写的代码无法保存
- 方式 2:
- 把你要执行的 JS 代码 书写在一个 .js 文件内
- 打开命令行, 切换目录到 JS 文件所在的目录
- 输入指令: node 文件名
- 方式 1:
四、node 模块化开发
- node 必须模块化开发
- node 自带的所有内容都是以模块的形式出现的
- 模块化语法
- 导出
- 每一个 JS 文件天生自带一个变量叫做 module
- 表示的是当前自己这个模块的所有信息
- 每一个文件默认导出一个对象
- 语法:
- 如果你想向默认导出的对象内添加成员
- module.exports.属性名 = 属性值
- exports.属性名 = 属性值
- node 的 每一个 JS 文件, 内部天生自带一个 变量 叫做 exports
- 变量内部存放的是 指向 module.exports 这个对象的 地址
- 如果你想修改这个默认导出的内容
- module.exports = 值
- 如果你想向默认导出的对象内添加成员
1、给 module.exports 直接赋值 (任意类型无所谓)
module.exports = 'QF001'
module.exports = 10086
module.exports = true
module.exports = false
module.exports = [1, 2, 3]
module.exports = function () {
console.log("你好");
};
module.exports = () => {
console.log("你好");
};
const obj = {
id: 'QF001',
name: '张三',
age: 18
}
module.exports = obj
console.log(module)
2、给 module.exports 这个对象内添加一些属性 (属性的值无所谓)
module.exports.id = 'QF001'
module.exports.name = '张三'
module.exports.age = 18
// 因为 module.exports 和 exports 是同一个地址, 所以此时的代码会修改原本的 name 值
exports.name = '李四'
exports.info = {
w: 10086,
h: 10010
}
3、给 exports 这个对象内添加一些属性 (属性的值无所谓)
module.exports.id = 'QF001'
module.exports.name = '张三'
module.exports.age = 18
// 因为 module.exports 和 exports 是同一个地址, 所以此时的代码会修改原本的 name 值
exports.name = '李四'
exports.info = {
w: 10086,
h: 10010
}
// /**
// * 此时我们会切断 exports 和 module.exports 之间的关联
// * 所以这行代码没有导出的功能
// */
exports = [1, 2, 3, 4, 5]
// /**
// * 因为上边的一行代码将 exports 和 module.exports 之间的关联 切断了
// * 所以现在的这个 name 属性 不会生效
// */
exports.name = '王五'
console.log('导出的内容, 在你导入的时候我会执行一遍', module.exports)
- 导入
- 每一个 JS 文件天生自带一个方法叫做 require()
- 语法: require('地址') 注意: 如果地址书写的时候, 文件后缀是 .js, 那么可以省略后缀不写
- 返回值: 该文件的 module.exports (该文件向外暴露的内容)
/**
* 在 node 中 导入的文件如果后缀是 .js 那么可以省略后缀
*
* 导入文件的时候会先将这个文件整体执行一遍
* 然后将 导出的内容, 拿到当前文件内
*/
const res = require('./04_node的模块化')
console.log('导入的数据: ', res)
- 模块分类
- 自定义模块: 自己写的 JS 文件
- 内置模块: node 给我们提供的模块, 直接引入使用即可
- 第三方模块
- 由其他人写好上传到某一个仓库内(npm)
- 我们去这个仓库内(npm)下载到本地, 然后引入使用
五、node 内置模块 fs
node 给出的内置模块, 专门用来操作 文件/文件夹
const fs = require('fs')
console.log(fs)
-
异步读取文件
- 语法: fs.readFile(文件路径, 配置参数, 回调函数)
- 参数:
- 文件路径: 必填
- 配置参数: 不写默认是 buffer 可以手动配置为 utf-8
- 回调函数: 必填, 接受两个参数, 第一个为报错信息, 第二个为正确读取到的文件的内容(字符串格式的)
fs.readFile("./index1.txt", "utf-8", (error, data) => { if (error) return console.log(error); console.log(data); }); -
同步读取文件
let str = fs.readFileSync("./index1.txt", "utf-8"); console.log(str); -
异步写入文件
- 语法: fs.writeFile(文件地址, 写入内容, 回调函数)
- 参数:
- 文件地址:
- 这个文件, 直接讲内容写入到指定文件内
- 没有这个文件, 创建一个出来, 然后写入到指定文件内
- 写入内容:
- 符串格式的内容, 将这段文本直接写入到指定文件中, 并覆盖这个文件之前的所有内容
- 回调函数:
- 必写, 哪怕这个函数什么也不做, 也必须要写
- 文件地址:
fs.writeFile("./index.txt", "你好 世界", () => { console.log("写入完成"); }); -
同步写入文件
fs.writeFileSync("./index.txt", "hello word"); console.log("node end"); -
向文件内 追加数据
fs.appendFile('./index.txt', '我是一个新加入的文本', () => {})
六、内置模块 path
node 自带的模块, 专门用于和路径相关的操作
const path = require("path");
console.log(path);
- 绝对路径
- C:/a/b/c/d.html
- 相对路径
- ./d.html
- ../c/d.html
- 组装一个相对路径 path.join(路径片段 1, 路径片段 2, 路径片段 3)
const res = path.join("a", "b/c", "d", "e.html"); console.log(res); // a\b\c\d\e.html - 组装一个绝对路径 path.resolve(路径片段 1, 路径片段 2, 路径片段 3)
const res1 = path.resolve("a", "b/c", "d", "e.html"); const res2 = path.resolve("C:", "b/c", "d", "e.html"); console.log(res1); // C:\Users\41099\Desktop\qianfeng-prepares-lessons\06_周\05_天\code\06_内置模块path\a\b\c\d\e.html console.log(res2); // D:\b\c\d\e.html - 组装一个解析路径 path.parse(路径)
const res = path.parse( "C:/Users/41099/Desktop/qianfeng-prepares-lessons/06_周/05_天/code/06_内置模块path/a/b/c/d/e.html" ); console.log(res); /* { // 根路径 root: 'C:/', // 完整文件目录(截止到目录, 不会到文件) dir: 'C:/Users/41099/Desktop/qianfeng-prepares-lessons/06_周/05_天/code/06_内置模块path/a/b/c/d', // 完整文件名 base: 'e.html', // 文件后缀名 ext: '.html', // 文件名 name: 'e' } */
七、内置模块 url
node 自带的模块, 专门用来操作 url 地址的
const url = require('url')
- url.parse('地址', 是否深度解析);
- 地址: 必填
- 是否深度解析
- 默认是 false, 不深度解析, 可以手动配置为 true
- 深度解析其实就是把 对象中的 query 解析为 对象格式
1、false
const res = url.parse('http://localhost:8888/cart.html?goodsId=10086&userId=10010')
console.log(res)
/*
Url {
protocol: 'http:',
slashes: true,
auth: null,
host: 'localhost:8888',
port: '8888',
hostname: 'localhost',
hash: null,
search: '?goodsId=10086&userId=10010',
query: 'goodsId=10086&userId=10010',
pathname: '/cart.html',
path: '/cart.html?goodsId=10086&userId=10010',
href: 'http://localhost:8888/cart.html?goodsId=10086&userId=10010'
}
*/
2、true
const res = url.parse(
"http://www.baidu.com:8080/a/b/c/index.html?key=value&name=QF001&age=18#abc",
true
);
console.log(res);
/*
Url {
// 协议
protocol: 'http:',
slashes: true,
auth: null,
// 域(域名+端口号)
host: 'www.baidu.com:8080',
// 端口号
port: '8080',
// 域名
hostname: 'www.baidu.com',
// hash值
hash: '#abc',
// 携带的参数
search: '?key=value&name=QF001&age=18',
// 查询字符串
query: 'key=value&name=QF001&age=18',
// 路径名称
pathname: '/a/b/c/index.html',
// 路径(路径名称 + 参数)
path: '/a/b/c/index.html?key=value&name=QF001&age=18',
// 完整地址
href: 'http://www.baidu.com:8080/a/b/c/index.html?key=value&name=QF001&age=18#abc'
}
深度解析后的
Url {
...
query: [Object: null prototype] { key: 'value', name: 'QF001', age: '18' },
...
}
八、内置模块 http
node 自带的一个模块, 用于开启一个 http 服务
- 服务器
- 提供 服务 的 机器
- 服务: 提供一些内容(文件/数据)
- 机器: 电脑
- 有一台电脑, 运行了 一个 '软件'
- 这个 "软件" 可以向外开放一个 "文件夹"(根目录)
- 当其他电脑访问到这台电脑的时候, 并且制定了访问这个 "软件" 的时候
- 那么相当于在访问这个文件夹
- 例子:
- 一台电脑: 10.11.12.13
- 软件: 8080
- 开放的文件夹是: D:/a/b
- 当你打开浏览器访问 http:10.11.12.13:8080 的时候, 就是在访问这台电脑上的 D:/a/b
- node 就可以利用 http 模块来充当 "软件" 启动服务
- 提供 服务 的 机器
初始搭建步骤
0、引入内置模块
const http = require("http");
1、创建服务
- 语法: http.createServer(函数)
- 函数: 每当前端有一个请求访问这个服务器的时候, 就会执行一次
- 返回值: 一个服务
const server = http.createServer(() => {
console.log("前端发一次请求, 我就执行一次");
});
2、给当前服务配置一个端口号
- 语法: server.listen(端口号(0~65535), 回调函数)
server.listen(8080, () => {
console.log("启动服务成功~~~");
});
3、创建函数时 函数接收的两个参数
- 第一个 形参: request, 对应的值为前端请求时携带的请求报文
- 第二个 形参: response, 表示本次响应的相关信息, 你只要添加到 res 内, 会由服务器自动组装响应报文返回给前端
- res.end 是一个函数, 这个函数调用的时候 能够关闭当前请求。这个函数可以传递一个参数, 这个参数会传递给请求者
const server = http.createServer((req, res) => {
fs.readFile('./client/views/index.html', 'utf-8', (err, data) => {
if (err) return console.log(err)
res.end(data)
})
})
// 2. 给服务器配置一个端口号
server.listen(8080, () => console.log('服务器启动成功~'))
补充---请求
- 什么算请求?
- 在浏览器地址栏输入一个 地址, 然后按下回车
- 以浏览器为主体在发送请求
- 服务器返回的内容直接给到浏览器, 显示在页面上
- 在浏览器内 以 link script iframe img 等标签请求的内容
- 例如:
<link href="./css/a.css"></link> - 例如:
<script src="./js/a.js"></script>
- 例如:
- 当前页面中的 js 代码内的 ajax 请求
- 在浏览器地址栏输入一个 地址, 然后按下回车
- 请求的完整地址是什么
- 在一个 html 文件内所有的书写地址的位置都可以写 绝对地址 和 相对地址
- 绝对地址: 写什么就是什么
- 相对地址: 你打开的文件地址是什么, 那么相对地址就按照打开文件的地址进行拼接
- 例子: 打开页面是 http://localhost:8080/a/b/c/index.html
- 如果你的地址写的是 ./a/a.css 完整地址: http://localhost:8080/a/b/c/a/a.css
- 你的地址写的是 ../a.css 完整地址: http://localhost:8080/a/b/a.css
- 你的地址写的是 ../d/a.css 完整地址: http://localhost:8080/a/b/d/a.css
- 你的地址写的是 /a.css 完整地址: http://localhost:8080/a.css
- 在一个 html 文件内所有的书写地址的位置都可以写 绝对地址 和 相对地址