Web开发的一些面试题

这次记一些面试题总结,给自己用。


一、Vue and React

1、Vue底层原理

基于MVVM设计,双向绑定:发布者-订阅者模式,Object.defineProperty()数据劫持。
https://www.jianshu.com/p/5990a386132a

2、webpack一些配置,删除无用代码原理,chunk如何加载,摇树,runtime

通过分析静态的ES模块,来剔除未使用代码的。

webpack –config webpack.config.js

chunk动态加载:https://www.cnblogs.com/dahe1989/p/11543832.html

webpack打包去除无用代码:https://www.cnblogs.com/maycpou/p/14560116.html

3、手写promise

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
class WPromise {
static pending = 'pending';
static fulfilled = 'fulfilled';
static rejected = 'rejected';

constructor(executor) {
this.status = WPromise.pending; // 初始化状态为pending
this.value = undefined; // 存储 this._resolve 即操作成功 返回的值
this.reason = undefined; // 存储 this._reject 即操作失败 返回的值
// 存储then中传入的参数
// 至于为什么是数组呢?因为同一个Promise的then方法可以调用多次
this.callbacks = [];
executor(this._resolve.bind(this), this._reject.bind(this));
}

// onFulfilled 是成功时执行的函数
// onRejected 是失败时执行的函数
then(onFulfilled, onRejected) {
// 返回一个新的Promise
return new WPromise((nextResolve, nextReject) => {
// 这里之所以把下一个Promsie的resolve函数和reject函数也存在callback中
// 是为了将onFulfilled的执行结果通过nextResolve传入到下一个Promise作为它的value值
this._handler({
nextResolve,
nextReject,
onFulfilled,
onRejected
});
});
}

_resolve(value) {
// 处理onFulfilled执行结果是一个Promise时的情况
// 这里可能理解起来有点困难
// 当value instanof WPromise时,说明当前Promise肯定不会是第一个Promise
// 而是后续then方法返回的Promise(第二个Promise)
// 我们要获取的是value中的value值(有点绕,value是个promise时,那么内部存有个value的变量)
// 怎样将value的value值获取到呢,可以将传递一个函数作为value.then的onFulfilled参数
// 那么在value的内部则会执行这个函数,我们只需要将当前Promise的value值赋值为value的value即可
if (value instanceof WPromise) {
value.then(
this._resolve.bind(this),
this._reject.bind(this)
);
return;
}

this.value = value;
this.status = WPromise.fulfilled; // 将状态设置为成功

// 通知事件执行
this.callbacks.forEach(cb => this._handler(cb));
}

_reject(reason) {
if (reason instanceof WPromise) {
reason.then(
this._resolve.bind(this),
this._reject.bind(this)
);
return;
}

this.reason = reason;
this.status = WPromise.rejected; // 将状态设置为失败

this.callbacks.forEach(cb => this._handler(cb));
}

_handler(callback) {
const {
onFulfilled,
onRejected,
nextResolve,
nextReject
} = callback;

if (this.status === WPromise.pending) {
this.callbacks.push(callback);
return;
}

if (this.status === WPromise.fulfilled) {
// 传入存储的值
// 未传入onFulfilled时,value传入
const nextValue = onFulfilled
? onFulfilled(this.value)
: this.value;
nextResolve(nextValue);
return;
}

if (this.status === WPromise.rejected) {
// 传入存储的错误信息
// 同样的处理
const nextReason = onRejected
? onRejected(this.reason)
: this.reason;
nextReject(nextReason);
}
}
}

4、封装fetch

接上一个Promise实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* 模拟一个简单的异步行为 */
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('willem');
}, 1000);
});
}

fetchData().then((data) => {
// after 1000ms
console.log(data); // willem
return 'wei';
}, (err) => {}).then((data2) => {
console.log(data2); // wei
});

5、es6转es5原理

(1)parse

