变量的类型(8种)
7种原始类型:Boolean、Undefined、Null、String、Number、Symbol(不可修改的)、BigInt(可以超过数字的安全整数限制,2^53)和Object
typeof null === 'object'
typeof function fn() {} === 'function'
typeof a= [] === 'object'
基本数据类型存储在栈里,引用类型存储在堆里
栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。
栈是后进先出,堆是可以随意取出想要的
深拷贝和浅拷贝
深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是引用。
假设B复制了A,修改A的时候,看B是否发生变化:
如果B跟着也变了,说明是浅拷贝,拿人手短!(修改堆内存中的同一个值)
如果B没有改变,说明是深拷贝,自食其力!(修改堆内存中的不同的值)
什么时候用呢?也就是拷贝完之后是否还要用被拷贝的数据
var a = [1, 2, 3]
var b = a; // 浅拷贝
var b = a.concat([]); // 深拷贝
var b = a.slice(0); // 深拷贝
以上两种方法都生成了新数组
实现深拷贝的3种方法:
1.JSON.parse(JSON.stringify(xxx))
2.用递归的方法
function copy(obj) {
var newobj = null;
//通过typeof判断是否为引用数据类型且不等于null 注意typeof (null)===object
if (typeof (obj) === 'object' && obj !== null) {
// 三元表达式 来判断储存的类型
newobj = obj instanceof Array ? [] : {}
//循环obj 中的每一项,如果里面还有复杂数据类型,则直接利用递归再次调用copy函数
for (const key in obj) {
newobj[key] = copy(obj[key])
}
// 为基本就直接赋值
} else {
newobj = obj
}
return newobj
}
————————————————
版权声明:本文为CSDN博主「一团小强强」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42241018/article/details/107895767
3.loadsh的cloneDeep
var, let, const区别
let, var, const都是用来声明变量的
var存在声明提升,允许重复定义和赋值的
const 一般用来定义敞亮,值不能被更改,所以在定义时就要赋值,复杂类型不能更改它的地址,如const a = [];她是可以被push的,a[0] = 1;
let和const都只在声明所在的会计作用与有效,不存在变量提升。
let 1.不存在变量声明提升
2.存在暂时性死区(在代码定义前使用,会报错)
function(x = y, y =2) {}
3.不允许重复声明
4.块级作用域(es5只用全局和函数作用域)
解构赋值
从数组和对象中提取值,对变量进行赋值
Promise
promise是异步解决方案,对象的状态不受外界的影响
他有三个状态:pender、fullfiled、rejected
promise构造函数接受一个函数做参数,resolve和reject
resolve的作用是将pending->fullfiled
异步操作的成功时的调用,将异步操作的结果作为参数传递出去
reject的作用是将pending->rejected
异步操作失败时调用
.then方法是定义在原型对象Promise.prototype
上的,返回的是一个新的promise实例,是promise的resolved的一个回调函数
.catch方法也是定义在原型对象Promise.prototype
上的,返回的也是一个新的promise实例promise的rejected的一个回调函数
promise内部的error会被外部的promise吃掉(就是会报错,但是还是会继续执行,这与try/catch不同),因此在可能的情况下,可以写多个catch
async和await的返回都是一个新的promise对象
Event Loop
即事件循环,是指浏览器或Node的一种解决js单线程运行时不回阻塞的一种机制,也就是我们常用的异步原理。
任务分为两种:宏任务(setTimeout、setInterval、IO等)和微任务(Progress.nextTick、Promise、async)
执行栈在执行完同步任务后,查看执行栈是否为空,如果为空就会检查微任务队列,如果微任务队列为空,就去执行宏任务,否则就一次性执行完所有的微任务(先入先出),再去执行宏任务。
async function async1() {
console.log('async start');
await async2();
console.log('async end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout')
}, 0)
async1();
new Promise(function (resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
})
console.log('script end');
// 输出
script start->async start->async2->promise1->script end->async end->promise2->setTimeout
async2的输出是因为实际上await是一个让出线程的标志。await后面的表达式会先执行一遍,将await后面的代码加入到microtask中,然后就会跳出整个async函数来执行后面的代码。
export和export default的区别
export只能输出原来定义的名字,import需要使用原来的名字,而export default可以自定义名称
从url输入到页面展现,到底发生了什么?
1.首先要查看缓存(浏览器的缓存->系统缓存->路由器缓存)
2.DNS解析:将域名解析成ip地址
3.TCP链接:TCP三次握手(防止已失效的链接请求报文段,突然又传送到服务器,然后出错)
4.发送HTTP请求
5.服务器处理请求,并返回HTTP报文
6.浏览器解析渲染页面
7.断开链接,TCP四次挥手
浏览器中的url包含:http://www.baidu.com:8080/search?queryName="xxx"
http:传输协议(http/https)
www.baidu.com:域名
8080:端口
/search: 文件路径
queryName="xxx":参数
HTTP
http包含:请求行、请求头、请求体
http请求包含:TCP握手,http响应信息,关闭TCP连接
请求行:GET、POST、DELET、PUT、OPTIONS等
请求头:host,http1.1中加入了connection: keepalive持久连接,一个连接,多个请求
请求体:可以承载多个请求参数的数据
http响应报文
1.响应行包含:协议版本,状态码及状态码描述
2.状态码如下:
1xx:指示信息-表示请求已接收,继续处理
2xx:成功-表示请求已经被成功接受,理解
3xx:重定向-要完成请求必须进行更进一步操作
4xx:客户端错误-请求有语法错误或请求无法实现
5xx:服务端错误-服务器未能实现合法请求
常见状态码:
200:服务器已经成功接受请求并返回
304:客户端已经拥有该数据
400:客户端请求的语法错误,服务器无法理解
401:身份验证失败
404:服务器无法根据客户端的请求找到资源
500:服务器内部错误
502:网关或代理服务器尝试执行请求,去接受无效回应
HTTP中GET和POST的区别:
1.GET在浏览器回退时是无害的,而POST会再次提交请求。
2.GET产生的URL地址可以被标记为书签,而POST不可以。
3.GET请求会被浏览器主动cache,而POST不会,除非手动设置。
4.GET请求只能进行url编码,而POST支持多种编码方式。
5.GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
6.GET请求在URL中传送的参数是有长度限制的,而POST没有。
7.对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
8.GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
9.GET参数通过URL传递,POST放在Request body中。
浏览器缓存策略(强缓存和协商缓存)
缓存的优点:
1.减少了不必要的数据传输,节省了带宽
2.减少了服务器的负担,提升网站的性能
3.加快了客户端加载网页的速度
4.用户体验友好
缺点:
资源更改时,客户端不及时更新,造成获取信息滞后
强缓存:(200)
当浏览器请求文件时,服务器在response header里对文件做的配置,expires和catch-control
expires:是一个时间戳,二次请求时试图向服务器请求资源,浏览器就会先对比本地时间和expires时间戳,如果本地时间小于expires设定的过期时间,就直接去读取缓存。
缺点:若本地时间(客户端时间)和服务端时间不同,expires就无法达到预期。
catch-control:是一个时间长度,通过max-age来控制资源的有效期,在该时间长度内有效。
public/private:浏览器和代理服务器/浏览器
nostore/no-cache:不使用任何缓存/直接向服务器确认
协商缓存:(304)
依赖于服务端于浏览器之间的通信,浏览器需要向服务器去询问缓存的相关信息,进而判断是重新发送请求,下载完整的响应报文,还是从本地获取缓存的资源
1.last-Modified:是一个时间戳,如果启用协商缓存,他会在首次请求时随着Response Headers返回服务器接受到这个时间戳后,会对比该时间戳和资源在服务器上最后修改的时间是否一致。不一致的话,返回完整的响应内容,否则返回304
缺点:
1.手动更改服务器内容,即使没有修改内容,但服务器也认为这是新内容,进而引发一次完整的响应。
2.修改文件速度过快,if-modified-since只能检查到以秒为最小计量差,所以该请求时,没重新请求。
2.Etag:为了解决Last-Modified更改造成的问题,etag是由服务器为每个资源生成的唯一的标识字符串,文件内容不同,etag不同,当首次请求时,我们会在响应头里获取到一个最初的标识字符串。
eg: etag: w/"2a3b-1602480f459"
下一次请求时,请求头里就会带上一个值相同的,名为if-None-Match的字符串供服务端对比了
缺点:
etag的生成需要服务器的额外开销,会影响服务器的性能。
浏览器缓存:
1.Memory Cache
2.Service Worker Cache
3.Disk Cache
4.Push Cache(http2仅存于会话阶段)
react中HashRouter和BrowserRouter区别:
用法上:
HashRouter相当于锚点定位,不论#号后面的路径怎么变,请求的都相当于是#之前的哪个页面(index.html)
无论前后端是否分离,都可以把前端包放到服务端的public/static里
后端请求的路径为"/"
BrowserRouter请求ip:端口/xxx/xxx因此url都会访问一个不同的后端地址,如果没有该地址则会返回404
可以通过中间件解决,放在服务器端路由匹配的最后,如果前面的api接口不匹配,则返回index.html,要求前后端路由url不能重复
解决方法:前后端分离部署,前一个:IP1:端口1,后一个:IP2:端口2,然后通过ngix配置