关于前端:20道前端高频面试题附答案

39次阅读

共计 16407 个字符,预计需要花费 42 分钟才能阅读完成。

ES6 新个性

1.ES6 引入来严格模式
    变量必须申明后在应用
    函数的参数不能有同名属性, 否则报错
    不能应用 with 语句 (说实话我根本没用过)
    不能对只读属性赋值, 否则报错
    不能应用前缀 0 示意八进制数, 否则报错 (说实话我根本没用过)
    不能删除不可删除的数据, 否则报错
    不能删除变量 delete prop, 会报错, 只能删除属性 delete global[prop]
    eval 不会在它的外层作用域引入变量
    eval 和 arguments 不能被从新赋值
    arguments 不会主动反映函数参数的变动
    不能应用 arguments.caller (说实话我根本没用过)
    不能应用 arguments.callee (说实话我根本没用过)
    禁止 this 指向全局对象
    不能应用 fn.caller 和 fn.arguments 获取函数调用的堆栈 (说实话我根本没用过)
    减少了保留字(比方 protected、static 和 interface)2. 对于 let 和 const 新增的变量申明

3. 变量的解构赋值

4. 字符串的扩大
    includes():返回布尔值,示意是否找到了参数字符串。startsWith():返回布尔值,示意参数字符串是否在原字符串的头部。endsWith():返回布尔值,示意参数字符串是否在原字符串的尾部。5. 数值的扩大
    Number.isFinite()用来查看一个数值是否为无限的(finite)。Number.isNaN()用来查看一个值是否为 NaN。6. 函数的扩大
    函数参数指定默认值
7. 数组的扩大
    扩大运算符
8. 对象的扩大
    对象的解构
9. 新增 symbol 数据类型

10.Set 和 Map 数据结构 
    ES6 提供了新的数据结构 Set。它相似于数组,然而成员的值都是惟一的,没有反复的值。Set 自身是一个构造函数,用来生成 Set 数据结构。Map 它相似于对象,也是键值对的汇合,然而“键”的范畴不限于字符串,各种类型的值(包含对象)都能够当作键。11.Proxy
    Proxy 能够了解成,在指标对象之前架设一层“拦挡”,外界对该对象的拜访
    都必须先通过这层拦挡,因而提供了一种机制,能够对外界的拜访进行过滤和改写。Proxy 这个词的原意是代理,用在这里示意由它来“代理”某些操作,能够译为“代理器”。Vue3.0 应用了 proxy
12.Promise
    Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更正当和更弱小。特点是:对象的状态不受外界影响。一旦状态扭转,就不会再变,任何时候都能够失去这个后果。13.async 函数 
    async 函数对 Generator 函数的区别:(1)内置执行器。Generator 函数的执行必须靠执行器,而 async 函数自带执行器。也就是说,async 函数的执行,与一般函数截然不同,只有一行。(2)更好的语义。async 和 await,比起星号和 yield,语义更分明了。async 示意函数里有异步操作,await 示意紧跟在前面的表达式须要期待后果。(3)失常状况下,await 命令前面是一个 Promise 对象。如果不是,会被转成一个立刻 resolve 的 Promise 对象。(4)返回值是 Promise。async 函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象不便多了。你能够用 then 办法指定下一步的操作。14.Class 
    class 跟 let、const 一样:不存在变量晋升、不能反复申明...
    ES6 的 class 能够看作只是一个语法糖,它的绝大部分性能
    ES5 都能够做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。15.Module
    ES6 的模块主动采纳严格模式,不论你有没有在模块头部加上 "use strict";。import 和 export 命令以及 export 和 export default 的区别

常见的 HTTP 申请办法

  • GET: 向服务器获取数据;
  • POST:将实体提交到指定的资源,通常会造成服务器资源的批改;
  • PUT:上传文件,更新数据;
  • DELETE:删除服务器上的对象;
  • HEAD:获取报文首部,与 GET 相比,不返回报文主体局部;
  • OPTIONS:询问反对的申请办法,用来跨域申请;
  • CONNECT:要求在与代理服务器通信时建设隧道,应用隧道进行 TCP 通信;
  • TRACE: 回显服务器收到的申请,次要⽤于测试或诊断。

介绍下 promise 的个性、优缺点,外部是如何实现的,入手实现 Promise

