手撕八股

TJF.

1. sleep 函数的实现

1
2
3
4
5
//  sleep函数作用是让线程休眠,等到指定时间在重新唤起。

const sleep = (time:number| string){
return new Promise(resolve=setTimeout(resolve,time))
}

2. 防抖节流函数的手写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
### 防抖函数

const debounce= (fb:Function,delay:string|number) {
let timer = null;
return function(){
clearTimeout(timer);
timer = setTimeout(()=>{
fb.apply(this,arguments)
},delay||1000)
}
}

### 节流

const throttle = (fb:Function,delay:string|number)=>{
let flag = null;
return function(){
fb.apply(this,arguments)
}
}

3.深拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const deepClone = function (copyData) {
if (copyData) {
let resData = copyData instanceof Object ? {} : [];
for (key in copyData) {
if (key.hasOwnProperty(key)) {
resData[key] = deepClone(copaData[key]);
} else {
resData[key] = copaData[key];
}
}
return resData;
} else {
return copyData;
}
};

4. 数组扁平化及数组转 tree

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
 ###  扁平化
##将[1,[2,[3,[4,5]]],6] ==> [1,2,3,4,5,6]

const flatData =function(list){
return list.reduce((pre,cur)=>Array.isArray(cur)?pre.concat(flatData(pre)):cur,[])
}


Ag: 转成对应结构
treeList = [
{
id: 1,
pid: null,
label: '第一层',
value: '1',
children: [
{
id: 2,
pid: 1,
label: '第二层1',
value: '2.1',
children: []
},
{
id: 3,
pid: 1,
label: '第二层2',
value: '2.2',
children: []
},
{
id: 4,
pid: 1,
label: '第二层3',
value: '2.3',
children: [
{
id: 5,
pid: 4,
label: '第三层1',
value: '3.1',
children: []
},
{
id: 6,
pid: 4,
label: '第三层2',
value: '3.2',
children: []
},
]
},
]
} ]


const treeToList = function (tree) {
if (!(tree instanceof Array)) return tree;
let resData = [];
tree.map((item) => {
if (item.children?.length > 1) {
resData.push(...treeToList(item.children));
}
delete item.children && resData.push(item);
});
return resData;
};

### 数组转树

const list = [
{id: 1,pid: null,label: '第一层',value: '1'},
{id: 2,pid: 1,label: '第二层1', value: '2.1'},
{id: 3, pid: 1,label: '第二层2',value: '2.2'},
{id: 4,pid: 1,label: '第二层3', value: '2.3'},
{id: 5,pid: 4,label: '第三层1',value: '3.1'},
{id: 6, pid: 4,label: '第三层2',value: '3.2'},
]

const listToTree = (list, root) => {
let listTemp = list.filter((item) => {
return item.pid == root;
});
listTemp.forEach(element => {
element.children = listToTree(list, element.id);
});

return listTemp;
};


5.手写 instanceOf()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// ## instaceof 适用于判断引用类型; typeof适用于判断基本类型(7个),引用类型都是Object;最佳判断为Object.prototype.tostring.call();
const instanceOf = function (target, origin) {
let proto = Object.getPrototypeOf(target);
let prototype = origin.prototype;
while (true) {
if (!proto) return false;
if (proto === prototype) {
return true;
}
proto = Object.getPrototypeOf(proto);
}
};

// eg:
// console.log(instanceOf([1,3],Array)) ===> true
// console.log(instanceOf([1,3],Date)) ===> false

6. 函数柯里化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
## 函数柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数

function curry(targetfn) {
var numOfArgs = targetfn.length;
return function fn() {
if (arguments.length < numOfArgs) {
return fn.bind(null, ...arguments);
} else {
return targetfn.apply(null, arguments);
}
}
}


7. 手写 apply、bind、call

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
## 异同: 三者都是用于改变this指向,其差异性体现在传递参数,执行时机,以及返回对象的不同;apply除去this 之外还需要传递参数的数组;apply和call都是立即执行,bind则是返回一个改变上下文的函数副本,原来的函数不发生变化;

## apply

const myapply = function(context){
const context = context || window;
context[fn] = this;
var result;
if(arguments[1]){
result = fn(...arguments[1]);
}else{
result = fn();
}
delete context.fn;
return result
}

## bind的实现

const mybind = function(context){
// 判断所调用的对象是否是函数
if(typeof this !== "function"){
throw new TypeError("Error")
}

var args = [...arguments].slice(1); // 获取参数
let fn = this; // 这个this是执行函数本身;

// bind 要返回一个函数
return function Fn(){
return fn.apply(
this instanceof Fn? this : context, // 这个this 指的是???
args.concat(...arguments);
)
}
}

## call的实现
//

const mycall = (context)=>{
// 判断所调用的对象是否是函数
if(typeof this !== "function"){
throw new TypeError("Error")
}
const context = context || window;
context[fn] = this;
let args = [...arguments].slice(1);
let result = context[fn](...args);
delete context.fn
return result
}

8 实现 eventEmitter

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
// eventEmitter的架构本质上是 订阅-发布者的模式

const Emitter = class EventEmitter {
constructor() {
this.listener = {};
}

on(type, cb) {
if (!this.listemers[type]) {
this.listeners[type] = [];
}
this.listeners[type].push(cb);
}

emit(type, ...args) {
if (this.listeners[type]) {
this.listeners[type].forEach((cb) => {
cb(...args);
});
}
}

off(type, cb) {
if (this.listeners[type]) {
const targetIndex = this.listeners[type].findIndex((item) => item === cb);
if (targetIndex !== -1) {
this.listeners[type].splice(targetIndex, 1);
}

if (this.listeners[type].length === 0) {
delete this.listeners[type];
}
}
}
};

9. 解析 url 为对象

1

10. 手写 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

const Promise = function(constructor){
let that = this;
that.status = "pending";
that.value = undefined;
that.reason = undefined;

function resolve (value){
if(that.status ==="pending"){
that.value = value;
that.status = "resolved"
}
}

function reject(reason){
if(that.status ==="pending"){
that.reason = reason;
that.status = "rejected"
}
}

try{constructor(resolve,reject); }
catch(e){ reject(e); }

}

Promise.prototype.then = (res,err)=>{
let that = this;
switch(that.status){
case 'resolved' : res(that.value); break;
case 'rejected' : err(that.reason); break;
default;
}

//
}

//
## 拓展 请求失败重试机制
//

手写new

1
2
3
4
5
6
7
const myNew = (fun,...args)=>{
let obj = {};
fun.bind(obj,...args);
obj._proto_ = fun.prototype;

return obj
}
  • 标题: 手撕八股
  • 作者: TJF.
  • 创建于 : 2022-09-28 00:00:00
  • 更新于 : 2024-03-04 08:40:28
  • 链接: https://github.com/taowind/2022/09/28/前端手写题/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论