手写题

手写题

实现 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
26
//静态方法
static all(promiseArr) {
let result = [];
//声明一个计数器 每一个promise返回就加一
let count = 0;
return new Mypromise((resolve, reject) => {
for (let i = 0; i < promiseArr.length; i++) {
//这里用 Promise.resolve包装一下 防止不是Promise类型传进来
Promise.resolve(promiseArr[i]).then(
(res) => {
//这里不能直接push数组 因为要控制顺序一一对应(感谢评论区指正)
result[i] = res;
count++;
//只有全部的promise执行成功之后才resolve出去
if (count === promiseArr.length) {
resolve(result);
}
},
(err) => {
reject(err);
}
);
}
});
}

实现 Promise.finally

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Promise.prototype.finally = function (callback) {
return this.then(
(value) => {
return Promise.resolve(callback()).then(() => {
return value;
});
},
(err) => {
return Promise.resolve(callback()).then(() => {
throw err;
});
}
);
};

实现 Promise.allSettled

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
Promise.allSettled = function (promiseArr) {
let result = [];
return new Promise((resolve, reject) => {
promiseArr.forEach((p, i) => {
Promise.resolve(p).then(
(val) => {
result.push({
status: "fulfilled",
value: val,
});
if (result.length === promiseArr.length) {
resolve(result);
}
},
(err) => {
result.push({
status: "rejected",
reason: err,
});
if (result.length === promiseArr.length) {
resolve(result);
}
}
);
});
});
};

实现 Promise.race

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  //静态方法
static race(promiseArr) {
return new Mypromise((resolve, reject) => {
for (let i = 0; i < promiseArr.length; i++) {
Promise.resolve(promiseArr[i]).then(
(res) => {
//promise数组只要有任何一个promise 状态变更 就可以返回
resolve(res);
},
(err) => {
reject(err);
}
);
}
});
}
}

数组去重

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//reduce + includes 去重
function uniq(arr) {
return arr.reduce((prev, next) => {
if (!prev.includes(next)) {
prev.push(next);
}
return prev;
}, []);
}
console.log(uniq(arr));

function unq(arr) {
return arr.reduce((prev, next) => {
if (!prev.includes(next)) {
prev.push(next);
}
return prev;
}, []);
}

数组扁平化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function flot(arr) {
let result = [];
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
result = result.concat(flot(arr[i]));
} else {
retult = result.push(arr[i]);
}
}
return result;
}
function flot(arr) {
return arr.reduce((prev, next) => {
return prev.concat(Array.isArray(next) ? flat(next) : next);
}, []);
}

实现es6数组的forEach方法

1
2
3
4
5
6
Array.prototype.myForEach = function (fn) {
let arr = [...this];
for (let i = 0; i < arr.length; i++) {
fn(arr[i], i, arr);
}
};

实现es6数组的filter方法

1
2
3
4
5
6
7
8
9
10
Array.prototype.myFilter(fn) {
let arr = [...this];
let newArr = [];
for(let i=0; i<arr.length; i++) {
if(fn(arr[i], i, arr)) {
newArr.push(arr[i]);
}
}
return newArr;
}

实现es6数组的reduce方法

1
2
3
4
5
6
7
8
9
10
11
12
13
Array.prototype.myReduce = function (fn, params) {
let arr = [...this];
let index = 0;
let prev = params;
if (!params) {
index = 1;
prev = arr[0];
}
for (let i = 0; i < arr.length; i++) {
prev = fn(prev, arr[i], i, arr);
}
return prev;
};

实现es6数组的map方法

1
2
3
4
5
6
7
8
Array.prototype.myMap(fn) {
let arr = [...this];
let newArr = [];
for(let i=0; i<arr.length; i++) {
newArr.push(fn(arr[i], i, arr));
}
return newArr;
}

实现es6数组的find方法