1)Promise 根本个性

  • 1、Promise 有三种状态:pending(进行中)、fulfilled(已胜利)、rejected(已失败)
  • 2、Promise 对象承受一个回调函数作为参数, 该回调函数承受两个参数,别离是胜利时的回调 resolve 和失败时的回调 reject;另外 resolve 的参数除了正常值以外,还可能是一个 Promise 对象的实例;reject 的参数通常是一个 Error 对象的实例。
  • 3、then 办法返回一个新的 Promise 实例,并接管两个参数 onResolved(fulfilled 状态的回调);onRejected(rejected 状态的回调,该参数可选)
  • 4、catch 办法返回一个新的 Promise 实例
  • 5、finally 办法不论 Promise 状态如何都会执行,该办法的回调函数不承受任何参数
  • 6、Promise.all()办法将多个多个 Promise 实例,包装成一个新的 Promise 实例,该办法承受一个由 Promise 对象组成的数组作为参数 (Promise.all() 办法的参数能够不是数组,但必须具备 Iterator 接口,且返回的每个成员都是 Promise 实例),留神参数中只有有一个实例触发 catch 办法,都会触发 Promise.all()办法返回的新的实例的 catch 办法,如果参数中的某个实例自身调用了 catch 办法,将不会触发 Promise.all()办法返回的新实例的 catch 办法
  • 7、Promise.race()办法的参数与 Promise.all 办法一样,参数中的实例只有有一个率先扭转状态就会将该实例的状态传给 Promise.race()办法,并将返回值作为 Promise.race()办法产生的 Promise 实例的返回值
  • 8、Promise.resolve()将现有对象转为 Promise 对象,如果该办法的参数为一个 Promise 对象,Promise.resolve()将不做任何解决;如果参数 thenable 对象 (即具备 then 办法),Promise.resolve() 将该对象转为 Promise 对象并立刻执行 then 办法;如果参数是一个原始值,或者是一个不具备 then 办法的对象,则 Promise.resolve 办法返回一个新的 Promise 对象,状态为 fulfilled,其参数将会作为 then 办法中 onResolved 回调函数的参数,如果 Promise.resolve 办法不带参数,会间接返回一个 fulfilled 状态的 Promise 对象。须要留神的是,立刻 resolve()的 Promise 对象,是在本轮“事件循环”(event loop)的完结时执行,而不是在下一轮“事件循环”的开始时。
  • 9、Promise.reject()同样返回一个新的 Promise 对象,状态为 rejected,无论传入任何参数都将作为 reject()的参数

2)Promise 长处

  • ①对立异步 API

    • Promise 的一个重要长处是它将逐步被用作浏览器的异步 API,对立当初各种各样的 API,以及不兼容的模式和手法。
  • ②Promise 与事件比照

    • 和事件相比拟,Promise 更适宜解决一次性的后果。在后果计算出来之前或之后注册回调函数都是能够的,都能够拿到正确的值。Promise 的这个长处很天然。然而,不能应用 Promise 解决屡次触发的事件。链式解决是 Promise 的又一长处,然而事件却不能这样链式解决。
  • ③Promise 与回调比照

    • 解决了回调天堂的问题,将异步操作以同步操作的流程表达出来。
  • ④Promise 带来的额定益处是蕴含了更好的错误处理形式(蕴含了异样解决),并且写起来很轻松(因为能够重用一些同步的工具,比方 Array.prototype.map())。

3)Promise 毛病

  • 1、无奈勾销 Promise,一旦新建它就会立刻执行,无奈中途勾销。
  • 2、如果不设置回调函数,Promise 外部抛出的谬误,不会反馈到内部。
  • 3、当处于 Pending 状态时,无奈得悉目前停顿到哪一个阶段(刚刚开始还是行将实现)。
  • 4、Promise 真正执行回调的时候,定义 Promise 那局部实际上曾经走完了,所以 Promise 的报错堆栈上下文不太敌对。

4)简略代码实现
最简略的 Promise 实现有 7 个次要属性, state(状态), value(胜利返回值), reason(错误信息), resolve 办法, reject 办法, then 办法

