目录
一、前言
js为什么可以在浏览器中执行?
浏览器通过js解析引擎执行js代码,不同的浏览器使用不同的js引擎。
- chrome => v8
- fireFox => OdinMonkey
- safri => jscore
- ie => Chakra(查克拉)
- …
其中v8引擎性能最好
js为什么可以操作dom和bom?
每个浏览器都内置了dom、bom API,js调用这些api即可操作dom和bom
Node.js简介
nodejs是基于v8引擎的js运行环境,他和浏览器类似,都是js的运行环境,只不过有如下区别:
- 浏览器是js的前端运行环境
- nodejs是js的后端运行环境
- nodejs中无法调用浏览器内置api,如dom,bom。它有其自己的内置api,如fs,http,path
Node.js可以做什么?
node.js作为一个js的运行环境,仅仅提供了基础的功能和api。然而,基于node.js提供的这些基础功能,出现了很多强大的工具和框架:
- express框架,可以快熟构建web应用
- electron框架,可以构建跨平台的桌面应用
Node.js怎么学?
浏览器中的js学习路径:
js基础语法 + 浏览器内置api(dom,bom)+第三方框架(jq,vue,react)
Node.js的学习路径:
ji基础语法 + node.js内置api(fs,path,http) + 第三方模块(express,koa2,mysql)
常用终端快捷键
- tab: 补全路径
- esc: 清空当前输入
- 输入cls: 清空终端
二、内置API
fs文件系统模块
在js中使用的时候,需要先引入
const fs = require('fs')
-
fs.readFile()
读取指定文件中的内容
fs.readFile(path, format, cb) path: 必选参数,文件路径 format:可选,以什么编码格式来读取文件,比如'utf8' cb:必选,文件读取完毕后的回调,回调的第一个参数是error,第二个参数是文件读取结果。若读取成功,error为null
-
fs.writeFile()
向指定的文件中写入内容,会直接覆盖掉文件里内容
fs.readFile(path, data, format, cb) format: 默认utf8 data: 必选,要写入的内容 cb: 回调,参数error,若写入成功,error为null
-
相对路径会出现的问题
在使用fs操作文件时,如果路径采用的是相对路径,容易出现问题,原因是:node执行js代码的时候,会根据执行node命令时所处的目录,动态拼接出被操作文件的完整路径。
解决方法:
采用绝对路径
__dirname: 代表当前文件所处的目录
path路径模块
使用的时候,同样需要先引入:
const path = require('path')
-
path.join()
将多个路径片段拼接成完整的路径字符串,经常配合__dirname使用。注意’…/'会抵消前面的路径
console.log(path.join('/a', '/b/c', '../', '/d'))//\a\b\d
//当前目录:D:\test path.join(__dirname, 'a')//D:\test\a path.join(__dirname, '/a')//D:\test\a path.join(__dirname, './a')//D:\test\a path.join(__dirname, '../a')//D:\a
-
path.basename()
获取路径中的最后一部分,可以用来获取文件名
path.basename(path, ext) //参数path: 必选,路径 //参数ext:可选,文件扩展名 //返回值: 路径中的最后一部分
path.basename('a/b/index.html')//index.html path.basename('a/b/index.html', '.html')//index path.basename('a/b/index.html/')//index.html path.basename('a/b/index')//index
-
path.extname()
获取文件扩展名
path.extname(path)
path.extname('a/index.html')//.html
http模块
用来创建web服务器。服务器与普通电脑的区别在于,服务器上安装了web服务器软件,例如: IIS,Apache等。
在nodejs中,我们不需要安装第三方服务器软件,通过http模块,几行简单的代码就能实现一个服务器。
同样需要先导入:
const http = require('http')
-
服务器相关概念
-
域名和域名服务器
ip地址和域名是一一对应关系,这份关系映射存放在域名服务器上(DNS)。域名服务器就是提供ip地址和域名之间转换服务的服务器。
-
-
创建最基本的web服务器
-
导入http模块
const http = require('http')
-
创建web服务器实例
const server = http.createServer()
-
为服务器绑定request事件,监听客户端请求
server.on('request', (req, res) => { })
-
req请求对象
它包含了与客户端相关的数据和属性,例如:
-
req.url是客户端请求的url地址
-
req.method是请求类型
-
-
res响应对象
它包含了与服务器相关的数据和属性,例如:
- res.end(str),像客户端发送指定的内容,并结束此次请求处理过程
-
解决中文乱码问题
当调用res.end()方法,向客户端发送中文内容时,会出现乱码问题,此时需要手动设置编码格式:
- res.setHeader(‘Content-type’, ‘text/html; charset=utf-8’)
-
-
启动服务器
server.listen(80, () =>{ })
-
-
根据不同的url做出不同的响应
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>' } res.setHeader('Content-type', 'text/html; charset=utf-8') res.end(content) })
三、模块化
什么是模块化?
模块化就是遵守特定的规则,将一个大的系统或者说是文件,拆分成多个独立并且相互依赖的小模块。
模块化的好处是:
- 提高了代码的复用性
- 提高了代码的可维护性
- 可以实现按需加载
模块化规范
模块化规范就是对代码进行模块化的拆分与组合时,需要遵守的特定规则。例如:
- 使用什么样的语法格式来引用模块
- 使用什么样的始发格式向外暴露成员
nodejs中的模块化规范
nodejs遵循了CommonJS规范。CommonJS规定:
- 每个模块内布,module代表当前变量
- module是一个对象,它的exports属性是对外的接口
- 加载某个模块其实是加载该模块的module对象的exports属性
nodejs中的三大类模块
nodejs中根据模块来源的不同,分为三大类:
- 内置模块:fs文件系统模块,path路径模块,http模块等
- 自定义模块:用户创建的每个js文件,都是自定义模块
- 第三方模块:使用前需要先下载
加载模块
上面说的三类模块,都采用require()方法进行加载。需要注意的是,使用require加载模块时,会执行被加载模块中的代码。另外,可以省略.js后缀名
模块作用域
和函数作用域类似,在模块中定义的变量、方法等成员,只能在模块内部访问,这种模块级别的限制,叫做模块作用域。
module对象
每个nodejs模块中都有一个module对象,它里面存储了当前模块的相关信息,打印如下:
可以使用module.exports对象,将模块内的成员暴露出去,供外界使用。
外界用require()方法导入时,得到的其实就是module.exports所指向的对象。
exports对象
由于module.exports拼写起来比较复杂,Node提供了exports对象。默认情况下,exports和module.exports指向的是同一个对象。
exports和module.exports使用误区
-
时刻谨记,require()模块时,得到的永远是module.exports所指向的对象
exports.name = 'paul'//导出,require能得到 exports = { name: 'paul' }//导出,require得到的是一个空对象
出现上面的情况是因为:默认情况下,exports和module.exports指向的是同一个对象,如果对exports对象修改,那么module.exports对象也会同样修改。但是如果给exports赋值了一个新对象,exports和module.exports指向就不一样了,而require得到的永远是module.exports,所以是空对象
-
为了防止混乱,尽量不要在同一个模块中同时使用exports和module.exports
四、npm与包
nodejs中的第三方模块又叫包,由于nodejs内置模块仅提供了一些底层API,这样开发项目时,效率会很低。包是基于内置模块封装出来的,提供了更高级、更便利的API,极大提升了开发效率。
npm安装指定版本的包
默认情况下npm会安装最新版本,在包名后面加上@符号安装指定版本:
npm i moment@2.24.0
包的语义化版本规范
包的版本号是以“点分十进制”形式进行定义的,总过有三位数字,例如:2.24.0。其中每一位数字代表的具体含义如下:
- 第一位数字:大版本
- 第二位数字:功能版本
- 第三位数字:Bug修复版本
package.json
记录了项目中安装了哪些包,从而团队成员共享项目源代码时,可以剔除掉巨大的node_modules目录。
-
如何生成package.json文件
npm init -y
解决包下载速度慢的问题
-
淘宝npm镜像服务器
淘宝在国内搭建了一个服务器,专门把国外官方服务器上的包同步到国内的服务器,然后再国内提供下包的服务,从而极大地提升了下包的速度。
-
切换npm的下包镜像源
# 查看当前镜像源 npm config get registry # 切换为淘宝镜像源 npm config set registry=https://registry.npm.taobao.org/
-
nrm
为了更方便的查看和切换镜像源,可以安装nrm工具。
# 安装nrm npm i nrm -g # 查看所有可用的镜像源 nrm ls # 设置为淘宝镜像源 nrm use taobao
模块的加载机制
-
优先从缓存中加载
模块在第一次加载后会被缓存,这意味着多次调用require(),模块代码只会执行一次。
-
自定义模块的加载机制
必须指定以./或…/开头的路径标识符,否则node会将其当做内置模块或者第三方模块进行加载。另外,如果省略了文件的扩展名,nodejs会按以下顺序进行尝试:
- 按照确切的文件名进行加载
- 补全.js
- 补全.json
- 补全.node
- 加载失败,报错
-
加载第三方模块
如果require加载的不是内置模块,也没有以./或…/开头,则nodejs会从当前模块的父目录下的node_modules文件夹中加载第三方模块,如果没有找到,则在更上一层目录重找,直到根目录。
-
目录作为模块进行加载
当把目录进行模块进行加载时,会按照如下顺序执行:
- 在目录下查找package.json文件,main属性作为require加载的入口
- 如果没有package.json,或者main入口不存在,则nodejs会加载目录下的index.js文件
- 如果以上两步都失败了,则会报错:
Error: Cannot find module 'xxx'