面试合集

164 阅读11分钟

一、项目背景

二、性能优化:防抖和节流

防抖:当你持续触发事情时,一段时间内没有再触发事件,执行一次

节流:当你持续触发事情时,一段时间内调用一次函数(risize、scoll)

三、登录如何实现

四、token过期如何处理

五、项目后台谁写的?

六、cookie、localStorage、sessionStorage三个区别

(1)Cookie

Cookie是最早被提出来的本地存储方式,在此之前,服务端是无法判断网络中的两个请求是否是同一用户发起的,为解决这个问题,Cookie就出现了。Cookie的大小只有4kb,它是一种纯文本文件,每次发起HTTP请求都会携带Cookie。

Cookie的特性:

  • Cookie一旦创建成功,名称就无法修改
  • Cookie是无法跨域名的,也就是说a域名和b域名下的cookie是无法共享的,这也是由Cookie的隐私安全性决定的,这样就能够阻止非法获取其他网站的Cookie
  • 每个域名下Cookie的数量不能超过20个,每个Cookie的大小不能超过4kb
  • 有安全问题,如果Cookie被拦截了,那就可获得session的所有信息,即使加密也于事无补,无需知道cookie的意义,只要转发cookie就能达到目的
  • Cookie在请求一个新的页面的时候都会被发送过去

如果需要域名之间跨域共享Cookie,有两种方法:

  1. 使用Nginx反向代理
  2. 在一个站点登陆之后,往其他网站写Cookie。服务端的Session存储到一个节点,Cookie存储sessionId

2)LocalStorage

LocalStorage是HTML5新引入的特性,由于有的时候我们存储的信息较大,Cookie就不能满足我们的需求,这时候LocalStorage就派上用场了。

LocalStorage的优点:

  • 在大小方面,LocalStorage的大小一般为5MB,可以储存更多的信息
  • LocalStorage是持久储存,并不会随着页面的关闭而消失,除非主动清理,不然会永久存在
  • 仅储存在本地,不像Cookie那样每次HTTP请求都会被携带

LocalStorage的缺点:

  • 存在浏览器兼容问题,IE8以下版本的浏览器不支持
  • 如果浏览器设置为隐私模式,那我们将无法读取到LocalStorage
  • LocalStorage受到同源策略的限制,即端口、协议、主机地址有任何一个不相同,都不会访问

LocalStorage的 常用API:

// 保存数据到 localStorage
localStorage.setItem('key', 'value');

// 从 localStorage 获取数据
let data = localStorage.getItem('key');

// 从 localStorage 删除保存的数据
localStorage.removeItem('key');

// 从 localStorage 删除所有保存的数据
localStorage.clear();

// 获取某个索引的Key
localStorage.key(index)

SessionStorage的 使用场景

  • 由于SessionStorage具有时效性,所以可以用来存储一些网站的游客登录的信息,还有临时的浏览记录的信息。当关闭网站之后,这些信息也就随之消除了。

3)SessionStorage

SessionStorage和LocalStorage都是在HTML5才提出来的存储方案,SessionStorage 主要用于临时保存同一窗口(或标签页)的数据,刷新页面时不会删除,关闭窗口或标签页之后将会删除这些数据。

SessionStorage 与LocalStorage对比:

  • SessionStorage和LocalStorage都在本地进行数据存储
  • SessionStorage也有同源策略的限制,但是SessionStorage有一条更加严格的限制,SessionStorage只有在同一浏览器的同一窗口下才能够共享
  • LocalStorage和SessionStorage都不能被爬虫爬取

SessionStorage的 常用API:

// 保存数据到 sessionStorage
sessionStorage.setItem('key', 'value');

// 从 sessionStorage 获取数据
let data = sessionStorage.getItem('key');

// 从 sessionStorage 删除保存的数据
sessionStorage.removeItem('key');

// 从 sessionStorage 删除所有保存的数据
sessionStorage.clear();

// 获取某个索引的Key
sessionStorage.key(index)

七、浏览器有很多标签页,那同一个网站的sessionStorage能访问到吗?

不可以访问

八、什么是跨域、解决跨域有哪些方式?

(1)CORS

①简单请求过程:

在简单请求中,在服务器内,至少需要设置字段: Access-Control-Allow-Origin

②非简单请求过程