1
2
3
4
5
6
7
8
Array.prototype.myFind(fn) {
let arr = [...this];
for(let i=0; i<arr.length; i++) {
if(fn(arr[i], i, arr)) {
return arr[i];
}
}
}

实现es6数组的findIndex方法

1
2
3
4
5
6
7
8
9
Array.prototype.myFindIndex = function (fn) {
let arr = [...this];
for (let i = 0; i < arr.length; i++) {
if (fn(arr[i], i, arr)) {
return i;
}
}
return -1;
};

实现es6数组的every方法

1
2
3
4
5
6
7
8
9
Array.prototype.myEvery = function(fn) {
let arr = [...this];
for(let i=0; i<arr.length; i++) {
if(!fn(arr[i], i, arr)){
return false
}
}
return true;
}

实现es6数组的some方法

1
2
3
4
5
6
7
8
9
Array.prototype.mySome = function(fn) {
let arr = [...this];
for(let i=0; i<arr.length; i++) {
if(fn(arr[i], i, arr)) {
return true
}
}
return false;
}

实现es6数组的includes方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Array.prototype.myIncludes = function(value, index) {
let arr = [...this];
// 第二个参数为整数,从前面第index个位置往后找
// 为负数,从后面数index个开始往后找
// 如果不输入从0开始向后找
let fIndex = 0;
if(index !== undefined && typeof index === 'number' && !isNaN && index !== Infinity) fIndex = index;
if(fIndex < 0) fIndex = arr.length+fIndex;
for(let i=fIndex; i<arr.length; i++) {
// Object.is(value1, value2) 判断两个值是否为同一个值
if(Object.is(arr[i], value)) {
return true;
}
}
return false;
}

实现es6数组的flat方法

1
2
3
4
5
6
7
8
9
10
11
Array.prototype.myFlat = function(value = 1) {
let arr = [...this];
if(value === 0) return arr;
if(typeof value !== "number" || isNaN(value)) value = 1;
return arr.reduce((prev, next) => {
if(Array.isArray(next)) {
return [...prev, ...next.myFlat(value-1)];
}
return [...prev, next];
})
}

实现防抖 debounce

1
2
3
4
5
6
7
8
9
10
11
12
function debounce(fn, time) {
//要限制防抖的函数,限制时间
let timer = null;
return function () {
if (!timer) {
clearInterval(timer);
}
timer = setTimeout(() => {
fn.apply(this, arguments); //当前this指向btn,实参集合
}, time);
};
}

实现节流函数 throttle

1
2
3
4
5
6
7
8
9
10
function throttle(fn, time) {
let date = 0;
return function () {
let newDate = new Date().getTime();
if (newDate - date > time) {
fn.apply(this, arguments);
date = newDate;
}
};
}

写一个完整的深拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function deepClone(obj) {
let newObj = obj instancef Array ? [] : {} //判断传入的值是不是数组 true?[]:{}
if (obj && typeof obj === "object") { //判断传入的值是不是object
for (const key in obj) { //如果是for in 循环
if (obj.hasOwnProperty(key)) { //
if (obj[key] && typeof obj[key] === 'object') {
newObj[key] = deepClone(obj[key])
} else {
newObj[key] = obj[key]
}
}
}
}
return newObj //不是 直接返回
}
let a = [1, 2, 3, 4, 5]
let b = deepClone(a)
a[0] = 2
console.log(a, b);

实现 new 关键字编写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function objectFactory() {
var obj = new Object();
Constructor = Array.prototype.shift.call(arguments);
obj.__proto__ = Constructor.prototype;
var ret = Constructor.apply(obj, arguments);

// ret || obj 这里这么写考虑了构造函数显示返回 null 的情况
return typeof ret === "object" ? ret || obj : obj;
}
//使用
function person(name, age) {
this.name = name;
this.age = age;
}
let p = objectFactory(person, "布兰", 12);
console.log(p); // { name: '布兰', age: 12 }

