2024年node(16),大厂面经合集

下面是我在学习HTML和CSS的时候整理的一些笔记,有兴趣的可以看下:

HTML、CSS部分截图

进阶阶段

进阶阶段,开始攻 JS,对于刚接触 JS 的初学者,确实比学习 HTML 和 CSS 有难度,但是只要肯下功夫,这部分对于你来说,也不是什么大问题。

JS 内容涉及到的知识点较多,看到网上有很多人建议你从头到尾抱着那本《JavaScript高级程序设计》学,我是不建议的,毕竟刚接触 JS 谁能看得下去,当时我也不能,也没那样做。

我这部分的学习技巧是,增加次数,减少单次看的内容。就是说,第一遍学习 JS 走马观花的看,看个大概,去找视频以及网站学习,不建议直接看书。因为看书看不下去的时候很打击你学下去的信心。

然后通过一些网站的小例子,开始动手敲代码,一定要去实践、实践、实践,这一遍是为了更好的去熟悉 JS 的语法。别只顾着来回的看知识点,眼高手低可不是个好习惯,我在这吃过亏,你懂的。

1、JavaScript 和 ES6

在这个过程你会发现,有很多 JS 知识点你并不能更好的理解为什么这么设计,以及这样设计的好处是什么,这就逼着让你去学习这单个知识点的来龙去脉,去哪学?第一,书籍,我知道你不喜欢看,我最近通过刷大厂面试题整理了一份前端核心知识笔记,比较书籍更精简,一句废话都没有,这份笔记也让我通过跳槽从8k涨成20k。

JavaScript部分截图

2、前端框架

前端框架太多了,真的学不动了,别慌,其实对于前端的三大马车,Angular、React、Vue 只要把其中一种框架学明白,底层原理实现,其他两个学起来不会很吃力,这也取决于你以后就职的公司要求你会哪一个框架了,当然,会的越多越好,但是往往每个人的时间是有限的,对于自学的学生,或者即将面试找工作的人,当然要选择一门框架深挖原理。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

以 Vue 为例,我整理了如下的面试题。

Vue部分截图

})
Events.trigger(‘loginsuccess’)
Events.trigger(‘loginsuccess’)


## File System


* 得到文件与目录的信息:stat
* 创建一个目录:mkdir
* 创建文件并写入内容:writeFile,appendFile
* 读取文件的内容:readFile
* 列出目录的东西:readdir
* 重命名目录或文件:rename
* 删除目录与文件:rmdir,unlink



const fs = require(‘fs’);

//创建一个文件,添加内容,异步方式,回调函数:错误优先的原则
fs.writeFile(‘./log.txt’, ‘hello world’, function (err) {
})
//同步创建文件,不用写回调函数
fs.writeFileSync(‘./log1.txt’, ‘hello’)

//异步删除文件
fs.unlink(‘./log1.txt’, function () {
})
//同步删除文件
fs.unlinkSync()

//修改文件的名字
fs.renameSync(‘log.txt’, ‘lognew.txt’)
console.log(‘hello world’)

//追加内容
fs.appendFileSync(‘lognew.txt’, ‘gp18’)

//文件内容的读取
let rs = fs.readFileSync(‘lognew.txt’)
console.log(rs.toString());

//文件夹

//创建文件夹
if (!fs.existsSync(‘./log’)) {//如果不存在文件夹,就创建一个
fs.mkdirSync(‘./log’)
}
fs.writeFileSync(‘./log/1.txt’, ‘hello world !’);

//如果文件内,存在内容,不能直接删除
fs.rmdirSync(‘./log’)

//删除文件夹使用递归

//删除文件夹
function delfile(src) {
//读取文件的状态信息
var rs = fs.statSync(src);
if (rs.isDirectory()) {
//读取文件夹下的数据
var files = fs.readdirSync(src)
files.forEach((item, index) => {
let curPath = src + ‘/’ + item;
//if (fs.statSync(curPath).isDirectory()) {
delfile(curPath);
//} else {
// fs.unlinkSync(curPath);
//}
})
fs.rmdirSync(src);
} else {
fs.unlinkSync(src)
}

}

delfile(‘./log’)


json的基本操作



const fs = require(‘fs’);

var data = require(‘./data.json’)

let user = {
name: ‘wanghao’,
age: 20
}

//创建并添加内容
// fs.writeFileSync(‘data.json’, JSON.stringify(user));
console.log(data);
//修改json文件的内容
data.address = ‘beijing’;
fs.writeFileSync(‘data.json’, JSON.stringify(data));


