前端常见面试题归纳和总结

HTML&CSS

浏览器内核

常用五大浏览器及其内核

浏览器 内核
Google Chrome Blink引擎
Mozilla Firefox Gecko引擎
Apple Safari Webkit引擎
Microsoft Edge Blink引擎
Opera Blink引擎
IE(已被历史所淘汰) Trident(俗称IE内核)

盒模型、flex布局、两/三栏布局、水平/垂直居中;

BFC、清除浮动;

css3动画、H5新特性。

JavaScript

开始之前我们先来看一道面试题,请回答一下打印的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
async function test() {
debugger
setTimeout(() => {
console.log(1)
}, 0)
await Promise.resolve().then(() => console.log(2))
new Promise((resolve) => {
console.log(3)
for (var i = 0; i < 10000; i++) {
i == 9999 && resolve()
}
console.log(4);
}).then(function () {
console.log(5)
})
await new Promise(() => console.log(6)).then(() => console.log(7))
console.log(8);
}
test()

答案是: 2 3 4 6 5 1 想一下为什么会得到这样的结果吧!

继承、原型链、this指向、设计模式、call, apply, bind;

继承与原型链

当谈到继承时,JavaScript 只有一种结构:对象。每个实例对象(object)都有一个私有属性(称之为 __proto__)指向它的构造函数的原型对象(prototype)。该原型对象也有一个自己的原型对象(__proto__),层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。

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
27
28
29
30
31
32
// 让我们创建一个函数 f,它自身拥有属性 a 和 b
function f() {
this.a = 1;
this.b = 2;
}
// 实例化 f 并赋给 o
let o = new f(); // 打印o输出 {a: 1, b: 2}
// 在 f 函数的原型上定义属性
f.prototype.b = 3;
f.prototype.c = 4;
// 注:不要在 f 函数的原型上直接定义 f.prototype = {b:3,c:4};这样会直接打破原型链
// 打印o会看到
{
a: 1
b: 2
[[Prototype]]: Object
b: 3
c: 4
constructor: ƒ f()
[[Prototype]]: Object
}
// 可以看到 o.[[Prototype]] 中有属性 b 和 c,其实也就等同于 o.__proto__ 或者 o.constructor.prototype
// 最后 o.[[Prototype]].[[Prototype]].[[Prototype]] 是 null
// null 是原型链的末尾,也就是这个原型链中的最后一个环节,根据定义,null 就是没有 [[Prototype]]。
// 综上,整个原型链如下:
// {a:1, b:2} ---> {b:3, c:4} ---> Object.prototype---> null
console.log(o.a, o.b); // 1, 2
// a 和 b 都是 o 的自身属性,而原型上也有一个'b'属性,但是它不会被访问到。这种情况被称为 "属性遮蔽 (property shadowing)"
console.log(o.c); // 4
// c 并非 o 的自身属性,而是 o.[[Prototype]] 上的属性
console.log(o.d); // undefined
// 可知 d 既不是 o 的自身属性也不是 o.[[Prototype]] 的属性,o.[[Prototype]].[[Prototype]] 为 null,原型上也没有 d 属性,即返回 undefined

继承方法,当继承的函数被调用时,this 指向的是当前继承的对象,而不是继承的函数所在的原型对象。

1
2
3
4
5
6
7
8
9
10
11
var o = {
a: 2,
m: function(){
return this.a + 1;
}
};
console.log(o.m()); // 3,当调用 o.m 时,'this' 指向了 o.
var p = Object.create(o); // p 是一个继承自 o 的对象
p.a = 4; // 创建 p 的自身属性 'a'
console.log(p.m()); // 5
// 调用 p.m 时,'this' 指向了 p,又因为 p 继承了 o 的 m 函数,所以,此时的 'this.a' 即 p.a,就是 p 的自身属性 'a'

this指向

new实现、防抖节流、let, var, const 区别、暂时性死区、event、loop;

new的时候都做了什么

new 关键字会进行如下的操作:
1、创建一个空的简单 JavaScript 对象(即 {});
2、为步骤 1 新创建的对象添加属性 __proto__,将该属性链接至构造函数的原型对象;
3、将步骤 1 新创建的对象作为 this 的上下文;
4、如果该函数没有返回对象,则返回 this。

promise使用及实现、promise并行执行和顺序执行;

Promise 一共有三种状态,而其必然处于以下三种状态之一:
待定(pending),初始状态,既没有被兑现,也没有被拒绝;
已兑现(fulfilled),意味着操作成功完成;
已拒绝(rejected),意味着操作失败。

传递到 then() 中的函数被置入到一个微任务队列中,而不是立即执行,这意味着它是在 JavaScript 事件队列的所有运行时结束了,且事件队列被清空之后,才开始执行:

1
2
3
4
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
wait().then(() => console.log(4));
Promise.resolve().then(() => console.log(2)).then(() => console.log(3));
console.log(1); // 1, 2, 3, 4

async/await的优缺点;

闭包、垃圾回收和内存泄漏、数组方法、数组乱序, 数组扁平化、事件委托、事件监听、事件模型

网络

HTTP1, HTTP2, HTTPS、常见的http状态码;

浏览从输入网址到回车发生了什么;

前端安全(CSRF、XSS)

前端跨域、浏览器缓存、cookie, session, token, localstorage, sessionstorage;

TCP连接(三次握手, 四次挥手)

性能相关

图片优化的方式

500 张图片,如何实现预加载优化

懒加载具体实现

减少http请求的方式

webpack如何配置大型项目

参考文章

继承与原型链