class Promise{constructor(executor) {
    this.state = 'pending';
    this.value = undefined;
    this.reason = undefined;
    let resolve = value => {if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
      }
    };
    let reject = reason => {if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;
      }
    };
    try {
      // 立刻执行函数
      executor(resolve, reject);
    } catch (err) {reject(err);
    }
  }
  then(onFulfilled, onRejected) {if (this.state === 'fulfilled') {let x = onFulfilled(this.value);
    };
    if (this.state === 'rejected') {let x = onRejected(this.reason);
    };
  }
}

5)面试够用版

function myPromise(constructor){ let self=this;
  self.status="pending" // 定义状态扭转前的初始状态 
  self.value=undefined;// 定义状态为 resolved 的时候的状态 
  self.reason=undefined;// 定义状态为 rejected 的时候的状态 
  function resolve(value){
    // 两个 ==="pending",保障了了状态的扭转是不不可逆的 
    if(self.status==="pending"){
      self.value=value;
      self.status="resolved"; 
    }
  }
  function reject(reason){
     // 两个 ==="pending",保障了了状态的扭转是不不可逆的
     if(self.status==="pending"){
        self.reason=reason;
        self.status="rejected"; 
      }
  }
  // 捕捉结构异样 
  try{constructor(resolve,reject);
  }catch(e){reject(e);
    } 
}
myPromise.prototype.then=function(onFullfilled,onRejected){ 
  let self=this;
  switch(self.status){case "resolved": onFullfilled(self.value); break;
    case "rejected": onRejected(self.reason); break;
    default: 
  }
}

// 测试
var p=new myPromise(function(resolve,reject){resolve(1)}); 
p.then(function(x){console.log(x)})
// 输入 1 

6)大厂专供版

const PENDING = "pending"; 
const FULFILLED = "fulfilled"; 
const REJECTED = "rejected";
const resolvePromise = (promise, x, resolve, reject) => {if (x === promise) {
    // If promise and x refer to the same object, reject promise with a TypeError as the reason.
    reject(new TypeError('循环援用'))
  }
  // if x is an object or function,
  if (x !== null && typeof x === 'object' || typeof x === 'function') {
    // If both resolvePromise and rejectPromise are called, or multiple calls to the same argument are made, the first call takes precedence, and any further calls are ignored.
    let called
    try { // If retrieving the property x.then results in a thrown exception e, reject promise with e as the reason.
      let then = x.then // Let then be x.then
      // If then is a function, call it with x as this
      if (typeof then === 'function') {// If/when resolvePromise is called with a value y, run [[Resolve]](promise, y)
        // If/when rejectPromise is called with a reason r, reject promise with r.
        then.call(x, y => {if (called) return
          called = true
          resolvePromise(promise, y, resolve, reject)
        }, r => {if (called) return
          called = true
          reject(r)
        })
      } else {
        // If then is not a function, fulfill promise with x.
        resolve(x)
      }
    } catch (e) {if (called) return
      called = true
      reject(e)
    }
  } else {
    // If x is not an object or function, fulfill promise with x
    resolve(x)
  }
}
function Promise(excutor) {
  let that = this; // 缓存以后 promise 实例例对象
  that.status = PENDING; // 初始状态
  that.value = undefined; // fulfilled 状态时 返回的信息
  that.reason = undefined; // rejected 状态时 回绝的起因 
  that.onFulfilledCallbacks = []; // 存储 fulfilled 状态对应的 onFulfilled 函数
  that.onRejectedCallbacks = []; // 存储 rejected 状态对应的 onRejected 函数
  function resolve(value) { // value 胜利态时接管的终值
    if(value instanceof Promise) {return value.then(resolve, reject);
    }
    // 实际中要确保 onFulfilled 和 onRejected ⽅办法异步执⾏行行,且应该在 then ⽅办法被调⽤用的那⼀一轮事件循环之后的新执⾏行行栈中执⾏行行。setTimeout(() => {
      // 调⽤用 resolve 回调对应 onFulfilled 函数
      if (that.status === PENDING) {// 只能由 pending 状态 => fulfilled 状态 (防止调⽤用屡次 resolve reject)
        that.status = FULFILLED;
        that.value = value;
        that.onFulfilledCallbacks.forEach(cb => cb(that.value));
      }
    });
  }
  function reject(reason) { // reason 失败态时接管的拒因
    setTimeout(() => {
      // 调⽤用 reject 回调对应 onRejected 函数
      if (that.status === PENDING) {// 只能由 pending 状态 => rejected 状态 (防止调⽤用屡次 resolve reject)
        that.status = REJECTED;
        that.reason = reason;
        that.onRejectedCallbacks.forEach(cb => cb(that.reason));
      }
    });
  }

  // 捕捉在 excutor 执⾏行行器器中抛出的异样
  // new Promise((resolve, reject) => {//     throw new Error('error in excutor')
  // })
  try {excutor(resolve, reject);
  } catch (e) {reject(e);
  }
}
Promise.prototype.then = function(onFulfilled, onRejected) {
  const that = this;
  let newPromise;
  // 解决理参数默认值 保障参数后续可能持续执⾏行行
  onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value;
  onRejected = typeof onRejected === "function" ? onRejected : reason => {throw reason;};
  if (that.status === FULFILLED) { // 胜利态
    return newPromise = new Promise((resolve, reject) => {setTimeout(() => {
        try{let x = onFulfilled(that.value);
          resolvePromise(newPromise, x, resolve, reject); // 新的 promise resolve 上⼀一个 onFulfilled 的返回值
        } catch(e) {reject(e); // 捕捉前⾯面 onFulfilled 中抛出的异样 then(onFulfilled, onRejected);
        }
      });
    })
  }
  if (that.status === REJECTED) { // 失败态
    return newPromise = new Promise((resolve, reject) => {setTimeout(() => {
        try {let x = onRejected(that.reason);
          resolvePromise(newPromise, x, resolve, reject);
        } catch(e) {reject(e);
        }
      });
    });
  }
  if (that.status === PENDING) { // 期待态
// 当异步调⽤用 resolve/rejected 时 将 onFulfilled/onRejected 收集暂存到汇合中
    return newPromise = new Promise((resolve, reject) => {that.onFulfilledCallbacks.push((value) => {
        try {let x = onFulfilled(value);
          resolvePromise(newPromise, x, resolve, reject);
        } catch(e) {reject(e);
        }
      });
      that.onRejectedCallbacks.push((reason) => {
        try {let x = onRejected(reason);
          resolvePromise(newPromise, x, resolve, reject);
        } catch(e) {reject(e);
        }
      });
    });
  }
};