### Stream


读取文件流  
 可读流的事件  
 可写的文件流  
 pipe链式使用  
 pipe



const fs = require(‘fs’);
const zlib = require(‘zlib’);

fs.writeFileSync(‘log.txt’, ‘gp18’);

fs.createReadStream(‘log.txt’)
.pipe(zlib.createGzip())//这时候压缩文件还在内存中
.pipe(fs.createWriteStream(‘log.txt.gzip’));//输出到物理目录


## crypto数据加密


crypto模块的目的是为了提供通用的加密和哈希算法。用纯JavaScript代码实现这些功能不是不可能,但速度会非常慢。Nodejs用C/C++实现这些算法后,通过cypto这个模块暴露为JavaScript接口,这样用起来方便,运行速度也快。


### MD5和SHA1


MD5是一种常用的哈希算法,用于给任意数据一个“签名”。这个签名通常用一个十六进制的字符串表示.



const crypto = require(‘crypto’);

const hash = crypto.createHash(‘md5’);

hash.update(‘hello world’);

console.log(hash.digest(‘hex’));


### Hmac


Hmac算法也是一种哈希算法,它可以利用MD5或SHA1等哈希算法。不同的是,Hmac还需要一个密钥;


只要密钥发生了变化,那么同样的输入数据也会得到不同的签名,因此,可以把Hmac理解为用随机数“增强”的哈希算法。



const crypto = require(‘crypto’);

const hash = crypto.createHmac(‘sha256’, ‘secret-key’);

hash.update(‘hello world’);

console.log(hash.digest(‘hex’));


### AES


对称加密算法,加密和解密都用相同的秘钥



const crypto = require(‘crypto’);
//数据加密
function aesEncrypt(data, key) {

//用指定的算法和秘钥,返回一个cipher对象
const cipher = crypto.createCipher(‘aes192’, key)
var crypted = cipher.update(data, ‘utf8’, ‘hex’)
crypted += cipher.final(‘hex’);
return crypted;
}

//数据解密
function aesDecrypt(encrypted, key) {
const decipher = crypto.createDecipher(‘aes192’, key)
var decrypted = decipher.update(encrypted, ‘hex’, ‘utf8’);
decrypted += decipher.final(‘utf8’)
return decrypted;
}

var data = ’ hello gp18’;
var key = ‘password’;
//d:加密数据
var encrypted = aesEncrypt(data, key)
console.log(‘encrypted:’, encrypted)
//d:解密数据
var decrypted = aesDecrypt(encrypted, key)
console.log(‘decrypted:’, decrypted)


## 路由


### 入门


通过启动一个服务访问index.html页面,并且加载图片和css资源  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200719122206186.png)



const http = require(‘http’);
const fs = require(‘fs’)
const data = require(‘./user.json’)

http.createServer((req, res) => {

var url = req.url;
//d:设置默认路径加载 index.html
if (url === ‘/’) {
url = ‘/index.html’
}

if (url.indexOf(‘favicon.ico’) > -1) {
res.end(‘’)
}
//d:获取该服务下的完整路径
var fullpath = __dirname + url;

console.log(url);
//d:通过url判断文件类型
switch (url) {
case “/index.html”:
res.setHeader(‘Content-Type’, ‘text/html’);
break;
case “/logo.png”:
res.setHeader(‘Content-Type’, ‘image/png’);
break;
case “/index.js”:
res.setHeader(‘Content-Type’, ‘application/x-javascript’);
break;
case “/api/getlist”:
res.setHeader(‘Content-Type’, ‘application/json;chartset=utf-8;’)
res.write(JSON.stringify(data))
res.end()
return;

}
//d:读取路由内容并输出
let result = fs.readFileSync(fullpath)
res.write(result);
res.end()
})
.listen(3000, function () {
console.log(‘localhost 3000 start…’)
})


### 静态资源服务实战


d:步骤:


1、在本地启动一个server,等待来自客户端的请求  
 2、当请求抵达时,根据请求的url,设置静态资源的路径为`www`,映射到文件的位置  
 3、检查文件是否存在,如果不存在,返回错误页面,如果存在


* 判断文件是文件还是文件夹,打开文件待读取
* 设置response header
* 发送文件到客户端


4、等待来自客户端的下一个请求  
 Server.js



const http = require(‘http’);
const content = require(‘./util/content’)
const proxy = require(‘http-proxy-middleware’)
const mimeTypes = require(‘./util/mimeTypes’)
const path = require(‘path’);

//静态资源的路径
const statPath = __dirname + ‘/www’;