第一步主要是将 ES6 语法解析为 AST 抽象语法树。简单地说就是将代码打散成颗粒组装的对象。这一步主要是通过 babylon 插件来完成

(2)transfrom

第二步是将打散的 AST 语法通过配置好的 plugins(babel-traverse 对 AST 进行遍历转译)和 presets (es2015 / es2016 / es2017 / env / stage-0 / stage-4 其中 es20xx 表示转换成该年份批准的标准,env 是最新标准,stage-0 和 stage-4 是实验版)转换成新的 AST 语法。这一步主要是由 babel-transform 插件完成。plugins 和 presets 通常在 .babelrc 文件中配置。

(3)Generator

第三步是将新的 AST 语法树对象再生成浏览器都可以识别的 ES5 语法。这一步主要是由 babel-generator 插件完成。

https://blog.csdn.net/weixin_44135121/article/details/104161852

6、手写函数curry,闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 普通的add函数
function add(x, y) {
return x + y
}

// Currying后
function curryingAdd(x) {
return function (y) {
return x + y
}
}

add(1, 2) // 3
curryingAdd(1)(2) // 3

curry:https://www.jianshu.com/p/2975c25e4d71

闭包:https://www.jianshu.com/p/9eb30b6af3a1

7、手写前序遍历、中序遍历、快排

https://www.cnblogs.com/echolun/p/13328927.html

8、vue路由原理,路由守卫

路由原理:https://www.cnblogs.com/gaosirs/p/10606266.html

路由守卫:https://www.jianshu.com/p/691379025334

9、react hook相关

https://blog.csdn.net/kellywong/article/details/106430977

10、如何优化,前端错误监控

数据采集->上报->服务处理->数据存储->可视化

https://segmentfault.com/a/1190000021029136

11、vue和react框架比较

二者都通过虚拟DOM,在渲染之前进行domDiff操作,降低了dom 频繁操作的成本,

vue 的模版语法对初学者较容易上手

12、webpack进行css-less打包

https://www.jianshu.com/p/218ecf81c07b

二、浏览器相关

1、浏览器存储方式有什么

Cookie、localStorage、 sessionStorage

https://www.cnblogs.com/jing-tian/p/10991431.html

2、LS的limit一般浏览器限制多少

5M,cookie较小,一般4k

3、如果LS做缓存层有什么方案保证不溢出

LRU

4、LRU实现

https://www.cnblogs.com/everlose/p/12854807.html

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
var LRUCache = function (capacity) {
this.cache = new Map();
this.capacity = capacity;
};

LRUCache.prototype.get = function (key) {
if (this.cache.has(key)) {
// 存在即更新
let temp = this.cache.get(key);
this.cache.delete(key);
this.cache.set(key, temp);
return temp;
}
return -1;
};

LRUCache.prototype.put = function (key, value) {
if (this.cache.has(key)) {
// 存在即更新(删除后加入)
this.cache.delete(key);
} else if (this.cache.size >= this.capacity) {
// 不存在即加入
// 缓存超过最大值,则移除最近没有使用的
this.cache.delete(this.cache.keys().next().value);
}
this.cache.set(key, value);
};

5、浏览器输入url到页面呈现过程

DNS 解析 -> 三次握手 ->建立TCP连接后发起http请求 ->服务器收到请求并响应HTTP请求 ->浏览器解析htm代码,并请求htm代码中的资源(如js、css图片等) -> 断开TCP连接
(四次挥手)->浏览器对页面进行渲染呈现给用户

https://blog.csdn.net/qq_21993785/article/details/81188253

三、微前端

1、样式隔离

https://www.yuque.com/techiu/vkrpan/urz482
2、路由同步

3、JS沙箱

4、低代码

四、Flutter相关

1、https://www.jianshu.com/p/93821c12a825

2、https://zhuanlan.zhihu.com/p/102193331

3、https://www.jianshu.com/p/1e00b5aaf422

4、https://blog.csdn.net/u013095264/article/details/88802822

龙颜大悦,朕要赏赐!