【学习笔记】黑马程序员Node.js全套入门教程 | 基础篇
⛄最近要写一些npm命令发现文件读写和路径API忘记了,索性直接复习了一遍NodeJS,边学边忘真的痛苦。⛄本文包含以下内容:对NodeJS的基础介绍,NodeJS的内置包的简单介绍,CommonJS模块化介绍,npm包下载与发布介绍。
⭐注:本文是对黑马程序员Node.js全套入门教程的学习笔记记录,加入了一些自己的练习改动与思考。
⭐推荐大家去看原视频:黑马程序员Node.js全套入门教程
初识NodeJs
思考与认识
JS为什么可以在浏览器中被执行
====浏览器====
待执行的JS代码
↓
JavaScript解析引擎
====浏览器====
浏览器中含有JavaScript解析引擎负责解析JS代码
不同的浏览器使用不同的JavaScript解析引擎:
- Chrome => V8
- Firefox => OdinMonkey(奥丁猴)
- Safri => JSCore
- IE浏览器 => Chakra(查克拉)
- 等...
Chrome浏览器的V8解析引擎性能最好
为什么JavaScript可以操作DOM和BOM
====浏览器====
DOMAPI BOMAPI AjaxAPI
↓
待执行的JS代码(调用WebAPI)
↓
JavaScript解析引擎
每个浏览器都内置了DOM、BOM这样的API函数,因此,浏览器中的JavaScript才可以调用它们。
浏览器中的JavaScript运行环境
- 运行环境是指代码正常运行所需的必要环境。
====Chrome浏览器运行环境====
V8引擎 内置API
↑ ↓
待执行的JavaScript代码
====Chrome浏览器运行环境====
- V8引擎负责解析和执行JavaScript 代码。
- 内置API是由运行环境提供的特殊接口,只能在所属的运行环境中被调用。
JavaScript能否做后端开发
- JS可以在浏览器中运行,我们需要通过Node.js让JS代码在服务端运行
Node.js 简介
什么是Node.js
- Node.js 是一个基于Chrome V8引擎的JavaScript运行环境。
- 官网地址:Node.js (nodejs.org)
Node.js中的JavaScript运行环境
====Node.js运行环境====
V8引擎 内置API(fs path http JS内置对象等)
↑ ↓
待执行的JavaScript代码
====Chrome浏览器运行环境====
- 浏览器是JavaScript 的前端运行环境。
- Node.js 是JavaScript的后端运行环境。
- Node.js 中无法调用DOM和BOM等浏览器内置API。
Node.js 可以做什么
Node,js作为一个JavaScript 的运行环境,仅仅提供了基础的功能和API。然而,基于Node.,js提供的这些基础能,很多强大的工具和框架如雨后春笋,层出不穷,所以学会了Node.js,可以让前端程序员胜任更多的工作和岗位。
- 基于 Express 框架 (opens new window),可以快速构建 Web 应用
- 基于 Electron 框架 (opens new window),可以构建跨平台的桌面应用
- 基于 restify 框架 (opens new window),可以快速构建 API 接口项目
- 读写和操作数据库、创建实用的命令行工具辅助前端开发
- 等...
安装Node.js
如果希望通过Node.,js 来运行Javascript 代码,则必须在计算机上安装Node.js环境才行。
- 前往官网下载安装:节点.js (nodejs.org)
区分LTS版本和Current版本的不同
- LTS为长期稳定版,对于追求稳定性的企业级项目来说,推荐安装LTS版本的Node.js。
- Current 为新特性尝鲜版,对热衷于尝试新特性的用户来说,推荐安装Current 版本的Node.js。但是,Current 版本中可能存在隐藏的Bug 或安全性漏洞,因此不推荐在企业级项目中使用Current版本的 Node.js
查看已安装的Node.js版本号
- 打开终端输入
node -v
,即可查看node.js版本号
- 打开终端输入
什么是终端
- 终端(英文: Terminal)是专门为开发人员设计的,用于实现人机交互的一种方式。
- 使用
node <js文件名>
运行js文件
常用模块
fs文件系统模块
- fs 模块是Node.js 官方提供的、用来操作文件的模块。它提供了一系列的方法和属性,用来满足用户对文件的操作需求。
导入模块
// Nodejs内置模块 无需额外安装
const fs = require('fs')
读取文件内容
- 使用fs.readFile()方法,可以读取指定文件中的内容
fs.readFile(path[, options], callback)
参数解释:
- path:必选参数,字符串,表示文件的路径。
- options:可选参数,表示以什么编码格式来读取文件。
callback:必选参数,文件读取完成后,通过回调函数拿到读取的结果,该函数会传入两个参数。
- err:文件读取错误时发生的报错
- dataStr:文件内容
示例代码
const fs = require('fs')
fs.readFile('./test.text', 'utf8', function (err, dataStr) {
// 如果读取成功,则err为null
// 如果读取失败,err的值为错误对象
if(err) {
console.log(err)
}
console.log('+++++++++')
// 打印成功的结果
console.log(dataStr)
})
写入文件内容
- 使用fs.writeFile0方法,可以向指定的文件中写入内容,语法格式如下
- 该方法只能创建文件,不能创建目录
fs.writeFile(file, data[, options], callback)
参数解释:
- file:必选参数,需要指定一个文件路径的字符串,表示文件的存放路径。
- data:必选参数,表示要写入的内容。
- options:可选参数,表示以什么格式写入文件内容,默认值是utf8。
callback:必选参数,文件写入完成后的回调函数,该函数会传入一个参数。
- err:文件写入错误时发生的报错
示例代码
const fs = require('fs')
fs.writeFile('./write.text', 'Hello FS Module!', 'utf8', function (err) {
// 如果写入成功,则err为null
// 如果写入失败,err的值为错误对象
if (err) {
console.log(err)
}
})
处理路径问题
- 在使用fs 模块操作文件时,如果提供的操作路径是以./或../开头的相对路径时,很容易出现路径动态拼接错误的问题。
- 原因:代码在运行的时候,会队执行node命令时所处的目录,动态拼接出被操作文件的完整路径。(相对于用户所在目录,而不是相对于文件目录)
__dirname
- __dirname表示当前文件所处的目录,更改后可解决路径问题
const fs = require('fs')
fs.readFile(__dirname + '/test.text', 'utf8', function (err, dataStr) {
// ...
})
fs.writeFile(__dirname + '/write.text', 'Hello FS Module!', 'utf8', function (err) {
// ...
})
path路径模块
- path模块是Node.js官方提供的、用来处理路径的模块。它提供了一系列的方法和属性,用来满足用户对路径的处理需求。
导入模块
// Nodejs内置模块 无需额外安装
const fs = require('fs')
路径拼接
- 使用path.join(方法,可以把多个路径片段拼接为完整的路径字符串,语法格式如下
path.join([...path])
参数解释:
- 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.text')
console.log(pathStr2) // 将相对路径转化为绝对路径
与 __dirname 使用字符串加法的不同
- 如果使用字符串加法
__dirname + './a'
会在路径中多出一个点(.)使用path.join可以解决此问题
- 如果使用字符串加法
获取路径中的文件名
- 使用path.basename()方法,可以获取路径中的最后一部分,经常通过这个方法获取路径中的文件名,语法格式如下
path.basename(path[, ext])
参数解释:
- path:必选参数,表示一个路径的字符串
- ext:可选参数,表示文件扩展名
使用示例
const path = require('path')
const fpath = '/a/b/c/index.html'
let fullName = path.basename(fpath)
console.log(fullName) // index.html
let nameWithoutExt = path.basename(fpath, '.html')
console.log(nameWithoutExt) // index
获取路径中的文件扩展名
- 使用path.extname)方法,可以获取路径中的扩展名部分
path.extname(path)
参数解释:
- path:必选参数,表示一个路径的字符串
使用示例
const path = require('path')
const fpath = '/a/b/c/index.html'
let fext = path.extname(fpath)
console.log(fext) // .html
http模块
- http模块是Node.js 官方提供的、用来创建 web服务器的模块。通过 http模块提供的 http.createServer()方法,就能方便的把一台普通的电脑,变成一台Web服务器,从而对外提供Web资源服务。
- 服务器和普通电脑的区别在于,服务器上安装了web服务器软件,例如:IIS、Apache等。通过安装这些服务器软件,就能把一台普通的电脑变成一台web服务器。
- 在Node.js 中,我们不需要使用IIS、Apache等这些第三方web服务器软件。因为我们可以基于Node,js提供的http模块,通过几行简单的代码,就能轻松的手写一个服务器软件,从而对外提供web服务。
基本四步
- 导入http模块
- 创建web服务器实例
- 为服务器实例绑定request事件,监听客户端请求
- 启动服务器
导入模块
const http = require('http')
创建web服务器实例
const server = http.createServer()
为服务器绑定request事件
server.on('request', (req, res) => {
console.log('Someone visit our web server.')
const url = req.url // 请求地址
const method = req.method // 请求url
// 根据路径判断返回不同内容
let content = '<h1>404 Not found!</h1>'
if(url === '/' || url === '/index.html') {
content = '<h1>首页</h1>'
}
res.setHeader('Content-Type', 'text/html; charset=utf-8') // 设置响应头
res.end(content) // 向客户端响应内容
})
启动服务器
server.listen(80, () => {
console.log('http server running at http://127.0.0.1')
})
模块化
模块分类
Node.js 中根据模块来源的不同,将模块分为了3大类,分别是
- 内置模块(内置模块是由Node.js官方提供的,例如fs、path、http等)
- 自定义模块(用户创建的每个.js文件,都是自定义模块)
- 第三方模块(由第三方开发出来的模块,并非官方提供的内置模块,也不是用户创建的自定义模块,使用前
需要先下载)
加载模块
// 加载内置fs模块
const fs = require('fs')
// 加载用户自定义模块
const custom - require('./custom.js')
// 加载第三方模块
const moment - require('moment')
- 注意:使用require方法加载其它模块时,会执行被加载模块中的代码。
模块作用域
- 和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问,这种模块级别的访问限制,叫做模块作用域。
- 该作用域防止了全局变量污染的问题
module对象
在每个.js自定义模块中都有一个module对象,它里面存储了和当前模块有关的信息
- id,path,exports,parent,filename等...
module.exports
- 在自定义模块中,可以使用module.exports对象,将模块内的成员共享出去,供外界使用。
- 外界用require()方法导入自定义模块时,得到的就是 module.exports所指向的对象。
代码示例
// moduleA.js
// 导出变量
module.exports.username = 'zs'
module.exports.sayHello = function() {
console.log('Hello!')
}
// main.js
// 导入并使用变量
const moduleA = require('./moduleA.js')
moduleA.sayHello()
exports对象
- 由于module.exports单词写起来比较复杂,为了简化向外共享成员的代码,Node提供了exports对象。默认情况下,exports和module.exports 指向同一个对象。最终共享的结果,还是以module.exports指向的对象为准。
- 时刻谨记,require)模块时,得到的永远是 module.exports指向的对象
console.log(module.exports) // {}
console.log(exports) // {}
console.log(module.exports === exports) // true
CommonJS规范
Node.js遵循了CommonJS模块化规范,CommonJS规定了模块的特性和各模块之间如何相互依赖。
CommonJS规定:
- 每个模块内部,module变量代表当前模块。
- module变量是一个对象,它的exports属性(即module.exports)是对外的接口。
- 加载某个模块,其实是加载该模块的 module.exports属性。require)方法用于加载模块。
模块加载机制
模块第一次加载后会被缓存,即多次调用 require()
不会导致模块的代码被执行多次,提高模块加载效率。
内置模块加载
内置模块加载优先级最高。
自定义模块加载
加载自定义模块时,路径要以 ./
或 ../
开头,否则会作为内置模块或第三方模块加载。
导入自定义模块时,若省略文件扩展名,则 Node.js 会按顺序尝试加载文件:
- 按确切的文件名加载
- 补全
.js
扩展名加载 - 补全
.json
扩展名加载 - 补全
.node
扩展名加载 - 报错
第三方模块加载
- 若导入第三方模块, Node.js 会从当前模块的父目录开始,尝试从
/node_modules
文件夹中加载第三方模块。 - 如果没有找到对应的第三方模块,则移动到再上一层父目录中,进行加载,直到文件系统的根目录。
例如,假设在 C:\Users\bruce\project\foo.js
文件里调用了 require('tools')
,则 Node.js 会按以下顺序查找:
C:\Users\bruce\project\node_modules\tools
C:\Users\bruce\node_modules\tools
C:\Users\node_modules\tools
C:\node_modules\tools
目录作为模块加载
当把目录作为模块标识符进行加载的时候,有三种加载方式:
- 在被加载的目录下查找
package.json
的文件,并寻找main
属性,作为require()
加载的入口 - 如果没有
package.json
文件,或者main
入口不存在或无法解析,则 Node.js 将会试图加载目录下的index.js
文件。 - 若失败则报错
npm与包
包
概念
- Node.js 中的第三方模块又叫做包。
- 就像电脑和计算机指的是相同的东西,第三方模块和包指的是同一个概念,只不过叫法不同。
来源
- 不同于Node.js 中的内置模块与自定义模块,包是由第三方个人或团队开发出来的,免费供所有人使用。
- Node.js 中的包都是免费且开源的,不需要付费即可免费下载使用。
为什么需要包
- 由于Node.js 的内置模块仅提供了一些底层的API,导致在基于内置模块进行项目开发的时,效率很低。
- 包是基于内置模块封装出来的,提供了更高级、更方便的API,极大的提高了开发效率。
- 包和内置模块之间的关系,类似于jQuery和浏览器内置API之间的关系。
从哪里下载包
- 国外有一家IT公司,叫做npm, Inc.这家公司旗下有一个非常著名的网站: https://www.npmjs.com/ ,它是全球最大的包共享平台,你可以从这个网站上搜索到任何你需要的包,只要你有足够的耐心!
- npm, Inc.公司提供了一个服务器,来对外共享所有的包,我们可以从这个服务器上下载自己所需要的包。
如何下载包
- npm, Inc.公司提供了一个包管理工具,我们可以使用这个包管理工具,从服务器把需要的包下载到本地使用。
这个包管理工具的名字叫做Node Package Manager (简称npm包管理工具),这个包管理工具随着Node.js的安装包一起被安装到了用户的电脑上。
- npm, Inc.公司提供了一个包管理工具,我们可以使用这个包管理工具,从服务器把需要的包下载到本地使用。
npm
- npm是Nodejs官方的包管理工具。
- 初次装包完成后,在项目文件夹下多一个叫做node_ modules的文件夹和package-lockjson的配置文件。
- node_modules 文件夹用来存放所有已安装到项目中的包。require()导入第三方包时,就是从这个目录中查找并加载包。
- package-lockjson 配置文件用来记录node modules目录下的每一个包的下载信息,例如包的名字、版本号、下载地址等。
# 初始化npm配置文件
# -y表示使用配置默认选项
# 执行后出现 package.json 文件
npm init -y
# 下载包
npm install <包名称>
# 删除包
npm uninstall <包名称>
# 切换镜像源加速下载
npm config set registry=https://registry.npm.taobao.org/
# 在执行npm install命令时,如果提供了-g参数,则会把包安装为全局包。
# 全局包会被安装到C:\Users\用户目录VAppData\RoamingInpm\node_modules目录下。
npm install <包名称> -g
- 上述命令只能在英文的目录下成功运行!所以,项目文件夹的名称一定要使用英文命名,不要使用中文,不能出现空格。
- 运行npm install命令安装包的时候,npm包管理工具会自动把包的名称和版本号,记录到package.json 中。
// packge.json
{
"name": "nodeNpm",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
发布包
- 新建itheima-tools文件夹,作为包的根目录
在itheima-tools文件夹中,新建如下三个文件:
- package.json(包管理配置文件)
- index.js(包的入口文件)
- README.md(包的说明文档)
// packge.json
{
"name": "myTool", // 包名称
"version": "1.0.0", // 包版本
"description": "", // 包的描述
"main": "index.js", // 包的入口文件
"scripts": { // 包的可执行指令
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [], // 搜索关键字,使用那些关键字可以搜索到该作者
"author": "", // 包的作者
"license": "ISC" // 包遵循的开源协议
}
// main.js
module.export = {
add(a, b){
return a+b
}
}
- 包根目录中的README.md文件,是包的使用说明文档。通过它,我们可以事先把包的使用说明,以 markdown的格式写出来,方便用户参考。
- README文件中具体写什么内容,没有强制性的要求;只要能够清晰地把包的作用、用法、注意事项等描述清楚即可。我们所创建的
这个包的 README.md文档中,会包含以下6项内容:
- 安装方式、导入方式、格式化时间、转义HTML中的特殊字符、还原HTML中的特殊字符、开源协议
npm发布
注册npm账号
- 访问https://www.npmjs.com/ 网站,点击 sign up按钮,进入注册用户界面
- 填写账号相关的信息:Full Name、Public Email、Username、Password
- 点击Create an Account按钮,注册账号
- 登录邮箱,点击验证链接,进行账号的验证
登录npm账号
- npm账号注册完成后,可以在终端中执行npm login命令,依次输入用户名、密码、邮箱后,即可登录成功。
- 注意:在运行npm login命令之前,必须先把下包的服务器地址切换为npm的官方服务器。否则会导致发布包失败!
# 输入账号密码后即可成功登录
npm login
发布
# 将包发布在npm上
npm publish
# 删除发布的包
npm unpublish <包名> --force
- npm unpublish命令只能删除72小时以内发布的包。
- npm unpublish 删除的包,在24小时内不允许重复发布发布包的时候要慎重。
- 尽量不要往npm上发布没有意义的包!
⛄以上便是基础篇的全部内容了,学习后能让你对NodeJS有一个大致的了解。