//解决History强制刷新的问题
function refershHistory(res) {
res.writeHead(302, {
‘location’: ‘http://localhost:3000/’
})
res.end();
return false;
}

//设置代理
function setProxy(url, req, res) {
if (//api/.test(url)) {
console.log(‘proxy’)
let options = {
target: ‘http://localhost:3005’,
changeOrigin: true,
pathRewrite: {
‘^/api’: ‘’
}
}
let statProxy = proxy(options);
return statProxy(req, res)
}

if (//static/.test(url)) {
console.log(‘proxy’)
let options = {
target: ‘https://www.lgstatic.com’,
changeOrigin: true,
pathRewrite: {
‘^/static’: ‘’
}
}
let statProxy = proxy(options);
return statProxy(req, res)
}
}

var app = http.createServer((req, res) => {
let url = req.url;
//默认索引页
if (url === ‘/’) {
url = “/index.html”
}

//history强制刷新问题
if (/?position|search|profile/.test(url)) {
return refershHistory(res);
}

//代理
if (//api/.test(url) || //static/.test(url)) {
return setProxy(url, req, res);
}

let extname = path.extname(url).substring(1);
let conentType = mimeTypes[extname] ? mimeTypes[extname] : “text/html”;
res.setHeader(‘Content-Type’, conentType)
let result = content(url, statPath);
res.write(result);
res.end();

})

app.listen(3000, function (err) {
if (!err) {
console.log(‘localhost 3000 start …’)
}
})


util/content.js 根据url读文件内容



const fs = require(‘fs’);
//d:statPath绝对路径
function content(src, statPath) {
let fullPath = statPath + src;
console.log(‘fullPath:’, fullPath)
//d:判断是文件夹还是文件
if (fs.existsSync(fullPath)) {
let stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
return readDir(fullPath);
} else {
return fs.readFileSync(fullPath);
}
} else {
return ‘file not found’
}

}

//d:读取文件夹里内容
function readDir(src) {
let files = fs.readdirSync(src);
let result = [‘

  • ’];
    files.forEach((item, index) => {
    result.push( <li>${item}</li>)
    })
    result.push(‘
’)
return result.join(’ ')
}

module.exports = content;


util/mimeType.js



let mimes = {
‘css’: ‘text/css’,
‘less’: ‘text/css’,
‘gif’: ‘image/gif’,
‘html’: ‘text/html’,
‘ico’: ‘image/x-icon’,
‘jpeg’: ‘image/jpeg’,
‘jpg’: ‘image/jpeg’,
‘js’: ‘text/javascript’,
‘map’: ‘text/javascript’,
‘json’: ‘application/json’,
‘pdf’: ‘application/pdf’,
‘png’: ‘image/png’,
‘svg’: ‘image/svg+xml’,
‘swf’: ‘application/x-shockwave-flash’,
‘tiff’: ‘image/tiff’,
‘txt’: ‘text/plain’,
‘wav’: ‘audio/x-wav’,
‘wma’: ‘audio/x-ms-wma’,
‘wmv’: ‘video/x-ms-wmv’,
‘xml’: ‘text/xml’,
‘woff2’: ‘application/octet-stream’,
‘woff’: ‘application/octet-stream’,
‘ttf’: ‘application/octet-stream’
}

module.exports = mimes;


### 


## socket


### websocket


<https://www.runoob.com/html/html5-websocket.html>


WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。


WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。


在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。


现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。


HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200720213721494.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDE1Nzk2NA==,size_16,color_FFFFFF,t_70)


d:


#### websocket实现思路


* new WebSocket, WebSocket 有自己独有的协议`ws`
* WebSocket服务端使用 `ws第三方模块`,接收客户端发来的信息并做处理返回给客户端