对事件委托的了解

(1)事件委托的概念

事件委托实质上是利用了 浏览器事件冒泡 的机制。因为事件在冒泡过程中会上传到父节点,父节点能够通过事件对象获取到指标节点,因而能够把子节点的监听函数定义在父节点上,由父节点的监听函数对立解决多个子元素的事件,这种形式称为事件委托(事件代理)。

应用事件委托能够不必要为每一个子元素都绑定一个监听事件,这样缩小了内存上的耗费。并且应用事件代理还能够实现事件的动静绑定,比如说新增了一个子节点,并不需要独自地为它增加一个监听事件,它绑定的事件会交给父元素中的监听函数来解决。

(2)事件委托的特点

  • 缩小内存耗费

如果有一个列表,列表之中有大量的列表项,须要在点击列表项的时候响应一个事件:

<ul id="list">
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
  ......
  <li>item n</li>
</ul>

如果给每个列表项一一都绑定一个函数,那对于内存耗费是十分大的,效率上须要耗费很多性能。因而,比拟好的办法就是把这个点击事件绑定到他的父层,也就是 ul 上,而后在执行事件时再去匹配判断指标元素,所以事件委托能够缩小大量的内存耗费,节约效率。

  • 动静绑定事件

给上述的例子中每个列表项都绑定事件,在很多时候,须要通过 AJAX 或者用户操作动静的减少或者去除列表项元素,那么在每一次扭转的时候都须要从新给新增的元素绑定事件,给行将删去的元素解绑事件;如果用了事件委托就没有这种麻烦了,因为事件是绑定在父层的,和指标元素的增减是没有关系的,执行到指标元素是在真正响应执行事件函数的过程中去匹配的,所以应用事件在动静绑定事件的状况下是能够缩小很多反复工作的。

// 来实现把 #list 下的 li 元素的事件代理委托到它的父层元素也就是 #list 上:// 给父层元素绑定事件
document.getElementById('list').addEventListener('click', function (e) {
  // 兼容性解决
  var event = e || window.event;
  var target = event.target || event.srcElement;
  // 判断是否匹配指标元素
  if (target.nodeName.toLocaleLowerCase === 'li') {console.log('the content is:', target.innerHTML);
  }
});

