手写JavaScript函数式编程和异步编程底层代码

1.call实现

Function.prototype.$call = function(context, ...args) {
    // 调用者检查
    if(typeof this !== "function")
        throw new TypeError("必须使用函数调用$call方法")

    // 上下文检查
    context = context || globalThis
    context = context instanceof Object ? context : new Object(context)

    // 给上下文添加一个属性
    let property = Symbol("property")

    // 属性不可迭代
    Object.defineProperty(context, property, {
        enumerable: false,
        value: this
    })

    // 绑定后执行
    let res = context[property](...args)
    delete context[property]
    return res
}

// 方案二:采用反射对象的思路
Function.prototype.$call = function(context, ...args) {
    return new Proxy(this, {
        apply(target, thisArg, argArray) {
            return Reflect.apply(target, context, args)
        }
    })(...args)
}

// 方案三:采用eval函数参数是字符串,并且可以把字符串中this替换成绑定对象的思路
Function.prototype.$call = function(context, ...args) {
    // 检查调用对象
    if(typeof this !== "function")
        throw new TypeError("必须使用函数调用")

    // 检查上下文对象null和undefined
    context = context || globalThis
    // 检查上下文对象是否为对象
    context = context instanceof Object ? context : Object(context)

    // 替换this为绑定对象
    let func = this.toString().replace(/this/g, "context")

    // eval执行
    return eval(`(${func})(${args})`)
}

2.apply实现

// 方案一:使用绑定this中“函数被对象调用,this指向对象”的思路
Function.prototype.$apply = function(context, arg) {
    // 调用者检查
    if(typeof this !== "function")
        throw new TypeError("必须使用函数调用$apply方法")

    // 检查上下文null和undefined
    context = context || globalThis
    // 检查上下文是否是对象
    context = context instanceof Object ? context : new Object(context)

    // 给上下文对象准备添加一个属性
    let property = Symbol("property")

    // 属性不可迭代
    Object.defineProperty(context, property, {
        enumerable: false,
        value: this
    })

    // 绑定后执行
    let res = context[property](arg)
    delete context[property]
    return res
}

// 方案二:采用反射对象来实现
Function.prototype.$apply = function(context, arg) {
    return new Proxy(this, {
        apply(target, thisArg, argArray) {
            return Reflect.apply(target, context, arg)
        }
    })(arg)
}

// 方案三:采用eval函数参数是字符串,并且可以把字符串中this替换成绑定对象的思路
Function.prototype.$apply = function(context, arg) {
    if(typeof this !== "function")
        throw new TypeError("必须使用函数调用")

    context = context || globalThis
    context = context instanceof Object ? context : Object(context)

    // 替换this为绑定对象
    let func = this.toString().replace(/this/g, "context")

    // ${arg}会自动展开数组
    return eval(`(${func})(${arg})`)
}

3.bind实现

Function.prototype.$bind = function(context, ...args) {
    // 检查调用者,当出现错误时,可控地抛出TypeError
    if(typeof this !== "function")
        throw new TypeError("必须使用函数调用$bind方法")

    let that = this
    return function Func(...arg) {
        // 考虑如果构造函数经过bind绑定后又作为构造函数使用的情况,此时bind绑定会失效
        return that.call(this instanceof Func ? this: context, ...[...args, ...arg])
    }
}

4.函数柯里化实现

function curry(func, ...args) {
   if(args.length === func.length)
      return func(...args)
   // 利用闭包性质给拆分函数传值
   return function(arg) {
      return curry(func, ...[...args, arg])
   }
}

5.偏函数实现

function curry(func, ...args) {
   if(args.length === func.length)
      return func(...args)
   // 偏函数不要求每一个拆分函数都只有一个参数 
   return function(...arg) {
      return curry(func, ...[...args, ...arg])
   }
}

6.记忆化函数实现

// 使用高阶函数实现记忆化函数
function memorize(func) {
    let map = new Map()
    return function(...args) {
        let code = args.join("")
        if(map.has(code))
            return map.get(code)
        else {
            map.set(code, func(...args))
            return map.get(code)
        }
    }
}

// 递归记忆,递归路径上的值全部记忆
let f = memorize(function(n) {
    if(n < 2)
        return n
    return f(n - 1) + f(n - 2)
})

7.Promise A+实现