websocket的五步法:  
 第一步:new WebSocket(“ws://localhost:9998/echo”);  打开一个websocket  
 第二步:onopen :连接建立时触发  
 第三步:onmessage:客户端接收服务端数据时触发  
 第四步:onerror:通信发生错误时触发  
 第五步:close:连接关闭时触发


#### 实现原理


##### index.html



Document
留言

##### websocketServer.js


`ws`第三方模块<https://www.npmjs.com/package/ws>



const ws = require(‘ws’);

var websocketServer = new ws.Server({ port: 8099 });

//所有的客户端列表
var clientlist = {}
var id = 0;

websocketServer.on(‘connection’, (client) => {
client.id = id++;
clientlist[id] = client;
console.log(‘connection…’)
client.send(‘welcome to back’)
client.on(‘message’, (msg) => {
console.log(msg)
boardcast(client.id + “:” + msg);
})

//client退出时的事件
client.on(‘close’, () => {
boardcast(client.id + " 下线了");
delete clientlist[client.id];
})

})

//广博通知,所有客户端
function boardcast(message) {
for (let o in clientlist) {
clientlist[o].send(message)
}
}


### Socket.io


### Net


## Express介绍和安装


<https://www.expressjs.com.cn/>  
 这个翻译的版本比较好<http://caibaojian.com/expressjs/index.html>



npm install express --save


### helloworld



const express = require(‘express’);

const app = express();

app.get(‘/’, (req, res) => {
res.send(‘hello world’);// res.write + res.end
})

app.listen(3000, () => {
console.log(‘localhost start 3000 …’)
})


### 路由



const express = require(‘express’);

const app = express();

app.get(‘/’, (req, res) => {
res.send(‘hello world’);// res.write + res.end
})

app.post(‘/’, (req, res) => {
res.write(‘post hello world’);
res.end()
})

app.put(‘/’, (req, res) => {
res.send(‘put hello world’)
})

app.delete(‘/’, (req, res) => {
res.send(‘delete hello world’)
})

app.listen(3000, () => {
console.log(‘localhost start 3000 …’)
})


### 静态文件


文件目录结构  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200720225907241.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDE1Nzk2NA==,size_16,color_FFFFFF,t_70)



const express = require(‘express’);
const path = require(‘path’)

const app = express();

//可以配置多个静态资源目录, d:静态资源目录可以直接用server+文件名进行访问
app.use(express.static(‘public’))
// app.use(express.static(‘files’))

//可以给目录添加前缀
// app.use(‘/static’, express.static(‘files’))

//配置为绝对路径 d:当server目录和静态资源目录不在同级下时,可以配置绝对路径
app.use(‘/static’, express.static(path.resolve(__dirname, ‘./files’)))

app.listen(3000, () => {
console.log(‘localhost start 3000 …’)
})


### 中间件


* 执行任何代码
* 修改请求和响应对象
* 决定是否执行或结束请求响应周期
* 调用堆栈中的下一个中间件



const express = require(‘express’);
const path = require(‘path’)
const app = express();
var myLogger = function (req, res, next) {
console.log(‘log …’)
//转向下一个路由,中间件
next();
}

var requestTime = function (req, res, next) {
console.log(new Date().getTime())
next();
}

//应用中间件,中间件有前后顺序
app.use(requestTime, myLogger);
// app.use(myLogger);

app.get(‘/’, function (req, res) {
res.send(‘hello world’);
})

app.listen(3000, () => {
console.log(‘localhost start 3000 …’)
})


#### 自定义中间件外部引入


![在这里插入图片描述](https://img-blog.csdnimg.cn/20200720232619702.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDE1Nzk2NA==,size_16,color_FFFFFF,t_70)  
 myself-middleware.js



module.exports = function (){
return function (req,res,next){
console.log(“myselt middleware”)
next()
}
}


app.js内导入



const mySelfMidd = require(“./myself-middleware.js”)
app.use(mySelfMidd )


### 使用中间件


#### 应用程序中间件



const express = require(‘express’);
const app = express();

//应用中间件
// app.use(‘*’, function (req, res, next) {
// console.log(‘method:’, req.method);
// console.log(‘middleware:’, req.params)
// next();
// });

app.use(‘*’, function (req, res, next) {
console.log(1)
next();
}, function (req, res, next) {
console.log(2)
next();
});

app.get(‘/user/:id/books/:bookid’, function (req, res) {
console.log(‘get:’, req.params)
res.send(‘hello world’);//d:直接返回
})

app.listen(3000, () => {
console.log(‘localhost start 3000 …’)
})


#### 路由中间件


##### app.js



const express = require(‘express’);
const bodyParser = require(‘body-parser’);
const userRouter = require(‘./user’);//d:导入user模块
const app = express();

app.use(‘/static’, express.static(‘files’))

app.use(function (req, res, next) {
console.log(‘application middleware …’)
next();
})

//extended: false 表示是否使用系统模块 querystring ,官方推荐
//extended: true 使用第三方qs来处理
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())//d:最终输出的数据都是以json输出的
//d:中间件是有前后顺序的,使用body-parser需要放在路由的user模块之前,当使用路由中间件的时候才会成功使用body-parser

app.use(‘/user’, userRouter)//d:使用user模块,添加了一个 /user 的前缀

//错误优先的原则
app.use(function (err, req, res, next) {
console.log(err.stack);
res.status(200).send(‘somting is wrong!’)
})