在上述代码中,target 元素则是在 #list 元素之下具体被点击的元素,而后通过判断 target 的一些属性(比方:nodeName,id 等等)能够更准确地匹配到某一类 #list li 元素之上;

(3)局限性

当然,事件委托也是有局限的。比方 focus、blur 之类的事件没有事件冒泡机制,所以无奈实现事件委托;mousemove、mouseout 这样的事件,尽管有事件冒泡,然而只能一直通过地位去计算定位,对性能耗费高,因而也是不适宜于事件委托的。

当然事件委托不是只有长处,它也是有 毛病 的,事件委托会影响页面性能,次要影响因素有:

  • 元素中,绑定事件委托的次数;
  • 点击的最底层元素,到绑定事件元素之间的 DOM 层数;

在必须应用事件委托的中央,能够进行如下的解决:

  • 只在必须的中央,应用事件委托,比方:ajax的部分刷新区域
  • 尽量的缩小绑定的层级,不在 body 元素上,进行绑定
  • 缩小绑定的次数,如果能够,那么把多个事件的绑定,合并到一次事件委托中去,由这个事件委托的回调,来进行散发。

代码输入问题

window.number = 2;
var obj = {
 number: 3,
 db1: (function(){console.log(this);
   this.number *= 4;
   return function(){console.log(this);
     this.number *= 5;
   }
 })()}
var db1 = obj.db1;
db1();
obj.db1();
console.log(obj.number);     // 15
console.log(window.number);  // 40

这道题目看清起来有点乱,然而实际上是考查 this 指向的:

  1. 执行 db1()时,this 指向全局作用域,所以 window.number 4 = 8,而后执行匿名函数,所以 window.number 5 = 40;
  2. 执行 obj.db1(); 时,this 指向 obj 对象,执行匿名函数,所以 obj.numer * 5 = 15。

说一下怎么把类数组转换为数组?

// 通过 call 调用数组的 slice 办法来实现转换
Array.prototype.slice.call(arrayLike)

// 通过 call 调用数组的 splice 办法来实现转换
Array.prototype.splice.call(arrayLike,0)

// 通过 apply 调用数组的 concat 办法来实现转换
Array.prototype.concat.apply([],arrayLike)

// 通过 Array.from 办法来实现转换
Array.from(arrayLike)

参考 前端进阶面试题具体解答

代码输入后果

Promise.resolve('1')
  .then(res => {console.log(res)
  })
  .finally(() => {console.log('finally')
  })
Promise.resolve('2')
  .finally(() => {console.log('finally2')
      return '我是 finally2 返回的值'
  })
  .then(res => {console.log('finally2 前面的 then 函数', res)
  })

输入后果如下:

1
finally2
finally
finally2 前面的 then 函数 2

.finally()个别用的很少,只有记住以下几点就能够了:

  • .finally()办法不论 Promise 对象最初的状态如何都会执行
  • .finally()办法的回调函数不承受任何的参数,也就是说你在 .finally() 函数中是无奈晓得 Promise 最终的状态是 resolved 还是 rejected
  • 它最终返回的默认会是一个上一次的 Promise 对象值,不过如果抛出的是一个异样则返回异样的 Promise 对象。
  • finally 实质上是 then 办法的特例

.finally()的谬误捕捉:

Promise.resolve('1')
  .finally(() => {console.log('finally1')
    throw new Error('我是 finally 中抛出的异样')
  })
  .then(res => {console.log('finally 前面的 then 函数', res)
  })
  .catch(err => {console.log('捕捉谬误', err)
  })

输入后果为:

'finally1'
'捕捉谬误' Error: 我是 finally 中抛出的异样

代码输入后果

function Person(name) {this.name = name}
var p2 = new Person('king');
console.log(p2.__proto__) //Person.prototype
console.log(p2.__proto__.__proto__) //Object.prototype
console.log(p2.__proto__.__proto__.__proto__) // null
console.log(p2.__proto__.__proto__.__proto__.__proto__)//null 前面没有了,报错
console.log(p2.__proto__.__proto__.__proto__.__proto__.__proto__)//null 前面没有了,报错
console.log(p2.constructor)//Person
console.log(p2.prototype)//undefined p2 是实例,没有 prototype 属性
console.log(Person.constructor)//Function 一个空函数
console.log(Person.prototype)// 打印出 Person.prototype 这个对象里所有的办法和属性
console.log(Person.prototype.constructor)//Person
console.log(Person.prototype.__proto__)// Object.prototype
console.log(Person.__proto__) //Function.prototype
console.log(Function.prototype.__proto__)//Object.prototype
console.log(Function.__proto__)//Function.prototype
console.log(Object.__proto__)//Function.prototype
console.log(Object.prototype.__proto__)//null

