前端面试资料
Author: 刘建(Abbott Liu)
Create::2022/03/20
Update:2022/03/30
如果觉得不错,麻烦关注下我
技术能力考核
原生JavaScript
JavaScript 数据类型
JavaScript中有几种简单数据类型(也称为基本数据类型):Number、Undefined、Null、String和Boolean。还要一种复杂类型——Object,Object本质是一组无序的名值对组成。JavaScript中不支持任何创建自定义的类型的机制,而所有值都是这6种数据类型之一。
值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。
引用数据类型(对象类型):对象(Object)、数组(Array)、函数(Function),还有两个特殊的对象:正则(RegExp)和日期(Date)。
注:ES5中有5种基本数据类型,Symbol 是 ES6 引入了一种新的原始数据类型,表示独一无二的值。
判断Object和Array
使用instanceof
let o = new Object();
let a = new Array();
console.log(o instanceof Array);
console.log(a instanceof Array);
使用Array.isArray
console.log(Array.isArray(a))
行内元素有哪些?块级元素有哪些? 空(void)元素有那些?
行内元素:a、b、span、img、input、strong、select、label、em、button、textarea
块级元素:div、ul、li、dl、dt、dd、p、h1-h6、blockquote
空元素:即系没有内容的HTML元素,例如:br、meta、hr、link、input、img
什么是MVVM
MVVM(Model-View-ViewModel)是一种软件架构设计模式,它是一种简化用户界面的事件驱动编程方式。
去掉字符串的前后空格
function trimString(str) {
var regSpace = /^(\s*)|(\s*)$/ig;
if(str !== null && str !== undefined) {
return str.replace(regSpace, '')
} else {
return str
}
}
let valueTest = " AbbottLiu "
console.log(valueTest)
console.log(valueTest.length)
console.log(trimString(valueTest, ""))
console.log(trimString(valueTest, "").length)
生成一定范围内随机数
function createRandomNum(minVal, maxVal) {
var result = null
switch(arguments.length) {
case 1:
result = parseInt(Math.random()*minVal+1,10);
break;
case 2:
result = Math.floor(Math.random() * (maxVal - minVal + 1)) + minVal
break;
default:
break;
}
return result;
}
for(var i = 0; i<10; i++) {
console.log(createRandomNum(2));
}
防抖和节流
函数防抖(debounce):触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。
Title
点击
函数节流(throttle):高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率。
Title
点击
总结:
函数防抖:将多次操作合并为一次操作进行。原理是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。
函数节流:使得一定时间内只触发一次函数。原理是通过判断是否有延迟调用函数未执行。
区别: 函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。 比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现。
cookies,sessionStorage和localStorage的区别
三者之间的区别对比
分类 | Cookie | localStorage | sessionStorage |
---|---|---|---|
特性 | 一般由服务器生成,可设置失效时间。如果在浏览器端生成Cookie,默认是关闭浏览器后失效 | 除非被清除,否则永久保存 | 仅在当前会话下有效,关闭页面或浏览器后被清除 |
4K左右 | 一般为5MB | ||
与服务器端通信 | 每次会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题 | 仅在客户端(即浏览器)中保存,不参与和服务器的通信 | |
易用性 | 需要程序员自己封装,源生的Cookie接口不友好 | 源生接口可以接受,亦可再次封装来对Object和Array有更好的支持 |
Get和Post
分类 | GET | POST |
---|---|---|
后退按钮/刷新 | 无害 | 数据会被重新提交(浏览器应该告知用户数据会被重新提交) |
书签 | 可收藏为书签 | 不可收藏为书签 |
缓存 | 能被缓存 | 不能缓存 |
编码类型 | application/x-www-form-urlencoded | application/x-www-form-urlencoded 或 multipart/form-data。为二进制数据使用多重编码。 |
历史 | 参数保留在浏览器历史中 | 参数不会保存在浏览器历史中 |
对数据长度的限制 | 是的。当发送数据时,GET 方法向 URL 添加数据;URL 的长度是受限制的(URL 的最大长度是 2048 个字符) | 无限制。 |
对数据类型的限制 | 只允许 ASCII 字符 | 没有限制。也允许二进制数据 |
安全性 | 与 POST 相比,GET 的安全性较差,因为所发送的数据是 URL 的一部分。在发送密码或其他敏感信息时绝不要使用 GET ! | POST 比 GET 更安全,因为参数不会被保存在浏览器历史或 web 服务器日志中。 |
可见性 | 数据在 URL 中对所有人都是可见的。 | 数据不会显示在 URL 中。 |
它们的本质都是 TCP 链接,并无区别。但是由于 HTTP 的规定以及浏览器/服务器的限制,导致它们在应用过程中可能会有所不同。
TCP和UDP的比较
分类 | GET | POST |
---|---|---|
后退按钮/刷新 | 无害 | 数据会被重新提交(浏览器应该告知用户数据会被重新提交) |
书签 | 可收藏为书签 | 不可收藏为书签 |
TCP三次握手
注意,连接的建立与结束都是 客户端 发起的。
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
TCP为什么是三次握手,为什么不是两次或者四次
这是一个很有意思的问题~
首先,我们要知道TCP是全双工的,即客户端在给服务器端发送信息的同时,服务器端也可以给客户端发送信息。而半双工的意思是A可以给B发,B也可以给A发,但是A在给B发的时候,B不能给A发,即不同时,为半双工。 单工为只能A给B发,B不能给A发; 或者是只能B给A发,不能A给B发。
我们假设A和B是通信的双方。我理解的握手实际上就是通信,发一次信息就是进行一次握手。
第一次握手: A给B打电话说,你可以听到我说话吗?
第二次握手: B收到了A的信息,然后对A说: 我可以听得到你说话啊,你能听得到我说话吗?
第三次握手: A收到了B的信息,然后说可以的,我要给你发信息啦!
在三次握手之后,A和B都能确定这么一件事: 我说的话,你能听到; 你说的话,我也能听到。 这样,就可以开始正常通信了。
注意: HTTP是基于TCP协议的,所以每次都是客户端发送请求,服务器应答,但是TCP还可以给其他应用层提供服务,即可能A、B在建立链接之后,谁都可能先开始通信。
如果两次,那么B无法确定B的信息A是否能收到,所以如果B先说话,可能后面的A都收不到,会出现问题 。
如果四次,那么就造成了浪费,因为在三次结束之后,就已经可以保证A可以给B发信息,A可以收到B的信息; B可以给A发信息,B可以收到A的信息。
AMD和CMD的区别
AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。
CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。
区别
- 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible。
- AMD 推崇依赖前置,CMD 推崇依赖就近。
- AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。比如 AMD 里,require 分全局 require 和局部 require,都叫 require。CMD 里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。CMD 里,每个 API 都简单纯粹。
WebSocket的定义
//申请一个WebSocket对象,参数是服务端地址,
var ws = new WebSocket("ws://localhost:8080");
ws.onopen = function() {
//当WebSocket创建成功时,触发onopen事件
console.log("open");
ws.send("hello"); //将消息发送到服务端
}
//当客户端收到服务端发来的消息时,触发onmessage事件,参数e.data包含server传递过来的数据
ws.onmessage = function(e) {
console.log(e.data);
}
//当客户端收到服务端发送的关闭连接请求时,触发onclose事件
ws.onclose = function(e) {
console.log("close");
}
//如果出现连接、处理、接收、发送数据失败的时候触发onerror事件
ws.onerror = function(e) {
console.log(error);
}
弹性盒子flexbox常用的容器属性与项目属性
介绍
CSS 弹性盒子布局是 CSS 的模块之一,定义了一种针对用户界面设计而优化的 CSS 盒子模型。在弹性布局模型中,弹性容器的子元素可以在任何方向上排布,也可以“弹性伸缩”其尺寸,既可以增加尺寸以填满未使用的空间,也可以收缩尺寸以避免父元素溢出。子元素的水平对齐和垂直对齐都能很方便的进行操控。通过嵌套这些框(水平框在垂直框内,或垂直框在水平框内)可以在两个维度上构建布局。
术语
- 容器:具有
display: flex
属性元素,任何元素都可以通过添加display:flex;属性,转换为弹性盒元素,转换为 flex 元素后,它的内部的“子元素”就支持 flex 布局了。 - 项目:flex 容器的”子元素”,容器中的项目自动转为行内块元素,不管之前是什么类型。
- 主轴:项目排列的轴线,一般默认情况下主轴为水平方向。
- 交叉轴:与主轴垂直的轴线,一般默认情况下,交叉轴为竖直方向。
容器属性
属性 | 描述 |
---|---|
flex-flow | 主轴方向与换行方式 |
justify-content | 项目在主轴上的对齐方式 |
align-items | 项目在交叉轴上的对齐方式 |
align-content | 项目在多行容器中的对齐方式 |
项目属性
属性 | 描述 |
---|---|
flex | 项目的缩放比例与基准宽度 |
align-self | 单个项目在交叉轴上的对齐方式 |
order | 项目在主轴上排列顺序 |
使用flex布局绘制样式
html文件
1
2
css文件
.t1 {
display: flex;
width: 500px;
height: 300px;
background: #00ee00;
align-items: center;
box-sizing: border-box;
justify-content: space-between;
padding: 20px;
}
.t11 {
width: 150px;
height: 100px;
background: #2c009f;
align-self: flex-end;
}
.t12 {
width: 150px;
height: 100px;
background: #00A0E9;
align-self: flex-start;
}
斐波那契数列
什么是斐波那契数列:斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、55、……在数学上,斐波纳契数列以如下被以递归的方法定义:F(0)=1,F(1)=1, F(n)=F(n-1)+F(n-2)(n>2,n∈N*)
function Fibonacci(n) {
if(n<=1) { return 1 };
return Fibonacci(n-1)+ Fibonacci(n-2)
}
console.log(Fibonacci(9));
清除浏览器缓存的几种方法
说了这么多 mate 兼容性不靠谱!所以说基本没用
ES6
Promise理解
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
const p = new Promise((resolve, reject)=>{
var a = 20
if(a > 10) {
reject(10)
} else {
resolve(5)
}
})
p.then((data)=>{
console.log('success == ', data);
}).catch((err)=>{
console.log('err == ', err);
})
Vue
Vue 生命周期
双向数据绑定原理
Vue是一个MVVM框架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。这也算是vue的精髓之处了。值得注意的是,我们所说的数据双向绑定,一定是对于UI控件来说的,非UI控件不会涉及到数据双向绑定。 单向数据绑定是使用状态管理工具(如Redux)的前提。
例子
defineProperty
输入:
watched 和 computed 区别
计算属性computed
- 支持缓存,只有依赖数据发生改变,才会重新进行计算
- 不支持异步,当computed内有异步操作时无效,无法监听数据的变化
- computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值
- 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed
- 如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。
{fullName}}
侦听属性watch
- 不支持缓存,数据变,直接会触发相应的操作。
- watch支持异步;监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
- 当一个属性发生变化时,需要执行对应的操作;一对多;
- 监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数
var vm = new Vue({
el: '#app',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
项目所遇到的问题
登录验证码图片显示
后台返回的登录验证码图片是以流的形式返回的。所以这里需要使用到Uint8Array和String.fromCharCode这2个api。Uint8Array表示一个8位无符号整型数组,用来存储返回来的流。String.fromCharCode()根据指定的 Unicode 编码中的序号值来返回一个字符串。这里我是使用axios进行请求的,同是需要指定返回的类型是arraybuffer,代码如下:
SSO单点登录
SSO(Single Sign On)是在一个多系统共存的环境下,用户在一处登录之后,就不用在其他的系统中登录,也就是用户的一次登录能得到其他所有系统的信任。单点登录在大型网站里面使用的比较多,例如像阿里巴巴这样的网站,在万丈的背后是成百上千的子系统,用户一次操作或交易可能涉及到几个十几个子系统的协作,如果每个子系统都需要用户认证,会在无形中增加时间的耗费。实现单点登录说到底就是要解决如何产生和存储那个信任,再就是其他子系统如何验证这个信任的有效性,因此要一下两个点:
秒杀系统前端优化
1、为什么需要前端优化?
在一个网站中,大部分的服务器请求带宽资源都被静态资源占用了,静态资源包含(CSS/IMG/JS/MP4)等,而HTTP协议接口占用带宽资源非常小,比如:
1M宽带等于等于128KB/S ,如果加载一个网页含静态资源需要640/KB ,那么就需要5秒时间加载整个网页。
想让用户的请求及时的发送到服务器端上,服务器带宽一定足够,所以这时候网站一定要实现动静分离架构模式,将静态资源与动态资源分开,静态资源放入到CDN服务器端上。
2、前端优化方案
前端的优化方案具体指的是静态资源优化方案,方式有如下几种:
- js/css/img实现压缩减少带宽的传输、将静态资源放入第三方资源服务器中(例如七牛云、阿里OSS等)。
- 商品详情页面使用Nginx+Lua+OpenResty实现商品详情页面的优化。
- 提交后按钮disabled,禁止用户重复提交。
3、Nginx实现页面缓存
1、nginx配置文件内容如下(nginx端口为7788,系统门户端口为8080)
events {
#的最大连接数(包含所有连接数)1024
worker_connections 1024; ## Default: 1024
}
http{
# 代理缓存配置
proxy_cache_path "./taodong_cachedata" levels=1:2 keys_zone=taodongcache:256m inactive=1d max_size=1000g;
server {
listen 7788;
location /{
#使用缓存名称
proxy_cache taodongcache;
#对以下状态码实现缓存
proxy_cache_valid 200 206 304 301 302 1d;
#缓存的key
proxy_cache_key $request_uri;
add_header X-Cache-Status $upstream_cache_status;
#反向代理地址
proxy_pass http://127.0.0.1:8080;
}
}
}
2.配置文件下新建文件夹:
mkdir taodong_cachedata
3.浏览器使用Nginx访问:http://127.0.0.1:7788/login,可以看到访问正常,Nginx反向代理到了门户系统)
Vue
页面卡顿问题
setInterval路由跳转继续运行并没有及时进行销毁
比如一些弹幕,走马灯文字,这类需要定时调用的,路由跳转之后,因为组件已经销毁了,但是setInterval还没有销毁,还在继续后台调用,控制台会不断报错,如果运算量大的话,无法及时清除,会导致严重的页面卡顿。
解决方案:在组件生命周期beforeDestroy停止setInterval
beforeDestory() {
clearInterval(this.timer);
MessageBox.close()
}
上传图片无效
某些时候,商家上传图片以后,某些图片上传没有成功。
因为在上传后,使用了定时器来跳转,没有判断全部图片是否都上传成功了。