Skip to content

手写实现

Call, Apply, Bind

js
const obj = { x : '100px' };
Function.prototype.myCall = function(thisArg, ...args) {
    if (typeof this !== 'function') {
        throw new Error('需要被函数来Call');
    }
    // 如果thisArg为空,则挂载到全局上
    thisArg = (thisArg == null) ? globalThis : Object(thisArg);

    // 挂载函数到目标对象上
    const fnSym = Symbol('fn');
    thisArg[fnSym] = this;

    const result = thisArg[fnSym](...args);

    // 记得清理挂载
    delete thisArg[fnSym];

    return result;
}
function myFunc(x,y,z) {
    console.log(`x=${x},y=${y},z=${z}`);
    console.log(`this.x=${this.x}`);
    setTimeout(() => {
        console.log('延迟检查 this', {...this});
    }, 0);
}
console.log(myFunc.myCall(obj,1,2,3));


Function.prototype.myApply = function(thisArg, arrayParam) {
    if (typeof this !== 'function') {
        throw new Error('需要函数调用');
    }
    thisArg = (thisArg == null) ? globalThis : Object(thisArg);

    const fnSym = Symbol('fn');
    thisArg[fnSym] = this;

    let n = arrayParam?.length;
    let result = null;
    if (n===0) {
        result = thisArg[fnSym]();
    }
    let args = [];
    for(let i = 0; i<n ; i++) {
        args.push(arrayParam[i]);
    }

    result = thisArg[fnSym](...args);

    delete thisArg[fnSym];
    return result;
}

console.log(myFunc.myApply(obj,[1,2,3]));


Function.prototype.myBind = function(thisArg, ...args) {
    if (typeof this !== 'function') {
        throw new Error('需要函数调用');
    }
    // 获取需要绑定的函数
    const targetFn = this;

    const boundFn = function(...boundArgs) {
        const newThis = (this instanceof boundFn) ? this : thisArg;
        return targetFn.myApply(newThis, args.concat(boundArgs));
    }

    // 保持函数原型链
    if (targetFn.prototype) {
        boundFn.prototype = Object.create(targetFn.prototype);
    }
    return boundFn;
}

function fn(a, b, c, ...args) {
    console.log(`a=${a}, b=${b}, c=${c}`)
    setTimeout(() => {
        console.log('延迟检查 this', {...this});
    }, 0);
    return args
}
const newFn = fn.myBind(obj, 1, 2)
console.log(newFn(3,4,5))

Promise

js
class MyPromise {
    state = 'pending'   // 状态
    value = undefined   // 成功后的数值
    reason = undefined  // 失败的结果

    resolveCallbacks = []   // 保存成功的回调函数
    rejectCallbacks = []    // 保存失败的回调函数

    constructor(func) {

        // 外面定义MyPromise时,定义的函数内部最终运行resolve()的对应函数
        const resolveHandler = (value) => {

            if (this.state !== 'pending')
                return
            const resolveValue = (val)=>{
                queueMicrotask(()=>{
                    if(val instanceof MyPromise) {
                        val.then(v=>resolveValue(v),
                            (err)=>rejectHandler(err))
                    }else if(val && typeof val.then === 'function'){
                        val.then(resolveValue, rejectHandler)
                    }else {
                        this.state = 'fulfilled'
                        this.value = val
                        this.resolveCallbacks.forEach((fn)=>{queueMicrotask(fn)})
                    }
                })
            }
            resolveValue(value)

            // queueMicrotask(() => {
            //     if (this.state === 'pending') {
            //         this.state = 'fulfilled'
            //         this.value = value
            //         this.resolveCallbacks.forEach(fn => queueMicrotask(fn))
            //     }
            // })
            // if (this.state === 'pending') {
            //     this.state = 'fulfilled'
            //     this.value = value
            //     this.resolveCallbacks.forEach(fn => queueMicrotask(fn))
            // }
        }
        const rejectHandler = (reason) => {
            if (this.state === 'pending') {
                this.state = 'rejected'
                this.reason = reason
                this.value = reason
                this.rejectCallbacks.forEach(fn => queueMicrotask(fn))
            }
        }
        try {
            // 定义MyPromise时,传参的函数会立刻执行
            func(resolveHandler, rejectHandler)
        } catch (err) {
            rejectHandler(err)
        }

    }

    then(fn1, fn2) {
        fn1 = typeof fn1 === 'function' ? fn1 : (v) => v
        // 当没有fn2时,说明不是catch过来的,但如果后续走进了onReject流程,则需要让fn2继续抛出错误
        fn2 = typeof fn2 === 'function' ? fn2 : (e) => { throw e; }

        if (this.state === 'pending') {
            return new MyPromise((resolve, reject) => {
                // 存储起来,用于状态改变后then的调用
                this.resolveCallbacks.push(() => {
                    try {
                        const newValue = fn1(this.value)
                        resolve(newValue)
                    } catch (err) {
                        reject(err)
                    }
                })
                this.rejectCallbacks.push(() => {
                    try {
                        const newReason = fn2(this.reason)
                        // 只要fn2正常通过,则继续resolve流程
                        resolve(newReason)
                    } catch (err) {
                        reject(err)
                    }
                })
            })
        }

        if (this.state === 'fulfilled') {
            return new MyPromise((resolve, reject) => {
                try {
                    const newValue = fn1(this.value)
                    resolve(newValue)
                } catch (err) {
                    reject(err)
                }
            })
        }

        if (this.state === 'rejected') {
            return new MyPromise((resolve, reject) => {
                try {
                    const newReason = fn2(this.reason)
                    // 只要fn2正常通过,则继续resolve流程
                    resolve(newReason)
                } catch (err) {
                    reject(err)
                }
            })
        }

    }

    catch(fn) {
        return this.then((v) => v, fn)
    }
}

MyPromise.resolve = function (value) {
    return new MyPromise((resolve, reject) => resolve(value))
}
MyPromise.reject = function (reason) {
    return new MyPromise((resolve, reject) => reject(reason))
}
MyPromise.all = function (promiseList = []) {
    return new MyPromise((resolve, reject) => {
        const resultList = new Array(promiseList.length);
        if (promiseList.length === 0)
            resolve([])
        let count = 0;
        promiseList.forEach((p, index) => {
            p.then(data => {
                resultList[index] = data; // 按索引存储
                if (++count === promiseList.length)
                    resolve(resultList);
            }).catch(reject);
        });
    });
}
MyPromise.race = function (promiseList = []) {
    return new MyPromise((resolve, reject) => {
        let flag = true
        promiseList.forEach(p => {
            p.then(data => {
                if (flag) {
                    resolve(data)
                    flag = false
                }
            }).catch(err => {
                reject(err)
            })
        })
    })
}