class VPromise {
  static PENDING = "pending";
  static FULFILLED = "fulfilled";
  static REJECTED = "rejected";

  static REJECT_ERROR = "can't reject yourself";
  static RESOLVE_ERROR = "can't resolve yourself";
  static STATUS_ERROR = "wrong status change";

  #status = VPromise.PENDING;
  #value;
  #reason;

  #fulfilledCallbacks = [];
  #rejectedCallbacks = [];

  constructor(func) {
    try {
      typeof func === "function" &&
        func.call(this, this.#resolve.bind(this), this.#reject.bind(this));
    } catch (err) {
      this.#reject(err);
    }
  }

  #resolve(value) {
    if (this.#status !== VPromise.PENDING) return;
    if (value === this) throw new TypeError(VPromise.RESOLVE_ERROR);
    if (value instanceof VPromise) {
      value.then(
        (res) => this.#resolve(res),
        (err) => this.#reject(err)
      );
    } else {
      this.#value = value;
      this.#status = VPromise.FULFILLED;
      (Array.isArray(this.#fulfilledCallbacks)
        ? this.#fulfilledCallbacks
        : []
      ).forEach((func) => {
        typeof func === "function" && func(this.#value);
      });
    }
  }

  #reject(reason) {
    if (this.#status !== VPromise.PENDING) return;
    if (reason === this) throw new TypeError(VPromise.REJECT_ERROR);
    if (reason instanceof VPromise) {
      reason.then(
        (res) => this.#reject(res),
        (err) => this.#reject(err)
      );
    } else {
      this.#reason = reason;
      this.#status = VPromise.REJECTED;
      (Array.isArray(this.#rejectedCallbacks)
        ? this.#rejectedCallbacks
        : []
      ).forEach((func) => {
        typeof func === "function" && func(this.#reason);
      });
    }
  }

  then(onFulfilledCallback, onRejectedCallback) {
    const forMatFulfilledCallback =
      typeof onFulfilledCallback === "function"
        ? onFulfilledCallback
        : (value) => value;
    const forMatRejectedCallback =
      typeof onRejectedCallback === "function"
        ? onRejectedCallback
        : (reason) => reason;

    return new VPromise((resolve, reject) => {
      if (this.#status === VPromise.PENDING) {
        const fulfilledCallbacks = Array.isArray(this.#fulfilledCallbacks)
          ? this.#fulfilledCallbacks
          : [];
        fulfilledCallbacks.push((value) => {
          try {
            resolve(forMatFulfilledCallback(value));
          } catch (err) {
            reject(err);
          }
        });
        this.#fulfilledCallbacks = fulfilledCallbacks;

        const rejectedCallbacks = Array.isArray(this.#rejectedCallbacks)
          ? this.#rejectedCallbacks
          : [];
        rejectedCallbacks.push((reason) => {
          try {
            reject(forMatRejectedCallback(reason));
          } catch (err) {
            reject(err);
          }
        });
        this.#rejectedCallbacks = rejectedCallbacks;
      } else if (this.#status === VPromise.FULFILLED) {
        queueMicrotask(() => {
          try {
            resolve(forMatFulfilledCallback(this.#value));
          } catch (err) {
            reject(err);
          }
        });
      } else if (this.#status === VPromise.REJECTED) {
        queueMicrotask(() => {
          try {
            reject(forMatRejectedCallback(this.#reason));
          } catch (err) {
            reject(err);
          }
        });
      } else {
        throw new Error(VPromise.STATUS_ERROR);
      }
    });
  }

  catch(onCatchCallback) {
    return this.then(
      null,
      (reason) =>
        typeof onCatchCallback === "function" && onCatchCallback(reason)
    );
  }

  finally(onFianllyCallback) {
    return this.then(
      (value) => {
        typeof onFianllyCallback === "function" && onFianllyCallback(value);
        return value;
      },
      (reason) => {
        typeof onFianllyCallback === "function" && onFianllyCallback(reason);
        throw new Error(reason);
      }
    );
  }

  static all(promiseList) {
    return new VPromise((resolve, reject) => {
      const result = [];
      (Array.isArray(promiseList) ? promiseList : []).forEach(
        (promise, index) => {
          if (promise instanceof VPromise) {
            promise.then((value) => {
              result[index] = value;
              result.length === promiseList.length && resolve(result);
            }, reject);
          } else {
            result[index] = promise;
            result.length === promiseList.length && resolve(result);
          }
        }
      );
    });
  }

  static allSettled(promiseList) {
    return new VPromise((resolve) => {
      const result = [];
      (Array.isArray(promiseList) ? promiseList : []).forEach(
        (promise, index) => {
          if (promise instanceof VPromise) {
            promise
              .then(
                (value) => {
                  result[index] = {
                    status: VPromise.FULFILLED,
                    value,
                  };
                },
                (reason) => {
                  result[index] = {
                    status: VPromise.REJECTED,
                    reason,
                  };
                }
              )
              .then(
                () => result.length === promiseList.length && resolve(result)
              );
          } else {
            result[index] = {
              status: VPromise.FULFILLED,
              value: promise,
            };
            result.length === promiseList.length && resolve(result);
          }
        }
      );
    });
  }

  static race(promiseList) {
    return new VPromise((resolve, reject) => {
      (Array.isArray(promiseList) ? promiseList : []).forEach(
        (promise) =>
          promise instanceof VPromise && promise.then(resolve, reject)
      );
    });
  }

  static any(promiseList) {
    return new VPromise((resolve, reject) => {
      const result = [];
      (Array.isArray(promiseList) ? promiseList : []).forEach(
        (promise, index) => {
          if (promise instanceof VPromise) {
            promise.then(resolve, (reason) => {
              result[index] = reason;
              result.length === promiseList.length && reject(result);
            });
          }
        }
      );
    });
  }

  static withResolvers() {
    let resolve;
    let reject;
    const promise = new VPromise((res, rej) => {
      resolve = res;
      reject = rej;
    });
    return { promise, resolve, reject };
  }
}

8.Promise的all,allSettled,any,race,iterate实现

// 静态方法all的实现
Promise.all = function(ar) {
    if(ar && typeof ar[Symbol.iterator] !== "function")
        throw new TypeError("all方法的参数必须是可迭代对象")

    return new Promise((resolve, reject) => {
        let cnt = 0
        let ps = []
        // 下面使用数组的快捷api进行遍历,所以这里将可迭代对象转化为数组
        ar = [...ar]
        // 如果是一个空的可迭代对象,那么立即返回一个以空数组兑现的Promise对象
        if(ar.length === 0)
            resolve([])
        ar.forEach((p, index) => {
            if(p instanceof Promise) {
                p.then(res => {
                    ps[index] = res
                    if(++ cnt === ar.length)
                        resolve(ps)
                }, err => {
                    reject(err)
                })
            } else {
                // 考虑数组中非Promise的元素
                ps[index] = p
                if(++ cnt === ar.length)
                    resolve(ps)
            }
        })
    })
}

// 静态方法allSettled的实现
Promise.allSettled = function(ar) {
    if(ar && typeof ar[Symbol.iterator] !== "function")
        throw new TypeError("allSettled参数必须是可迭代对象")
    return new Promise(resolve => {
        let cnt = 0
        let ps = []
        // 将可迭代对象ar转化为数组
        ar = [...ar]
        // 如果是一个空的可迭代对象,那么立即返回一个以空数组兑现的Promise对象
        if(ar.length === 0)
            resolve([])
        ar.forEach((el, index) => {
            if(el instanceof Promise) {
                el.then(res => {
                    ps[index] = { status: "fulfilled", value: res }
                    if(++ cnt === ar.length)
                        resolve(ps)
                }, err => {
                    ps[index] = { status: "rejected", reason: err }
                    if(++ cnt === ar.length)
                        resolve(ps)
                })
            } else {
                ps[index] = { status: "fulfilled", value: el }
                if(++ cnt === ar.length)
                    resolve(ps)
            }
        })
    })
}

// 静态方法any的实现
Promise.any = function(ar) {
    if(ar && typeof ar[Symbol.iterator] !== "function")
        throw new TypeError("any方法的参数必须是可迭代对象")

    return new Promise((resolve, reject) => {
        ar = [...ar]
        // Promise规范说明any方法中需要考虑length
        if(ar.length === 0) {
            reject("All Promises are rejected")
        }

        // 不同于all和race方法,any方法返回第一个兑现的Promise对象
        ar.forEach(p => {
            if(p instanceof Promise)
                p.then(resolve)
            else
                resolve(p)
        })

        // 如果所有Promise都被拒绝,那么该返回期约也会被拒绝。由于Promise状态机状态不可逆转,因此不用设置计数器判断期约是否全部被拒绝
        reject("All Promises are rejected")
    })
}

// 静态方法race的实现
Promsie.race = function(ar) {
    if(ar && typeof ar[Symbol.iterator] !== "function")
        throw new TypeError("race方法的参数必须是可迭代对象")

    return new Promise((resolve, reject) => {
        // 将可迭代对象转化为数组
        ar = [...ar]
        // 在Promise规范中没有说明race需要考虑ar是空迭代对象的情况
        ar.forEach(el => {
            if(el instanceof Promise) {
                el.then(resolve, reject)
            } else
                resolve(el)
        })
    })
}

// 静态方法iterate的实现(线性执行期约,JavaScript权威指南中提到)
Promise.iterate = function(ar) {
    if(ar && typeof ar[Symbol.iterator] !== "function")
        throw new TypeError("iterate方法的参数必须是可迭代对象")

    let promise = new Promise(res => res())
    ar = [...ar]
    ar.forEach(el => {
        promise = promise.then(() => el)
    })
    return promise
}

9.迭代器生成和遍历的实现

// 以1000以内的斐波那契数列为例
function fib(n) {
    let a = 0, b = 1, cnt = 0
    return {
        [Symbol.iterator]() {
            return this
        },
        next() {
            if(++ cnt === n + 1)
                return { done: true, value: undefined }
            else {
                [a, b] = [b, a + b]
                return { done: false, value: a }
            }
        }
    }
}

let f = fib(100)
for(let iter = f.next(); !iter.done; iter = f.next()) 
    if(iter.value > 1000)
        break
    else
        console.log(iter.value)

10.生成器生成和遍历的实现

// 以1000以内的斐波那契数列为例
function *fib(n) {
    let a = 0, b = 1
    for(let i = 0; i < n; i ++) {
        [a, b] = [b, a + b]
        yield a
    }
}

let f = fib(100)
for(let iter = f.next(); !iter.done; iter = f.next())
    if(iter.value > 1000)
        break
    else
        console.log(iter.value)

11.异步迭代器生成和遍历的实现

function asyncIterator(ar) {
    if(ar && typeof ar[Symbol.iterator] !== "function")
        throw new TypeError("参数必须是可迭代对象")
    let cnt = 0

    return {
        [Symbol.asyncIterator]() {
            return this
        },
        next() {
            // 异步迭代器的返回值一定是一个promise对象,兑现值或拒绝值是迭代器的返回值{done, value}
            if(cnt === ar.length)
                return new Promise(res => res({ done: true, value: undefined }))
            else if(ar[cnt] instanceof Promise)
                return ar[cnt ++].then(res => ({ done: false, value: res }), err => ({ done: false, value: err }))
            else
                return new Promise(res => res({ done: false, value: ar[cnt ++]}))
        }
    }
}

// 异步迭代器不只能处理promise对象
let ar = [new Promise(res => {
    setTimeout(() => {
        res("p1")
    }, 3000)
}), new Promise((res, rej) => {
    setTimeout(() => {
        rej("p2")
    }, 1000)
}), 1, 2, 3, "Danny"];

// 遍历异步迭代器,模仿for await
(function asyncAuto(asyncIterator) {
    let iter = asyncIterator.next();
    (function next() {
        iter.then(res => {
            if(!res.done) {
                console.log(res)
                iter = asyncIterator.next()
                next()
            }
        })
    })();
})(asyncIterator(ar))

12.async和await的实现

// 把function *看做是async,把yield看做是awaits
function *generator() {
    yield new Promise(res => res("p1"))
    yield 1
    yield new Promise((res, rej) => rej("p2"))
    yield "Danny"
}

(function generatorAuto(generator) {
    let iter = generator.next();
    (function next() {
        // 如果await后面的值是promise对象
        if(iter.value instanceof Promise)
            iter.value.then(res => {
                console.log(res)
                iter = generator.next()
                next()
            }, err => {
                console.log(err)
                iter = generator.next()
                next()
            })
        // 如果await后面的值不是promise对象
        else if(!iter.done) {
            console.log(iter.value)
            iter = generator.next()
            next()
        }
    })()
})(generator())
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vanghua

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值