app.listen(3000, () => {
console.log(‘localhost start 3000 …’)
})


##### user.js(用户的路由中间件的模块)



const express = require(‘express’);

var router = express.Router();

//针对user下所有的路由接口
router.use(function (req, res, next) {
//获取传过来的用户信息
//let username = req.body.username;
//从数据库查询
//let rs = db.getUserinfo(uername)
// if(rs){next()}
// else {
// res.send(‘用户不存在’)
// }
console.log(‘权限验证’)
next();
})

//针对user下 /:id 的接口做权限验证
router.use(‘/:id’, function (req, res, next) {
console.log(‘id 权限验证’)
next();
})

//http://localhost:3000/user/10
// router.get(“/:id”, function (req, res) {
// console.log(req.params.id)
// res.send(req.params.id)
// })

//d:获取名字的接口
router.get(‘/getname’, function (req, res) {
// res.setHeader(‘Content-Type’,‘’)
console.log(“get name …”)
//d:可以直接使用json返回
res.json({
name: ‘肖战’,
age: 20
})
})

//crud: create read update delete

//数据的添加,消息体在body上
//建议全部更新
router.post(‘/add’, function (req, res) {
//用req.body获取post数据,需要装body-parser中间件
console.log(req.body);
res.send(req.body)
})

//获取数据,请求的参数在url地址上,在不同的浏览器上有长度的限制
//长度的限制是浏览器限制的,不是http协议限制的
//http://localhost:3000/user/getinfo?username=hanye&age=20
router.get(‘/getinfo’, function (req, res) {
//req.query 不需要装任何中间件,或者配置
console.log(req.query)
res.send(req.query)
})

//数据的更新,消息体在body 上
//建议全部更新
router.put(‘/r1’, function (req, res) {
res.send(‘r1’)
});

//数据的更新,消息体在body 上
//建议部分更新 {name:‘zhangsan’,age:20,address:“beijing”}
router.patch(‘/r2’, function (req, res) {
res.send(‘r2’)
})

//数据的删除,消息体在body上
router.delete(‘/r3’, function (req, res) {
res.send(‘r3’)
})

//数据的协商,测试服务端的一些功能
router.options(‘/r4’, function (req, res) {
res.send(‘r4’)
})

// head
// 类似于get请求,返回的响应中没有类容,用于获取报头

router.get(‘/r5’, function (req, res) {
throw new Error(‘error message’)
})

module.exports = router;


#### 异常处理中间件


通常写在最后面,参数必须是四个



router.get(‘/r5’, function (req, res) {
throw new Error(‘error message’)//抛出异常
})



//错误优先的原则
app.use(function (err, req, res, next) {
console.log(err.stack);
res.status(200).send(‘somting is wrong!’)
})


#### 内置中间件



express.static //静态资源的设置,html,图片,。。.
express.json //解析传入的的数据请求,为json格式
express.urlencoded parses incoming requests with URL-encoded payloads. NOTE: Available with Express 4.16.0+


#### 第三方中间件


官方推荐:<https://www.expressjs.com.cn/resources/middleware.html>



app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())


#### 练习


get: http://localhost:3000/user/42


​ http://localhost:3000/users/34/books/8989


​ http://localhost:3000/flights/LAX-SFO


埋点:http://localhost:3000/user/hm.gif?id=1&keyword=


Post: http://localhost:3000/user/add {username:‘xiaoming’,age:20}



const express = require(‘express’);

var router = express.Router();

//http://localhost:3000/user/42
// router.get(‘/:id’, (req, res) => {
// res.send(req.params.id)
// })

//http://localhost:3000/user/66/books/88
router.get(‘/:id/books/:bookid’, (req, res) => {
res.json({
id: req.params.id,
bookid: req.params.bookid
})
})

// http://localhost:3000/user/flights/LAX-SFO
router.get(‘/flights/:from-:to’, (req, res) => {
res.send({
from: req.params.from,
to: req.params.to,
})
})

//http://localhost:3000/user/hm.gif?id=1&keyword=china
router.get(‘/hm.gif’, (req, res) => {
res.send(req.query)
})

//http://localhost:3000/user/add
router.post(‘/add’, (req, res) => {
res.send({
code: 1,
message: ‘数据获取成功’,
data: req.body //需要装第三方中间件,body-parser
})
})

module.exports = router;


### express generator


搭建框架  
 `express --view==ejs ./`  
 安装依赖  
 `npm install -g express-generator`