至少需要前三个字段

Access-Control-Allow-Origin: http://api.bob.com  // 允许跨域的源地址
Access-Control-Allow-Methods: GET, POST, PUT // 服务器支持的所有跨域请求的方法
Access-Control-Allow-Headers: X-Custom-Header  // 服务器支持的所有头信息字段
Access-Control-Allow-Credentials: true   // 表示是否允许发送Cookie
Access-Control-Max-Age: 1728000  // 用来指定本次预检请求的有效期,单位为秒

(2)JSONP

jsonp的原理就是利用<script>标签没有跨域限制,通过<script>标签src属性,发送带有callback参数的GET请求,服务端将接口返回数据拼凑到callback函数中,返回给浏览器,浏览器解析执行,从而前端拿到callback函数返回的数据。

1)原生JS实现:

<script>
    var script = document.createElement('script');
    script.type = 'text/javascript';
    // 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
    script.src = 'http://www.domain2.com:8080/login?user=admin&callback=handleCallback';
    document.head.appendChild(script);
    // 回调执行函数
    function handleCallback(res) {
        alert(JSON.stringify(res));
    }
 </script>

服务端返回如下(返回时即执行全局函数):

handleCallback({"success": true, "user": "admin"})

2)Vue axios实现:

this.$http = axios;
this.$http.jsonp('http://www.domain2.com:8080/login', {
    params: {},
    jsonp: 'handleCallback'
}).then((res) => {
    console.log(res); 
})

后端node.js代码:

var querystring = require('querystring');
var http = require('http');
var server = http.createServer();
server.on('request', function(req, res) {
    var params = querystring.parse(req.url.split('?')[1]);
    var fn = params.callback;
    // jsonp返回设置
    res.writeHead(200, { 'Content-Type': 'text/javascript' });
    res.write(fn + '(' + JSON.stringify(params) + ')');
    res.end();
});
server.listen('8080');
console.log('Server is running at port 8080...');

JSONP的缺点:

  • 具有局限性, 仅支持get方法
  • 不安全,可能会遭受XSS攻击

(3)postMessage 跨域

postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:

  • 页面和其打开的新窗口的数据传递
  • 多窗口之间消息传递
  • 页面与嵌套的iframe消息传递
  • 上面三个场景的跨域数据传递

用法:postMessage(data,origin)方法接受两个参数:

  • data: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。
  • origin: 协议+主机+端口号,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。

(4)nginx代理跨域

(5)nodejs 中间件代理跨域

(6)WebSocket协议跨域

WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。

原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。

九、权限管理的实现

权限管理我分成了两个部分、一个权限列表、一个是角色列表

  • 权限列表(所有菜单列表) 权限列表展示的是项目所有功能菜单、字段包含菜单名称、路径、菜单等级、菜单之间的依附关系(简单来说就是一个树结构以列表形式展示),我们可以对里面菜单进行增、删、改。

路径:是用来跳转哪个前端路由里面的页面

  • 角色列表 角色列表里面包含了每个角色的角色名称、角色描述、以及分配权限按钮

点击分配权限,会展示所有菜单的复选框、点击你想分配的权限

用户登录时、根据该用户登录返回的用户名称、用户对应角色去找他的权限、后台会返回一个树结构的用户对应的菜单(这也就是他的一个权限)这样每个用户进来的页面就会有所不同。

十、get和post区别

十一、压缩文件是怎么实现的

十二、有部署到服务器端吗?

十三、项目build的时候就会压缩、那么你为什么还要进行压缩呢

使用gzip可以减小文件体积,使传输速率更快

可以通过服务端使用Express做gzip压缩,配置如下

//安装相应的包
npm install compression -D
//导入包
const compression=require('compression')
//启动中间件
app.use(compression())

image.png

文件大小为74kb,但是传输过程中进行了压缩,变成了24k(减少下载流量)

十四、垂直布局

1.flex

2.绝对定位

十五、父容积高度塌陷、如何处理(待会查一下)

伪类去清除浮动

十六、BFC是什么?

BFC是一个独立的布局环境,可以理解为一个容器,在这个容器中按照一定规则进行物品摆放,并且不会影响其它环境中的物品。如果一个元素符合触发BFC的条件,则BFC中的元素布局不受外部影响。

十七、js里面有哪些数据类型

