01、前端存储:cookie、sessionStorage和localStorage的区别
相同点:
- cookie、sessionStorage和localStorage都属于浏览器本地存储;
- cookie、sessionStorage和localStorage存储遵循的同源策略。sessionStorage还限制是同一个页面。
区别是:
- cookie是由服务器端写入的,sessionStorage和localStorage是前端写入的;
- cookie的有效期,是在服务端设置好的。sessionStorage则是在页面关闭后自动清除,localStorage则可以长期保存,除非手动清除。
- cookie的存储空间比较小,每一个cookie大概是4kb。sessionStorage和localStorage存储空间比较大,大约为5M。
- 前端向后端发起请求的时候,会自动携带cookie。localStorage和sessionStorage则不会。
cookie是一般用于存储验证信息SessionID或者token;localStorage一般是用来存储一些不易变动的数据,这样减小服务器的压力。sessionStorage是用来检测用户是否是刷新进入页面的,比如音乐播放器进度条。
02、JavaScript数据类型
JavaScript数据类型分为两种:一种基本数据类型,一种是引用数据类型
基本数据类型:number、string、boolean、null、undefined、symbol和BigInt。 引用数据类型:object,包括了function、array、正则、date日期和Math数学函数。
基本数据类型和引用数据类型,它们在内存中的存储方式不同。基本数据类型是直接存储在栈内存中。引用数据类型是存储在堆内存中的,在栈内存中存储了指针,这个指针指向在堆内存中的实体。
基本数据类型中symbol是ES6新增的一种数据类型,它的特点就是不能有重复数据,可以用来作为对象的key。symbol创建的数据是唯一的,所以 Symbol() !== Symbol()。
BigInt数据类型,也是ES6新增,作用就是扩大了数据的范围,能够解决普通数据类型范围报错的问题。BigInt有两种使用方法:一种是直接在整数后面加n。另一种方式是调用BigInt构造函数。
03、对闭包的理解
函数和词法环境绑定在一起,这样的组合就是闭包,比如有一个函数A,它return一个函数B。函数B是可以访问到函数A内部定义的变量。函数A执行结束后,函数A中声明的变量并不会被销毁。
闭包的优点:让函数作用域中的变量不会因为函数执行结束而被销毁。也可以在外部访问到函数内部的局部变量; 闭包的缺点:垃圾回收器不会销毁闭包中的变量,这样就造成内存泄漏。
04、说一下Promise
Promise是实现异步的一种方式,解决了异步多层嵌套回调的问题,提升了代码的可读性,同时让我们所写的代码更利于维护。
Promise有三个状态:pendding、resolve和reject。在Promise的整个过程中,只发生一次状态转变。由pendding转为resolve或者reject。
Promise构造函数接收一个函数作为参数,这个函数有两个参数:resolve和reject,resolve和reject都是函数。
resolve函数的作用是把Promise由等待状态改为成功状态;reject是把Promise由等待状态转变为失败状态。
在Promise构造函数创建实例完成后,通过then函数来接收成功的回调函数,通过catch函数接受失败的回调函数,比如:
const func = function (parma) {
return new Promise((resolve, reject) => {
if (parma > 2) {
resolve(parma)
}
reject(parma)
})
}
func(0).then(res => {
console.log("结果", res)
}).catch(err => console.log("报错", err))
Promise的特点:
- Promise的状态,不收到外界的影响,当Promise发生状态变化后,Promise的生命周期也就结束了。
- Promise只发生一次状态改变。
- resolve的参数是then方法中回调函数的参数;reject的参数是catch方法中回调函数的参数。
Promise的其他方法:
Promise.all()
把多个Promise包装成一个Promise对象,等参数里面所有的Promise都返回成功了,才触发成功,否则返回失败结果,比如:
const func = new Promise((resolve, reject) => {
resolve(1)
})
const func2 = new Promise((resolve, reject) => {
reject(1)
})
const allPromise = Promise.all([func, func2])
allPromise.then(res => {
console.log("结果", res)
}).catch(err => {
console.log("报错", err)
})
这段代码的结果是失败状态:1
如果func2调用的resolve(1)的话,那么这段代码的结果为成功状态:[1,1]
Promise.any()
接收一个Promise对象集,只要有一个Promise返回成功,那么就返回这个Promise成功的值,比如:
const func = new Promise((resolve, reject) => {
resolve(1)
})
const func2 = new Promise((resolve, reject) => {
reject(0)
})
const promise = Promise.any([func, func2])
promise.then(res => {
console.log("结果", res)
}).catch(err => {
console.log("报错", err)
})
这段代码的结果为:结果 1
Promise.race()
只要Promise集合里面,有一个子Promise返回成功或者失败,那么父Promise将子Promise的状态返回,然后结束Promise的生命周期。比如:
const func = new Promise((resolve, reject) => {
reject(1)
})
const func2 = new Promise((resolve, reject) => {
resolve(0)
})
const promise = Promise.race([func, func2])
promise.then(res => {
console.log("结果", res)
}).catch(err => {
console.log("报错", err)
})
05、什么是跨域,怎么解决跨域
跨域:就是当前页的请求地址和当前页面的地址中,协议、域名、端口,其中一个不同,就造成了跨域。原因是浏览器为了保护网页安全做出的同原协议策略。
跨域的解决方式:
- cors;通过设置后端允许跨域访问
- node中间件、Nginx反向代理:跨域是浏览器限制不能跨域访问服务器,而node中间件和Nginx反向代理,是向代理服务器发起请求,代理服务器再向后端服务器发起请求。服务器和服务器之间不存在同源限制。
出现跨域的场景,一般是前后端分离开发、调用第三方接口。
06、什么是BFC
BFC是块级格式化上下文,是web页面中一个独立的渲染区域,内部元素的渲染不会影响到区域外面的其他元素。
BFC布局规则是: 内部元素会在垂直方向堆叠摆放,元素上下之间的距离,是由margin来决定的,而相邻的两元素的margin会发生重叠。
07、js判断数据类型的方式
JavaScript有3种方法判断数据类型:typeof、instanceof、Object.prototype.toString.call()。
typeof:用来判断基本数据类型的,如果使用typeof来判断引用数据类型的话,除了function会返回“function”,其他的都会返回“object”。
instanceof:用来区分引用数据类型、判断实例是否属于某一个构造函数。检测过程比较繁琐,而且对于undefined、null和symbol数据类型是无法检测的
Object.prototype.toString.call():可以用来检测所有的数据类型,返回的是该数据类型的字符串。
instanceof的原理是验证当前对象的原型prototype是不是出现在实例的原型链proto上,如果在,就返回true,否则返回false。
Object.prototype.toString.call()的原理是Object.prototype.toString表示一个返回对象数据类型的字符串,call()方法是改变this的指向,也就是把Object.prototype.toString()方法指向不同的数据类型上。
08、CSS样式优先级
在CSS样式中!important的优先级是最高的。其次是内联样式。
CSS选择器的优先级:id选择器 > (类选择器 | 伪类选择器|属性选择器) > (后代选择器 | 伪元素) > 子选择器或者相邻选择器 > 通配选择器。
09、JavaScript异步的方式
回调函数:是异步操作的基本方式,也是最简单,容易理解和实现的,比如常见的AJAX。但是回调函数不利于代码维护和阅读,代码结构混乱,流程难以追踪。
Promise、async/await
这三种是最常见的,实现异步操作的方式。
10、数组去重的方式
- 定义一个新数组,然后遍历数组过程中,每次判断新数组中是否存在元素,不存在的话,就将元素push进去。
- 利用Set数据类型的不重复特点,new一个Set,参数就是需要去重的数组,set会自动删除重复数据,然后将set转化为数组返回。
- reduce + includes:利用reduce遍历数组和传入一个空数组作为去重后的新数组,在内部再来判断新数组中是否存在当前元素,如果不存在,那么就将元素push进去。