JS常见手写面试题

实现一个 new 操作符

new 操作符做了什么:

  • 创建一个新的对象
  • 继承父类原型上的方法.
  • 添加父类的属性到新的对象上并初始化. 保存方法的执行结果.
  • 如果执行结果有返回值并且是一个对象, 返回执行的结果, 否则, 返回新创建的对象。
1
2
3
4
5
6
7
8
9
10
function _new(fn, ...args) {
//基于构造函数原型创建一个新对象
let obj = Object.create(fn.prototype);

// 添加属性到新创建的newObj上, 并获取obj函数执行的结果.
let res = fn.apply(obj, args);

// 如果执行结果有返回值并且是一个对象, 返回执行的结果, 否则, 返回新创建的对象
return typeof res === "object" ? res : obj;
}

实现 call

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。

  • 语法:
1
function.call(thisArg, arg1, arg2, ...)
  • 参数:
    thisArg 可选的。在 function 函数运行时使用的 this 值。请注意,this 可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动替换为指向全局对象,原始值会被包装。**arg1, arg2,…**指定的参数列表。
  • 返回值:
    使用调用者提供的 this 值和参数调用该函数的返回值。若该方法没有返回值,则返回 undefined。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Function.prototype.mycall = function (context, ...args) {
if (typeof context === "undefined" || context === null) {
context = window;
}
let fnKey = Symbol();

context[fnKey] = this;

let result = context[fnKey](...args);

delete context[fnKey];

return result;
};

实现 apply

apply() 方法调用一个具有给定 this 值的函数,以及以一个数组(或类数组对象)的形式提供的参数。和 call 类似,只是第二个参数不同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Function.prototype.myapply = function (context, args) {
if (typeof context === "undefined" || context === null) {
context = window;
}
let fnKey = Symbol();

context[fnKey] = this;

let result = context[fnKey](...args);

delete context[fnKey];

return result;
};

实现 bind

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Function.prototype.mybind = function (allArgs) {
if (typeof this !== "function") {
throw new Error("bind必须绑定在函数上");
}
let self = this; //保存需要调用的函数
let args = Array.prototype.slice.call(arguments, 1);

function bindfn(...argArr) {
var _this = this instanceof bindfn ? this : allArgs; //是否是用new调用,如果是new,此时绑定函数中的 this 应是由 new 调用绑定函数返回的实例对象
self.apply(_this, args.concat(argArr));
}

if (this.prototype) {
//维护原型
bindfn.prototype = this.prototype;
}
return bindfn;
};

实现 instanceOf

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

1
2
3
4
5
6
7
8
9
const myInstanceof = (target, origin) => {
while (target) {
if (target.__proto__ === origin.prototype) {
return true;
}
target = target.__proto__;
}
return false;
};

实现 Promise.all

官方规定 Promise.all()接受的参数是一个可遍历的参数,所以未必一定是一个数组,这里暂定传入为数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Promise.myall = function (promises) {
if (!Array.isArray(promises)) {
return;
}
let len = promises.length;
let result = new Array(len);
let count = 0;

return new Promise((resolve, reject) => {
for (let i = len - 1; i >= 0; i--) {
Promise.resolve(promises[i])
.then((data) => {
result[i] = data;
if (++count === len) {
resolve(result);
}
})
.catch((e) => reject(e));
}
});
};

实现 Array.prototype.reduce

1
2
3
4
5
6
7
8
9
Array.prototype.myReduce = function (callback, initialValue) {
let flag = initialValue === undefined ? false : true;
let value = flag ? initialValue : this[0];
let i = flag ? 0 : 1;
for (let j = i; j < this.length; j++) {
value = callback(value, this[j], i, this);
}
return value;
};

实现发布订阅模式

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
class Dep {
//主题对象
constructor() {
this.subs = []; //订阅者列表
}

notify() {
//所有的订阅者更新
this.subs.forEach((sub) => {
sub.update();
});
}
}

class Sub {
//订阅者
constructor(data) {
this.data = data;
}

update() {
//订阅者的更新方法, 也可自定义更新方法
this.data = this.data + 1;
console.log(this.data);
}
}

var dep = new Dep();

dep.subs.push(new Sub(1), new Sub(2));

var pub = {
//发布者
publish() {
dep.notify();
},
};

pub.publish();

实现一个带并发限制的调度器,最多同时运行两个任务

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 Scheduler {
constructor(count) {
this.count = 2;
this.queue = []; // 任务队列
this.run = []; //执行中的任务
}

add(task) {
this.queue.push(task);
return this.schedule();
}

schedule() {
if (this.run.length < this.count && this.queue.length) {
const task = this.queue.shift();
const promise = task().then(() => {
this.run.splice(this.run.indexOf(promise), 1);
});
this.run.push(promise);
return promise;
} else {
return Promise.race(this.run).then(() => this.schedule());
}
}
}
查看评论