十八、js里面有哪些作用域?

全局作用域 函数作用域 块级作用域

十九、可以通过什么改变this的指向

bind call apply (apply第二个参数必须是数组)

二十、es6里面你用过哪些新特性

let、const

扩展运算符

二十一、字符串可以用扩展用算符吗?

可以使用

补充:扩展运算符的用法

  • 对象的扩展运算符(...)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中(相当于Object.assign()属于浅拷贝)

  • 将数组转换为参数序列

  • 复制数组

  • 合并数组

  • *需要注意:如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。

const [...rest, last] = [1, 2, 3, 4, 5];         // 报错
const [first, ...rest, last] = [1, 2, 3, 4, 5];  // 报错
  • 将字符串转为真正的数组
[...'hello']    // [ "h", "e", "l", "l", "o" ]
  • 任何 Iterator 接口的对象,都可以用扩展运算符转为真正的数组

比较常见的应用是可以将某些数据结构转为数组:

// arguments对象
function foo() {
  const args = [...arguments];
}
  • 使用Math函数获取数组中特定的值
const numbers = [9, 4, 7, 1];
Math.min(...numbers); // 1
Math.max(...numbers); // 9

二十二、说一下什么事promise链式调用

Promise是异步编程的一种解决方案,它是一个对象,可以获取异步操作的消息,他的出现大大改善了异步编程的困境,避免了地狱回调,它比传统的解决方案回调函数和事件更合理和更强大。

Promise的特点:

  • 对象的状态不受外界影响

  • 一旦状态改变就不会再变,任何时候都可以得到这个结果。

Promise的缺点:

  • 无法取消Promise,一旦新建它就会立即执行,无法中途取消。
  • 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
  • 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

二十三、promise异常怎么捕获

catch去捕获异常

二十四、那么catch之后再catch一次可以捕获到异常吗?

Promise.reject(
    new Error("我错了,请原谅俺!!")
    ).catch((e)=>{
        console.log(e)
    }).catch((e)=>{
        console.log(e)
})

不可以再次捕获

promise有哪些常用方法

then()、catch()、all()、race()、finally

  • all()

all方法可以完成并行任务, 它接收一个数组,数组的每一项都是一个promise对象。当数组中所有的promise的状态都达到resolved的时候,all方法的状态就会变成resolved,如果有一个状态变成了rejected,那么all方法的状态就会变成rejected

  • race()

race方法和all一样,接受的参数是一个每项都是promise的数组,但是与all不同的是,当最先执行完的事件执行完之后,就直接返回该promise对象的值。如果第一个promise对象状态变成resolved,那自身的状态变成了resolved;反之第一个promise变成rejected,那自身状态就会变成rejected

那么race方法有什么实际作用呢?当要做一件事,超过多长时间就不做了,可以用这个方法来解决:

Promise.race([promise1,timeOutPromise(5000)]).then(res=>{})
  • finally()

finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。

promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});

二十五、 async和await异常怎么捕获

async function fn(){
    try{
        let a = await Promise.reject('error')
    }catch(error){
        console.log(error)
    }
}

二十六、vue-cli脚手架

二十七、webpack怎么样(待会总结)

1.启动打包项目

npm怎么装包吗?

【开发环境】:指的是你的项目尚且在编码阶段时的环境。你在代码可能还有各种console.log()、注释、格式化等。

【生产环境】:指的是你的项目已经完成编码,并发布上线可供用户浏览的阶段时的环境。代码可能经过了压缩、优化等处理

生产依赖和开发依赖有什么区别吗?

生产依赖 dependencies

npm i package-name --save 或 npm i package-name -S

开发依赖 devDependencies

npm i package-name --save-dev 或 npm i package-name -D

二十八、如何发布你自己写的npm的包?

二十九、vue双向绑定的原理?

三十、有了解ts吗?

三十一、html5里面有哪些新的特性?

1.语义化标签

2.音视频标签

3.canvas

4.svg

5.拖拽的api

三十二、原型链

三十三、如何获取一个对象的原型

obj.proto

obj.prototype

三十四、git指令

三十五、如何求一个数的阶层(123...i)

1.for循环

2.递归(跳出循环条件是什么i=1时)

三十六、axios如何发送post请求

三十七、axios设置请求头

三十八、sql会写吗?