1、事件循环
console.log(1)
setTimeout(() => {
console.log(2)
Promise.resolve().then((data) => {
console.log(3)
})
})
new Promise((resolve) => {
resolve()
console.log(4)
}).then(() => {
console.log(5)
setTimeout(() => {
console.log(6)
})
}).then(() => console.log(7))
console.log(8)
// 我给出的结果:1,4,8,5,2,3,6,7
// 实际答案:1,4,8,5,7,2,3,6
// 就是setTimeout并不会影响后边then的执行顺序,只有里边的回调才算宏任务
2、实现promise.all
哈哈哈,这个我写过,咔咔咔写出我的结果:
Promise.all = function(arr){
return new Promise((resolve, reject) => {
let num = 0; // 记录resolve的个数
let res = []; // 记录resolve的结果
let len = arr.length;
for (let i = 0; i < len; i++) {
let promise = arr[i];
if (!(promise instanceof Promise)) {
promise = Promise.resolve(promise);
}
promise.then((value) => {
num++;
res.push(value);
if (num === len) {
resolve(res);
}
}).catch((err) => {
rejected(err);
});
}
});
}
面试官说我这返回数组的顺序不对, 故将 res.push(value) 修改为 res[i] = value
然后他又帮我优化了一下,最终代码如下:
Promise.all = function(arr){
return new Promise((resolve, reject) => {
let num = 0; // 记录resolve的个数
let res = []; // 记录resolve的结果
let len = arr.length;
for (let i = 0; i < len; i++) {
let promise = arr[i];
// if (!(promise instanceof Promise)) {
// promise = Promise.resolve(promise);
//}/
Promise.reolsve(promise).then((value) => {
num++;
res[i] = value;
if (num === len) {
resolve(res);
}
}).catch((err) => {
rejected(err);
});
}
});
}
3、this指向有几种情况?实现call
这个我也写过,我的答案:
Function.prototype.call = function(that, ...args){
that.$fn = this;
const res = that.$fn(...args);
delete that.$fn;
return res;
}
但是面试官说,万一原来就有$fn呢,其实这个问题我也看过,别人是用symbol解决的,代码如下:
Function.prototype.call = function(that, ...args){
let a = Symbol('sss');
that[a] = this;
const res = that[a](...args);
delete that[a];
return res;
}
4、实现 instanceof
这个没写过,但是原理我大概懂的,就是从原型里查找,于是一边画了原型链关系一边写的,但是一开始写反了
正确的思路应该是从要查找的对象开始往前找,若一直找到原型最顶部(null)还没找到该原型,就返回false,若找到返回true,代码如下:
// o是 instanceof 左边的值,Constructor是右边的值
function instanceof(o, Constructor){
let obj = o.__proto__;
while (obj !== null) {
if (obj === Constructor.prototype) {
return true;
} else {
obj = obj.__proto__;
}
}
return false;
}
补充知识:
prototype是函数才有的属性
,__proto__
是每个对象都有的属性。大多数情况下,
__proto__
可以理解为“构造器的原型”,但是通过 Object.create()创建的对象有可能不是。
5、实现reduce
不太记得reduce怎么用的了,下面是语法:
array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
参数介绍:
total | 必需。初始值, 或者计算结束后的返回值。 |
currentValue | 必需。当前元素 |
currentIndex | 可选。当前元素的索引 |
arr | 可选。当前元素所属的数组对象。 |
initialValue | 可选。传递给函数的初始值 |
代码实现:
Array.prototype.selfReduce = function(fn, init){
let arr = this;
let total = init;
let value = arr[0];
for (let i = 0; i < arr.length; i++) {
total = fn(total, arr[i], i, arr);
}
return total;
}
但是上边只是简单的实现,好多情况没考虑,下面是一些要考虑的情况:
- 判断是否有初始值,当提供了初始值,则第一次执行回调函数时第一个参数就是初始值,则第二个参数是数组第一项,如果没有提供初始值,则第一个参数是数组第一项,第二个参数是数组第二项。
优化后的代码:
Array.prototype.selfReduce = function(fn, init){
console.log(this);
// 第一个参数必须要为function
if (typeof fn !== "function") {
throw new TypeError(fn + " is not a function");
}
let arr = this, startIndex = 0;
let total = init;
// 判断是否有初始值
if (!total) {
total = arr[0];
startIndex = 1;
}
for (let i = startIndex; i < arr.length; i++) {
total = fn(total, arr[i], i, arr);
}
return total;
}
总结:
只考察了js的内容,尤其是对一些API的实现,所以以后还是要对API的实现原理多了解了解。