这道义题目考查原型、原型链的根底,记住就能够了。

代码输入后果

async function async1 () {console.log('async1 start');
  await new Promise(resolve => {console.log('promise1')
  })
  console.log('async1 success');
  return 'async1 end'
}
console.log('srcipt start')
async1().then(res => console.log(res))
console.log('srcipt end')

输入后果如下:

script start
async1 start
promise1
script end

这里须要留神的是在 async1await前面的 Promise 是没有返回值的,也就是它的状态始终是 pending 状态,所以在 await 之后的内容是不会执行的,包含 async1 前面的 .then

代码输入后果

function foo() {console.log( this.a);
}

function doFoo() {foo();
}

var obj = {
  a: 1,
  doFoo: doFoo
};

var a = 2; 
obj.doFoo()

输入后果:2

在 Javascript 中,this 指向函数执行时的以后对象。在执行 foo 的时候,执行环境就是 doFoo 函数,执行环境为全局。所以,foo 中的 this 是指向 window 的,所以会打印出 2。

setInterval 模仿 setTimeout

形容 :应用setInterval 模仿实现 setTimeout 的性能。

思路 setTimeout 的个性是在指定的工夫内只执行一次,咱们只有在 setInterval 外部执行 callback 之后,把定时器关掉即可。

实现

const mySetTimeout = (fn, time) => {
    let timer = null;
    timer = setInterval(() => {
        // 敞开定时器,保障只执行一次 fn,也就达到了 setTimeout 的成果了
        clearInterval(timer);
        fn();}, time);
    // 返回用于敞开定时器的办法
    return () => clearInterval(timer);
}

// 测试
const cancel = mySetTimeout(() => {console.log(1);
}, 1000);  
// 一秒后打印 1

说一下 vue3.0 你理解多少?

 <!-- 响应式原理的扭转 Vue3.x 应用 Proxy 取代 Vue2.x 版本的 Object.defineProperty -->
 <!-- 组件选项申明形式 Vue3.x 应用 Composition API setup 是 Vue3.x 新增的一个选项,他
    是组件内应用 Composition API 的入口 -->
 <!-- 模板语法变动 slot 具名插槽语法 自定义指令 v-model 降级 -->
 <!-- 其它方面的更改 Suspense 反对 Fragment(多个根节点) 和 Protal (在 dom 其余局部渲染组建内容)组件
     针对一些非凡的场景做了解决。基于 treeshaking 优化,提供了更多的内置性能。-->

代码输入后果

function runAsync (x) {const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000))
    return p
}

Promise.all([runAsync(1), runAsync(2), runAsync(3)]).then(res => console.log(res))

输入后果如下:

1
2
3
[1, 2, 3]

首先,定义了一个 Promise,来异步执行函数 runAsync,该函数传入一个值 x,而后距离一秒后打印出这个 x。

之后再应用 Promise.all 来执行这个函数,执行的时候,看到一秒之后输入了 1,2,3,同时输入了数组[1, 2, 3],三个函数是同步执行的,并且在一个回调函数中返回了所有的后果。并且后果和函数的执行程序是统一的。

Promise.race

形容 :只有promises 中有一个率先扭转状态,就返回这个率先扭转的 Promise 实例的返回值。

实现

Promise.race = function(promises){return new Promise((resolve, reject) => {if(Array.isArray(promises)) {if(promises.length === 0) return resolve(promises);
            promises.forEach((item) => {Promise.resolve(item).then(value => resolve(value), 
                    reason => reject(reason)
                );
            })
        }
        else return reject(new TypeError("Argument is not iterable"));
    });
}

异步任务调度器

形容:实现一个带并发限度的异步调度器 Scheduler,保障同时运行的工作最多有 limit 个。

实现

