前端面经二之伴鱼

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的实现原理多了解了解。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值