Es5 实现继承&Es6 实现继承

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
// 原型链继承
function Animal() {
this.colors = ["black", "white"];
}
Animal.prototype.getColor = function () {
return this.colors;
};
function Dog() {}
Dog.prototype = new Animal();

let dog1 = new Dog();
dog1.colors.push("brown");
let dog2 = new Dog();
console.log(dog2.colors); // ['black', 'white', 'brown']

// 组合继承
function Animal(name) {
this.name = name;
this.colors = ["black", "white"];
}
Animal.prototype.getName = function () {
return this.name;
};
function Dog(name, age) {
Animal.call(this, name);
this.age = age;
}
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;

let dog1 = new Dog("奶昔", 2);
dog1.colors.push("brown");
let dog2 = new Dog("哈赤", 1);
console.log(dog2);
// { name: "哈赤", colors: ["black", "white"], age: 1 }

// 借用构造函数(经典继承)
function Animal(name) {
this.name = name;
this.getName = function () {
return this.name;
};
}
function Dog(name) {
Animal.call(this, name);
}
Dog.prototype = new Animal();

// 寄生组合式继承
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
function inheritPrototype(child, parent) {
let prototype = object(parent.prototype);
prototype.constructor = child;
child.prototype = prototype;
}
inheritPrototype(Dog, Animal);
//class实现继承
class Animal {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
class Dog extends Animal {
constructor(name, age) {
super(name);
this.age = age;
}
}

手写 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
function Person() {
console.log(this.name, a, b, c, d);
}
let egg = {
name: "小雅",
};
// 封装mycall
Function.prototype.mycall = function (obj) {
obj = obj || window; //这里注意this不能指向null
let newArgs = []; //需要拿到每一个arguments集合
obj.fn = this;
for (let i = 1; i < arguments.length; i++) {
//循环arguments集合,这里从下标1开始,第0项是this指向
newArgs.push(`arguments[${i}]`);
}
let res = eval(`obj.fn(${newArgs})`);
delete obj.fn;
return res;
};
console.log(Person.mycall(egg, {}, 2, 3, 4));
Person.call(egg, {}, 2, 3, 4);
Function.prototype.mycall = function (obj) {
obj = obj || window;
obj.fn = this;

delete obj.fn;
};

手写 Apply

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
function Person(a, b) {
console.log(this.name, a, b);
// return 123
}
let egg = {
name: "小雅",
};
//封装myapply
/*
1.需要注意的是第二个参数
2.this指向问题
3.返回值
4.this为null时
*/
Function.prototype.myapply = function (obj, args) {
obj = obj || window; //这里注意this不能指向null
let newArgs = []; //需要拿到每一个arguments集合
let res = null;
obj.fn = this;
if (!args) {
// 如果没有传第二个参数 直接返回当前的方法
res = obj.fn();
} else {
//如果有 循环遍历把每一项放到一个空数组里 然后使用eval()函数 将方法调用并传入新数组
for (let i = 0; i < args.length; i++) {
//循环arguments集合,这里从下标1开始,第0项是this指向
newArgs.push(`args[${i}]`);
}
res = eval(`obj.fn(${newArgs})`);
}
delete obj.fn; //删除当前的方法
return res; //返回值
};
Person.myapply(egg, [1, "2"]);
Person.apply(egg, [1, "2"]);

手写 bind

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function Person(a, b) {
console.log(this.name, a, b);
// return 123
}
let egg = {
name: "小雅",
};

//封装bind方法
Function.prototype.mybind = function (obj) {
let args = Array.prototype.slice.call(arguments, 1); //将伪数组转化为数组 arguments调用此方法 1 从下标1开始
let arg = null;
console.log(this);
let that = this; //获取到当前函数的this指向
return function () {
//闭包的方式返回一个函数 //这里为es5方法 es6 ()=>{} this继承父级 但是下边那个打印结果有问题,咱也不知道为啥
console.log(this);
arg = Array.prototype.slice.call(arguments);
that.apply(obj, [...args, ...arg]); //这里考虑到了函数内部的值 合并一下参数
};
};
Person.mybind(egg, 1)(2); //调用的时候为柯函数里化

实现柯里化函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function curry(fn, currArgs) {
// 这里的fn就是sum方法
return function () {
let args = Array.prototype.slice.call(arguments);
console.log(fn, currArgs);
// 首次调用时未提供参数currArgs,因此不用进行拼接执行
if (currArgs) {
args = args.concat(currArgs); // 这里的currArgs是上次递归传递进来的,也就是上次递归的args
}
// 递归调用
if (args.length < fn.length) {
return curry(fn, args);
}
console.log(args);
return fn.apply(this, args); // 这里调用了apply方法,将收集起来的args参数全都传入fn中
};
}
function sum(a, b, c, d, e) {
return a + b + c + d + e;
}
const fn = curry(sum);
console.log(fn(1)(2)(3)(4)(5)); // 6
console.log(fn(1)(2, 3)(4, 5)); // 6
console.log(fn(1, 2, 3, 4, 5)); //6

实现 jsonp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const jsonp = ({ url, params, callbackName }) => {
const generateUrl = () => {
let dataSrc = "";
for (let key in params) {
if (params.hasOwnProperty(key)) {
dataSrc += `${key}=${params[key]}&`;
}
}
dataSrc += `callback=${callbackName}`;
return `${url}?${dataSrc}`;
};
return new Promise((resolve, reject) => {
const scriptEle = document.createElement("script");
scriptEle.src = generateUrl();
document.body.appendChild(scriptEle);
window[callbackName] = (data) => {
resolve(data);
document.removeChild(scriptEle);
};
});
};

实现 instanceOf

1
2
3
4
5
6
7
8
9
10
function instanceOf(left, right) {
let proto = left.__proto__;
while (true) {
if (proto === null) return false;
if (proto === right.prototype) {
return true;
}
proto = proto.__proto__;
}
}

图片懒加载,实现lazyLoad()这个方法,使之只显示当前屏幕图片并测试

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
let imgSrc = [
"./image/01.jpg",
"./image/02.jpg",
"./image/03.jpg",
"./image/04.jpg",
"./image/05.jpg",
"./image/06.jpg",
"./image/07.jpg",
"./image/08.jpg",
"./image/09.jpg",
"./image/10.jpg",
"./image/11.jpeg",
"./image/12.jpeg",
"./image/13.jpeg",
"./image/14.jpeg",
"./image/15.jpeg",
"./image/16.jpeg",
"./image/17.jpeg",
"./image/18.jpeg",
"./image/19.jpeg",
"./image/20.jpeg"
];
let image = document.getElementById('image');
let imgs = [...image.children];
// 设置图片的自定定义属性src
for(let i=0; i<imgs.length; i++) {
imgs[i].dataset.src = imgSrc[i];
}

let len = imgs.length;

const lazyLoad = (function () {
return function () {
let deleteIndex = [];
for(let i=0; i<imgs.length; i++) {
if(imgs[i].getBoundingClientRect().top < window.innerHeight) {
imgs[i].src = imgs[i].dataset.src;
deleteIndex.push(i)
}
}
imgs = imgs.filter((item, index) => {
return !deleteIndex.includes(index)
})
if(imgs.length === 0) {
document.removeEventListener('scroll', lazyLoad);
}
}
})()

lazyLoad();
document.addEventListener('scroll', lazyLoad);

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
class Stack{
contructor() {
this.stack = [];
}

toString() {
return this.stack.join();
}

push(val) {
this.stack.push(val);
}

pop() {
return this.stack.pop();
}

top() {
return this.stack[this.stack.length-1];
}

size() {
return this.stack.length;
}
}

队列

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
class Queue{
constructor(size = 10) {
this.queue = [];
this.size = size;
}

enQueue(val) {
if(this.isFull()) {
this.deQueue();
}
this.queue.push(val)
}

deQueue() {
return this.queue.shift();
}

isFull() {
return this.queue.length === this.size;
}

isEmpty() {
return this.queue.length === 0;
}

toString() {
return this.queue.join();
}
}

链表

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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
class Node{
constructor({val, next}) {
this.val = val;
this.next = next;
}
}

let _head = Symbol('_head');
class NodeList{
constructor() {
// 初始一个头节点,不可访问,不能找到
Object.defineProperty(this, {
[_head]:{
writable: true,
value: new Node({val: null, next: null}),
enumerable:false,
configurable: false
}
})
}

// 插入节点
insert(val, index) {
let node = new Node({val: val, next: null})
// 如果没有头节点,插入的第一个节点就是头节点
if(!this[_head].val) {
this[_head] = node;
return;
}
// 如果index没有值,插入到最后
if(!index) {
let lastNode = this.find(this.size()-1);
lastNode.next = node;
return;
}

// 如果index为0,替换头节点
if(index === 0) {
node.next = this[_head];
this[_head] = node;
return;
}
// 其余正常的,先获取上一个节点
let prevNode = this.find(index-1);
node.next = prevNode.next;
prevNode.next = node;
return;
}

// 判断链表长度
size() {
let i=0;
let n = this[_head];
while(n) {
n = n.next;
i++;
}
return i;
}

// 将链表转成字符串形式
toString() {
let n = this[_head];
let str = "";
while(n){
str += n.val;
if(n.next) {
str += ", "
}
n = n.next;
}
return str;
}

// 获取节点
find(index) {
let n = this[_head];
let i = 0;
while(i !== index) {
i++;
n = n.next;
}
return n;
}

// 转为数组
toArray() {
let n = this[_head];
let arr = [];
while(n) {
arr.push(n.val);
n = n.next;
}
return arr;
}

// 更新
update(val, index) {
let node = this.find(index);
node.val = val;
}

// 删除
deleteByIndex(index) {
let node = this.find(index);

// 如果删除的是头节点
if(index === 0) {
this[_head] = node.next;
node.next = null;
return;
}

let prevNode = this.find(index-1);
prevNode.next = node.next;
node.next = 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
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
class Tree{
constructor(val, left, right) {
this.val = val;
this.left = left;
this.right = right;
}
}

let head = new Tree(1, null, null);
let node_1 = new Tree(2, null, null);
let node_2 = new Tree(3, null, null);
let node_3 = new Tree(4, null, null);
let node_4 = new Tree(5, null, null);
let node_5 = new Tree(6, null, null);
let node_6 = new Tree(7, null, null);
head.left = node_1;
head.right = node_2;
node_1.left = node_3;
node_1.right = node_4;
node_2.left = node_5;
node_2.right = node_6;
node_3.left = node_7;


// 实现树的中序遍历
function inOrder(head) {
if(!head) return
let stack = [head];
let n = head.left;
while(stack.length) {
while(n) { // 将n变为最左边的值
stack.push(n);
n = n.left;
}
let node = stack.pop();
console.log(node.val);
if (node.right) {
stack.push(node.right);
n = node.right.left;
}

}
}

// 实现树的先序遍历
function prevOrder(head) {
if(!head) return
let stack = [head];
while(stack.length) {
let n = stack.pop();
console.log(n.val);
n.right && stack.push(n.right);
n.left && stack.push(n.left);
}
}

// 实现树的层序遍历
function order(head) {
if(!head) return
let queue = [head];
while(queue.length) {
let n = queue.shift();
console.log(n.val);
n.left && queue.push(n.left);
n.right && queue.push(n.right);
}
}

手写题
http://example.com/2024/06/09/手写题/
作者
巷子里的老张先生
发布于
2024年6月9日
许可协议