//异常处理
var createError = require(‘http-errors’);
var express = require(‘express’);
var path = require(‘path’);
var cookieParser = require(‘cookie-parser’);
//日志处理模块
var logger = require(‘morgan’);
var indexRouter = require(‘./routes/index’);
var usersRouter = require(‘./routes/users’);

var app = express();

// view engine setup
//指定模板存储的位置
app.set(‘views’, path.join(__dirname, ‘views’));
app.set(‘view engine’, ‘ejs’);

app.use(logger(‘dev’));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, ‘public’)));

app.use(‘/’, indexRouter);
app.use(‘/users’, usersRouter);

// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404, ‘file not found!’));
});

// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
//全局的配置信息
res.locals.message = err.message;
res.locals.error = req.app.get(‘env’) === ‘development’ ? err : {};
// render the error page
res.status(500);
//参数是模板的名字
res.render(‘error’);
});

module.exports = app;


## Ejs


### 什么是EJS


EJS是一个简单高效的模板语言,通过数据和模板,可以生成HTML标记文本。可以说EJS是一个JavaScript库,EJS可以同时运行在客户端和服务器端,客户端安装直接引入文件即可,服务器端用npm包安装。


#### EJS的特点


* 快速编译和渲染
* 简单的模板标签
* 自定义标记分隔符
* 支持文本包含
* 支持浏览器端和服务器端
* 模板静态缓存
* 支持express视图系统


#### EJS的成员函数


Render(str,data,[option]):直接渲染字符串并生成html  
 str:需要解析的字符串模板  
 data:数据  
 option:配置选项


#### EJS的常用标签


<% %>流程控制标签  
 <%= %>输出标签(原文输出HTML标签)  
 <%- %>输出标签(HTML会被浏览器解析)  
 <%# %>注释标签  
 % 对标记进行转义


#### Includes




## MongoDB


<https://www.mongodb.com/download-center/community>


MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。


它的特点:高性能、易部署、易使用,存储数据非常方便。


### 在Windows系统上安装


为了从命令提示符下运行MongoDB服务器,你必须从MongoDB目录的bin目录中执行mongod.exe文件。  
 或者将bin配置到环境变量path中。



> 
> mongod --dbpath d:\data\db
> 
> 
> 


安装不成功的原因:


1:操作系统版本较低,dll缺失,建议装3.6版本


2:闪退 (cmd : 进入到安装目录 的bin目录,执行 mongod.exe ,看详细的错误信息 )


### 在Mac系统上安装


在Mac OS上面安装MongoDB,你可以通过编译源代码来安装 ,也可以在Mac OS上使用Homebrew安装。  
 使用Homebrew安装MongoDB:  
 方法一:$ brew install mongodb ( brew install mongodb-community@4.0 )  
 方法二:https://github.com/mongodb/homebrew-brew


启动:



mongod --config /usr/local/etc/mongod.conf


### MongoDB术语/概念


