经典手写题目
实现Promise,以及它的各种api
基础版Promise --excutor是同步的情况
class myPromise {
constructor(excutor) {
this.init();
// excutor 有两个参数
try {
// 3.绑定this
excutor(this.resolve.bind(this), this.reject.bind(this)); // excutor是Priomise本身的reolve等函数
} catch (e) {
this.reject(e)
}
}
resolve(value) {
console.log("excuting resolve functiom ")
if (this.status === 'pending') {
this.status = 'fullfiled'
this.value = value;
console.log("resovle:",this.status,this.value)
}
}
reject(value) {
if (this.status === 'pending') {
this.status = 'reject';
this.value = value;
}
}
init() {
this.status = "pending";
this.value = undefined;
}
then(onFulFilled,onReject){
if(this.status==="fullfiled"){
onFulFilled(this.value)
}
if(this.status==="reject"){
onReject(this.value)
}
}
}
let p = new myPromise((resolve,reject)=>{
console.log("start")
resolve("ok")}
).then(res=>{
console.log("onFulFilled",res)
})
实现new,对new过程的理解
new的过程,实际上是创建了一个新的对象,然后这个对象执行了构造函数。
function myNew(fun){
let args=[...arguments];
let obj={}; // 这就是为啥构造函数里面总是this.xxx=xxx;
obj.__proto__=fun.prototype;
let tmpObj=fun.apply(obj,args);
return tmpObj instanceof Object?tmpObj:obj;
}
function test(){
this.name='name';
// return {
// age:'age'
// }
}
let t= myNew(test);
console.log(t)
实现async/await-异步方法怎么同步执行
思路是借助es6的generator实现同步等待,难点在,自动化遍历执行完所有状态。
- generator是什么,以及特点
- 思路:假设需要按顺序执行a1,a2,…,an的异步方法,只需要,将他们声明成generator函数里的状态即可,然后通过next,不断去调。
console.clear()
// 产生异步函数
function getAsync() {
return function(...args) {
return new Promise((resolve,reject)=>{
console.log("excute",...args);
setTimeout(()=>{
console.log("resolve",...args);
resolve(...args)
}, Math.random() * 1000)
}
)
}
}
// 定义两个异步函数
let a1 = getAsync();
let a2 = getAsync();
// 声明异步函数,同步执行的顺序
function* generator(apis) {
let i=0;
for (let api of apis) {
i++;
yield api(i);
}
}
// 自动化执行函数
function myAsync(generator) {
return new Promise((resolve,reject)=>{
let ge = generator;
let args = [...arguments];
// 获取generator中的状态
let next = function(...args) {// args是上一个状态的返回值
let result = ge.next(...args);// 执行当前yeild
if (result.done){ // 结束
return resolve("all done")
}
// 难点:等当前状态返回后,触发下一次
result.value.then(res=>{ // 获取当前状态的返回值,本题中,result.value是一个promise对象,通过then获取当前状态的返回值。
// 取出本次的结果,当做参数
next(res);
}
);
}
next()
}
)
}
// main
let gen = generator([a1, a2]);
myAsync(gen).then(res=>{
console.log(res) // 输出end
})
难点
- 借助generator函数
- 怎么触发下一次函数?
- next不会阻塞主线程!
- 需要等待上一次的结果返回(then中触发下一次)
- 怎么结束? done
手写call apply bind
call和bind的区别就是,参数传入不同。两者都会立刻执行
fun.call(this,…args);
fun.apply(this,[…agrs]);
bind返回的是一个函数,不会立刻执行。
call
- 其实应该考虑没有传入context的情况,但面试考点一般不在这儿.所以,这里就直接写核心
Function.prototype.myCall=function(context){
let args=[...arguments].slice(1);
context.fn=this; // fn调用myCall,通过this获取fn
context.fn(...args)// 难点:要求执行fn的时候,this指向context;参数展开传入
delete context.fn;
}
apply
- 比起call,就注意一下参数而已
Function.prototype.myApply=function(context){
let args=[...arguments].slice(1); // 二维数组
let arr=args[0];
let fn=this;
context.fn=fn;
context.fn(...arr)
delete context.fn;
}
bind
Function.prototype.myBind=function(context){
// 1.返回的是函数
// 2.这个函数运行的时候,this指向context
// 3.可以多次传参
let arg1=[...arguments].slice(1);
let fn=this;
return function(...args){ // 你怎么保证不立刻执行?
return fn.apply(context,[...arg1,...args])
}
}