沐光

记录在前端之路的点点滴滴

前端面试题大全

前言

临近春节,很多人又考虑换工作了,考虑到还有一年多的工作的时间,提前总结总结也是不错的,这里就记录一下最近翻到了以及先前自己总结的一些问题,为之后的复习做准备。

HTML 篇

H5 有哪些新特性

  • 语义化标签(header、footer、nav、aside、article、section 等)
  • 增强表单(传送门
  • 本地存储
  • 多媒体元素标签: vedio 与 audio
  • 新增地理定位方法
  • canvas 画布
  • 拖放事件
  • webWorker
  • webSocket
特性 cookie localStorage sessionStorage
数据生命周期 一般由服务器生成,可以设置过期时间 除非被清理,否则一直存在 页面关闭就清理
数据存储大小 4K 5M 5M
与服务端通信 每次都会携带在 header 中,对于请求性能影响 不参与 不参与

从上表可以看到,cookie 已经不建议用于存储。如果没有大量数据存储需求的话,可以使用 localStorage 和 sessionStorage 。对于不怎么改变的数据尽量使用 localStorage 存储,否则可以用 sessionStorage 存储。

svg 与 canvas

svg canvas
svg 是一种使用 xml 描述 2D 图形的语言,矢量图 canvas 通过 javascript 来绘制 2D 图形,标量图
svg 基于 xml,这意味着 svg DOM 中的每个元素都是可用的,您可以为某个元素附加 javascript 事件处理器 canvas 是逐像素进行渲染的。在 canvas 中,一旦图形被绘制完成,它就不会继续得到浏览器的关注。如果其位置发生变化,那么整个场景也需要重新绘制,包括任何或许已被图形覆盖的对象

移动端页面适配方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script>
// 获取缩放大小
var scale = 1 / window.devicePixelRatio;
// content 配置默认缩放大小,不允许缩放
var content =
'width=device-width,initial-scale=' +
scale +
', maximum-scale=' +
scale +
', minimum-scale=' +
scale +
', user-scalable=no';
// 动态 meta 标签适配
document
.querySelector('meta[name="viewport"]')
.setAttribute('content', content);
// 基准 font-size 设置
document.documentElement.style.fontSize =
document.documentElement.clientWidth / 75 + 'px';
</script>

CSS 篇

CSS3 的新特性

  • transition(过渡动画)、animation(贞动画)、transform(形状变化)
  • 新增选择器(伪类选择器、相邻选择器等)
  • 边框、阴影、滤镜等
  • 弹性布局、栅格布局

推荐阅读

position 默认值以及默认基于什么定位

默认值为:static;

定位是基于最近的且 position 值为非 static 的父元素;

水平垂直居中有哪些方法。(至少 3 种)

  • translate 方法
  • position + margin 定位
  • flex 布局
  • table-ceil 方法
  • padding 实现

清除浮动有哪些方式。

  • after 伪类(IE 需要设置 zoom: 1)
  • 空 div 元素,设置 css : clear: both
  • 父级形成 BFC 结构,如: overflow: hidden

BFC 的相关知识考察

BFC 提供了一个环境,在这个环境中按照一定规则进行布局不会影响到其它环境中的布局。

常见问题:

  • 高度塌陷
  • 外边距折叠

实现方式:

  • 浮动元素,float 除 none 以外的值
  • 绝对定位元素,position(absolute,fixed)
  • display 为以下其中之一的值 inline-block,table-cells,table-captions
  • overflow 除了 visible 以外的值(hidden,auto,scroll)
  • ……

参考文章: 浅谈 BFC

CSS 选择器

实现以下字体样式效果

1
2
3
4
5
6
7
8
9
10
11
12
13
<div>
<p><!-- 红 --></p>
<p><!-- 白 --></p>
<p><!-- 红 --></p>
<p><!-- 白 --></p>
<!-- ... n 个 p -->
<p class="center"><!-- 黄 --></p>
<p><!-- 蓝 --></p>
<p><!-- 蓝 --></p>
<p><!-- 蓝 --></p>
<!-- ... n 个 p -->
<p><!-- 绿 --></p>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
div {
background-color: black;
}

p {
&:nth-child(2n) {
color: white;
}
&:nth-child(2n + 1) {
color: red;
}
&.center {
color: yellow;
}
// 此处得考虑优先级问题
&.center ~ p:not(:last-child) {
color: blue;
}
&:last-child {
color: green;
}
}

JavaScript 篇

ES6+ 有哪些新特性

  • let, const 变量
  • 模板字符串 “`”
  • 解构赋值 与 扩展运算符(... 运算符)
  • Promise 与 async
  • Map、Set
  • class
  • Array 的一些原生方法
  • 箭头函数、默认值

let 与闭包、解构 undefined 和 null 的值时的默认值问题、class 与原型链、Set 与 除重方法等等

Promise.all() 的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function PromiseAll(promiseArr) {
if (!Array.isArray(promiseArr)) {
throw new TypeError('You must pass an array');
}

const arrayLen = promiseArr.length;
const resolvedArr = [];
let pos = 0;

return new Promise((resolve, reject) => {
promiseArr.forEach(item => {
Promise.resolve(item)
.then(res => {
resolvedArr.push(res);
pos++;
if (pos === arrayLen) {
resolve(resolvedArr);
}
})
.catch(e => {
reject(e);
});
})
});
}

数组去括号并去重

1
2
// 试题
let originArr = [1, 2, [2, 3], 3, [2, [3, 0]], 4, [[[5]]]]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 实现的方法:
function formatArr(originArr) {
function flattenDeep(arr) {
let resArr = [];
if (Array.isArray(arr)) {
resArr = arr.reduce((a,b)=>[...a, ...flattenDeep(b)], resArr);
} else {
resArr.push(arr);
}
return resArr;
}
const flatArr = flattenDeep(originArr);
return [...new Set(flatArr)];
}

const testArr = [1, [[2], [3, [4, 5]], 5]];
console.log(formatArr(testArr));
1
2
3
4
5
6
// 简单方法
function formatArr(originArr) {
const flatArr = originArr.toString().split(',');
const filteredArr = [...new Set(flatArr)];
return filteredArr.map(n => Number(n));
}

This 指向问题

1
2
3
4
5
6
7
8
9
let obj = {
b: 1,
a: () => {
console.log(this.b)
}
}

obj.a()
// 输出 undefined

参考文章: 深入了解 this

以下代码依次输出的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
async function async1() {
console.log('as1')
await async2()
console.log('end as1')
}

async function async2() {
console.log('as2')
}

console.log('start')

async1(1)

setTimeout(() => {
console.log('setTimeout')
})

new Promise((rs, rj) => {
console.log('promise')
rs()
}).then(() => {
console.log('then')
})

console.log('end')
1
2
3
4
5
6
7
8
start
as1
as2
promise
end
end as1
then
setTimeout

HTTP 篇

常用的 HTTP 方法有哪些

  • GET:用于请求访问已经被 URI 识别的资源,可以通过 URL 传参给服务器
  • POST:用于传输信息给服务器,主要功能 GET 类似,但一般推荐使用 POST 方式
  • PUT:传输文件,报文主体中包含文件内容,保存到对应的 URI 位置
  • HEAD:获得报文首部,与 GET 方法类似,只是不返回报文主体,一般用于验证 URI 是否有效
  • DELETE:删除文件,与 PUT 方法相反,删除对应 URI 位置的文件
  • OPTIONS:查询对应 URI 支持的 HTTP 方法

GET 和 POST 的区别

  • GET 重点从服务器上获取资源,POST 重点向服务器发送数据
  • GET 传输的数据量小,因为受 URL 长度限制,但效率较高;POST 可以传输大量数据,所以上传文件时只能用 POST 方式;
  • GET 是不安全的,因为 URL 是可见的,可能会泄露私密信息,如密码等;
    POST 较 GET 安全性较高;

请求报文和响应报文

a. 请求报文包含三部分:

  • 请求行:包含请求方法、URI、HTTP 版本信息
  • 请求首部字段
  • 请求内容实体

b. 响应报文包含三部分:

  • 状态行:包含 HTTP 版本、状态码、状态码的原因短语
  • 响应首部字段
  • 响应内容实体

常见的状态码

  • 200:表示请求已成功,请求所希望的响应头或数据体将随此响应返回。
  • 301:永久重定向,资源已永久分配新 URI。
  • 302:临时重定向,资源已临时分配新 URI。
  • 304:自从上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容。
  • 307:临时重定向,POST 不会变成 GET。
  • 401:需要通过 HTTP 认证,或认证失败。
  • 403:表示对请求资源的访问被服务器拒绝了。
  • 404:表示服务器找不到你请求的资源。
  • 500:表示服务器执行请求的时候出错了。
  • 503:表示服务器超负载或正停机维护,无法处理请求。

强缓存和协商缓存

a. 强缓存相关的字段:

  • expires
  • cache-control:max-age=number

b. 协商缓存相关的字段:

  • Last-Modified/If-Modified-Since
  • Etag/If-None-Match

性能优化

HTML

  • 不要使用空 src 的 image 标签
  • 减少 iframe 的数量,其开销高,会阻塞 onload 事件,同域会抢资源
  • 减少不必要的 DOM 元素
  • 图片懒加载
  • 使用 CDN 的资源
  • css 样式放在顶部 header,js 放在 body 最后面

CSS

  • 能使用 base64 的尽量使用 base64
  • 背景图加载
  • 尽量不使用 @import 语法

JavaScript

  • 减少 DOM 访问
  • 多次修改统一节点时使用 documentFragment 文档片段来做中间拼接处理
  • 减少获取 clientHeight 等信息的次数,会造成反复重绘
  • 合理添加事件监听函数

其它

短链接的生成思路

一般链接的特点:不考虑 query 字段,一般就只有 26 个英文字母,而短链接的特点是含有 ([a-z][a-z][0-9]),因此一个粗略的想法就是将 26 进制转化成 62 进制,因此将对应算法写出来基本上就算是答道点子上了。

算法的大致思路为: 26 进制 -> 10 进制 -> 62 进制

参考文档