![在这里插入图片描述](https://img-blog.csdnimg.cn/20200724194003144.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDE1Nzk2NA==,size_16,color_FFFFFF,t_70)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200724193953637.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDE1Nzk2NA==,size_16,color_FFFFFF,t_70)


一个mongodb中可以建立多个数据库。


MongoDB的默认数据库为"db",该数据库存储在data目录中。


MongoDB的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中。


### MongoDB 集合


集合就是 MongoDB 文档组,类似于 RDBMS (关系数据库管理系统:Relational Database Management System)中的表格。


集合存在于数据库中,集合没有固定的结构,这意味着你在对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。


### MongoDB 文档


文档是一个键值(key-value)对(即BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点。


一个简单的文档例子如下:  
 {“genres”: [“犯罪”,“剧情” ],“title”: “肖申克的救赎”}


### MongoDB 数据类型


* Object ID :Documents 自生成的 \_id
* String: 字符串,必须是utf-8
* Boolean:布尔值,true 或者false
* Integer:整数 (Int32 Int64 你们就知道有个Int就行了,一般我们用Int32)
* Double:浮点数 (没有float类型,所有小数都是Double)
* Arrays:数组或者列表,多个值存储到一个键
* Object:如果你学过Python的话,那么这个概念特别好理解,就是Python中的字典,这个数据类型就是字典
* Null:空数据类型 , 一个特殊的概念,None Null
* Timestamp:时间戳
* Date:存储当前日期或时间unix时间格式 (我们一般不用这个Date类型,时间戳可以秒杀一切时间类型)


### 数据库常用命令


1. (1)Help查看命令提示
2. help
3. db.help()
4. db.test.help()
5. db.test.find().help()
6. (2)创建/切换数据库
7. use music
8. (3)查询数据库
9. show dbs
10. (4)查看当前使用的数据库db/db.getName()
11. (5)显示当前DB状态
12. db.stats()
13. (6)查看当前DB版本
14. db.version()
15. (7)查看当前DB的链接机器地址
16. db.getMongo()
17. (8)删除数据库
18. db.dropDatabase()


### Collection集合操作


1. (1)创建一个集合
2. db.createCollection(“collName”, {size: 20, capped: true, max: 100});
3. db.collName.isCapped(); //判断集合是否为定容量
4. (2)得到指定名称的集合
5. db.getCollection(“account”);
6. (3)得到当前db的所有集合
7. db.getCollectionNames();
8. (4)显示当前db所有集合的状态
9. db.printCollectionStats();


### 添加、修改与删除集合数据


(1)添加


db.users.save({name:‘zhangsan’,age:25,sex:true})


db.users.save({name:‘lisi’,age:20,sex:true,address:‘beijing’})


(2)修改


//1:查询条件


//2:更新字段


//3: 是否需要将参数2插入到集合当中,如果没有查询到记录,配置为false,否则为true


//4:更新一条,还是多条, true:多条记录,false:单条记录


db.users.update({age:25},{$set:{name:‘changeName’}},false,true)


(3)删除


db.users.remove({age:23})


### 集合数据查询(一)



(1)查询所有记录

db.users.find()

(2)查询去重后数据
db.users.distinct(‘name’)
(3)查询age = 20的记录
db.users.find({age:20})

(4)查询age > 22的记录
db.users.find({age:{$gt:22}})

(5)查询age < 22的记录
db.users.find({age:{$lt:22}})

(6)查询age >= 23的记录
db.users.find({age:{$gte:23}})

(7)查询age <= 23的记录
db.users.find({age:{$lte:23}})

(8)查询age >= 23 并且 age <= 25
db.users.find({age:{ g t e : 23 , gte:23, gte:23,lte:25}})

(9)查询name中包含 change的数据
db.users.find({name:/change/})
mysql:select * from users where name ‘%change%’

(10)查询name中以ch开头的
db.users.find({name:/^ch/})


### 集合数据查询(二)



(11)查询指定列name、age数据

db.users.find({},{name:1,age:1,_id:0})

(12)查询指定列name、age数据, age > 23
db.users.find({age:{$gt:23}},{name:1,age:1,_id:0}

(13)按照年龄排序
升序:db.users.find({},{name:1,age:1,_id:0}).sort({age:1})
降序:db.users.find({},{name:1,age:1,_id:0}).sort({age:-1})

(14)查询name = lisi, age = 20的数据

db.users.find({name:‘lisi’,age:20},{name:1,age:1,_id:0})

(15)查询前3条数据
db.users.find().limit(3)


### 集合数据查询(三)



(16)查询5条以后的数据

db.users.find(),skip(5)

(17)查询在3-5之间的数据
db.users.find().limit(3).skip(2)

(18)or与 查询

db.users.find({$or:[{age:25},{age:23}]})

(19)查询第一条数据
db.users.findOne()

(20)查询某个结果集的记录条数

db.users.find({age:20}).count()


### 案例练习


导入数据:



db.movies.insertMany([{},{}])



//查询所有数据
db.movies.find()

//查询电影列
db.movies.find({},{title:1,_id:0})

//查询电影名称、年份 , 评分
db.movies.find({},{title:1,year:1,_id:0,‘rating.average’:1})

//按照评分排序
db.movies.find({},{title:1,year:1,_id:0,‘rating.average’:1}).sort({‘rating.average’:-1})

//按照年份排序

db.movies.find({},{title:1,year:1,_id:0,‘rating.average’:1}).sort({year:-1})
//模糊查询
db.movies.find({title:/人/},{title:1,_id:0})

//获取总条数
db.movies.find({title:/人/},{title:1,_id:0}).count()

//根据翻页获取指定页面的数据
db.movies.find({},{title:1,_id:0}).skip(5).limit(5)


### Node连接mongoDB


db.js



const mongoose = require(‘mongoose’);

mongoose.connect(‘mongodb://127.0.0.1:27017/games’, {
useNewUrlParser: true,
useUnifiedTopology: true
})

var db = mongoose.connection;

db.on(‘error’, console.error.bind(console, ‘connection error:’));

db.once(‘open’, function () {
console.log(‘open…’)
})

module.exports = mongoose;


Index.js



const db = require(‘./db’);

var UserModel = db.model(‘users’, {
name: String,
age: Number,
sex: Boolean,
address: String
})

async function find() {
let rs = await UserModel.find({});
console.log(rs);
}

find();

function add() {
UserModel.insertMany([{ name: ‘user5’, age: 20 }, { name: ‘user6’, age: 21 }], function (err, docs) {
console.log(docs)
})
}

// add();

// async function update() {

// let rs = await UserModel.update({ name: ‘user6’ }, { $set: { age: 31 } })
// console.log(rs);
// }

// update();

// async function del() {
// let rs = await UserModel.remove({ name: “user6” })
// console.log(rs);
// }

// del()


  

  

## webpack


官网<https://www.webpackjs.com/concepts/>


### 核心概念


Entry :入口


output:出口


Plugins: 插件,执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量


Loader:翻译官,把浏览器不识别的内容做转换


### 研发环境



yarn add webpack webpack-cli //基础依赖

yarn add webpack-dev-server -D //热更新

yarn add mini-css-extract-plugin -D//将css文件提取为独立的文件的插件

yarn add html-webpack-plugin -D // 将模板文件和js文件整合到一块

yarn add sass-loader node-sass -D


##### webpack常用的插件和常用的 loader有哪些


**插件:**  
 mini-css-extract-plugin  
 html-webpack-plugin


**loader**  
 babel-loader  
 style-loader  
 css-loader  
 sass-loader


#### 自定义配置文件


创建webpack.config.dev.js 配置开发环境


添加快捷指令  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/2020072419573893.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDE1Nzk2NA==,size_16,color_FFFFFF,t_70)  
 webpack.config.dev.js



const path = require(‘path’)
const htmlWebpackPlugin = require(‘html-webpack-plugin’)
const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)