class Scheduler {queue = [];  // 用队列保留正在执行的工作
    runCount = 0;  // 计数正在执行的工作个数
    constructor(limit) {this.maxCount = limit;  // 容许并发的最大个数}
    add(time, data){const promiseCreator = () => {return new Promise((resolve, reject) => {setTimeout(() => {console.log(data);
                    resolve();}, time);
            });
        }
        this.queue.push(promiseCreator);
        // 每次增加的时候都会尝试去执行工作
        this.request();}
    request() {
        // 队列中还有工作才会被执行
        if(this.queue.length && this.runCount < this.maxCount) {
            this.runCount++;
            // 执行先退出队列的函数
            this.queue.shift()().then(() => {
                this.runCount--;
                // 尝试进行下一次工作
                this.request();});
        }
    }
}

// 测试
const scheduler = new Scheduler(2);
const addTask = (time, data) => {scheduler.add(time, data);
}

addTask(1000, '1');
addTask(500, '2');
addTask(300, '3');
addTask(400, '4');
// 输入后果 2 3 1 4

说一下常见的检测数据类型的几种形式?

typeof  其中数组、对象、null 都会被判断为 Object,其余判断都正确

instanceof 只能判断援用数据类型, 不能判断根本数据类型

constructor 它有 2 个作用 一是判断数据的类型,二是对象实例通过 constructor 对象拜访它的构造函数。须要留神的事件是如果创立一个对象来扭转它的原型,constructor 就不能来判断数据类型了

Object.prototype.toString.call()

Number() 的存储空间是多大?如果后盾发送了一个超过最大本人的数字怎么办

Math.pow(2, 53),53 为有效数字,会产生截断,等于 JS 能反对的最大数字。

Promise.allSettled

形容 :等到所有promise 都返回后果,就返回一个 promise 实例。

实现

Promise.allSettled = function(promises) {return new Promise((resolve, reject) => {if(Array.isArray(promises)) {if(promises.length === 0) return resolve(promises);
            let result = [];
            let count = 0;
            promises.forEach((item, index) => {Promise.resolve(item).then(
                    value => {
                        count++;
                        result[index] = {
                            status: 'fulfilled',
                            value: value
                        };
                        if(count === promises.length) resolve(result);
                    }, 
                    reason => {
                        count++;
                        result[index] = {
                            status: 'rejected'.
                            reason: reason
                        };
                        if(count === promises.length) resolve(result);
                    }
                );
            });
        }
        else return reject(new TypeError("Argument is not iterable"));
    });
}

Object.is 实现

题目形容:

Object.is 不会转换被比拟的两个值的类型,这点和 === 更为类似,他们之间也存在一些区别。1. NaN 在 === 中是不相等的,而在 Object.is 中是相等的
    2. + 0 和 - 0 在 === 中是相等的,而在 Object.is 中是不相等的

实现代码如下:

Object.is = function (x, y) {if (x === y) {
    // 当前情况下,只有一种状况是非凡的,即 +0 -0
    // 如果 x !== 0,则返回 true
    // 如果 x === 0,则须要判断 + 0 和 -0,则能够间接应用 1/+0 === Infinity 和 1/-0 === -Infinity 来进行判断
    return x !== 0 || 1 / x === 1 / y;
  }

  // x !== y 的状况下,只须要判断是否为 NaN,如果 x!==x,则阐明 x 是 NaN,同理 y 也一样
  // x 和 y 同时为 NaN 时,返回 true
  return x !== x && y !== y;
};

大数相加

题目形容: 实现一个 add 办法实现两个大数相加

let a = "9007199254740991";
let b = "1234567899999999999";

function add(a ,b){//...}

实现代码如下:

function add(a ,b){
   // 取两个数字的最大长度
   let maxLength = Math.max(a.length, b.length);
   // 用 0 去补齐长度
   a = a.padStart(maxLength , 0);//"0009007199254740991"
   b = b.padStart(maxLength , 0);//"1234567899999999999"
   // 定义加法过程中须要用到的变量
   let t = 0;
   let f = 0;   //"进位"
   let sum = "";
   for(let i=maxLength-1 ; i>=0 ; i--){t = parseInt(a[i]) + parseInt(b[i]) + f;
      f = Math.floor(t/10);
      sum = t%10 + sum;
   }
   if(f!==0){sum = '' + f + sum;}
   return sum;
}

正文完
 0