module.exports = {
//开发模式:development,代码调试, 生产模式:production ,代码压缩,优化
//如果mode不配置,会有警告提示信息
mode: “development”,
//代码调试,可以看到源代码
devtool: ‘inline-source-map’,

//入口文件,如果不配置,默然找根目录下 /src/index.js
// entry:“./src/js/index.js”,
entry: {//多页面,两个入口
‘main’: “./src/js/index.js”,
‘detail’: “./src/js/detai.js”
},
//打包完成,输出文件的位置(不能写相对路径),可以不配置,默认输出到dist目录
output: {
path: path.resolve(__dirname, ‘./dev’),
filename: ‘[name]-[hash].js’
},

//d:热更新
devServer: {
port: 9099,
//打开浏览器
open: true
},

// d:将模板文件和js文件整合到一块
plugins: [
new htmlWebpackPlugin({
title: ‘webpack demo home’,
//模板文件路径
template: “./src/views/index.html”,
//自动存储到output 配置的目录
filename: ‘index.html’,
chunks: [‘main’]//指定模块,让index.html的页面的内容只加载该页面对应的js的内容,如果不加的话也会同时加载detail页面的内容
}),

//d:多页面配置
new htmlWebpackPlugin({
title: ‘webpack demo home’,
//模板文件路径
template: “./src/views/detail.html”,
//自动存储到output 配置的目录
filename: ‘detail.html’,
chunks: [‘detail’]
}),

//d:将css文件提取为独立的文件的插件
new MiniCssExtractPlugin({
//页面引用的样式文件名
filename: ‘[name]-[hash].css’,
// chunkFilename: ‘common.css’,
})
],
module: {
rules: [
{
test: /.s[ac]ss$/,
//执行顺序:从右向左
use: [
// 将 JS 字符串生成为 style 节点
‘style-loader’,
// MiniCssExtractPlugin.loader, //这个和style-loader二者选其一,都是使用css的方式
//将 CSS 转化成 CommonJS 模块
‘css-loader’,
//把.scss文件文件转换为.css文件
‘sass-loader’
]
}
]
}
}


### 生产环境


## 项目实战


### 架构设计


#### 最后

-------------------------------------------------------------

**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)**

大厂面试问深度,小厂面试问广度,如果有同学想进大厂深造一定要有一个方向精通的惊艳到面试官,还要平时遇到问题后思考一下问题的本质,找方法解决是一个方面,看到问题本质是另一个方面。还有大家一定要有目标,我在很久之前就想着以后一定要去大厂,然后默默努力,每天看一些大佬们的文章,总是觉得只有再学深入一点才有机会,所以才有恒心一直学下去。



![](https://img-blog.csdnimg.cn/img_convert/718310d106ab948d6f467d78e08b1aed.png)



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值