Skip to content

手写实现 js 方法 ​

promise ​

javascript
// 先定义三个常量表示状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

// 新建 myPromise 类
class myPromise {
  constructor(executor) {
    // 储存状态的变量,初始值是 pending
    this.status = PENDING;

    // 成功之后的值
    this.value = null;
    // 失败之后的原因
    this.reason = null;

    // 更改成功后的状态
    this.resolve = (value) => {
      if (this.status === PENDING) {
        this.status = FULFILLED; // 修改状态
        this.value = value; // 保存成功后的值
        // 判断 并 执行回调函数
        while (this.onFulfilledCallback.length) {
          this.onFulfilledCallback.shift()(value);
        }
      }
    };
    // 更改失败后的状态
    this.reject = (reason) => {
      if (this.status === PENDING) {
        this.status = REJECTED; // 修改状态
        this.reason = reason; // 保存失败后的原因
        // 判断 并 执行回调函数
        while (this.onRejectedCallback.length) {
          this.onRejectedCallback.shift()(reason);
        }
      }
    };

    // 存储成功回调函数
    this.onFulfilledCallback = [];
    // 存储失败回调函数
    this.onRejectedCallback = [];

    try {
      // executor 是一个执行器,进入会立即执行
      // 并传入resolve和reject方法
      executor(this.resolve, this.reject);
    } catch (error) {
      this.reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    // if (this.status === FULFILLED) {
    //   onFulfilled(this.value);
    // } else if (this.status === REJECTED) {
    //   onRejected(this.reason);
    // } else if (this.status === PENDING) {
    //   // 等到执行成功失败函数的时候再传递
    //   this.onFulfilledCallback.push(onFulfilled);
    //   this.onRejectedCallback.push(onRejected);
    // }

    // 如果不传,就使用默认函数
    const realOnFulfilled =
      typeof onFulfilled === "function" ? onFulfilled : (value) => value;
    const realOnRejected =
      typeof onRejected === "function"
        ? onRejected
        : (reason) => {
            throw reason;
          };

    // then 链式调用
    const promise2 = new myPromise((resolve, reject) => {
      const fulfilledMicrotask = () => {
        // 创建一个微任务等待 promise2 完成初始化
        queueMicrotask(() => {
          try {
            // 获取成功回调函数的执行结果
            const x = realOnFulfilled(this.value);
            // 传入 resolvePromise 集中处理
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        });
      };

      const rejectedMicrotask = () => {
        // 创建一个微任务等待 promise2 完成初始化
        queueMicrotask(() => {
          try {
            // 调用失败回调,并且把原因返回
            const x = realOnRejected(this.reason);
            // 传入 resolvePromise 集中处理
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        });
      };
      // 判断状态
      if (this.status === FULFILLED) {
        fulfilledMicrotask();
      } else if (this.status === REJECTED) {
        rejectedMicrotask();
      } else if (this.status === PENDING) {
        // 等待
        // 因为不知道后面状态的变化情况,所以将成功回调和失败回调存储起来
        // 等到执行成功失败函数的时候再传递
        this.onFulfilledCallback.push(fulfilledMicrotask);
        this.onRejectedCallback.push(rejectedMicrotask);
      }
    });
    return promise2;
  }

  all(promises) {
    if (!Array.isArray(promises)) {
      throw new Error("promises must to be an array!!!");
    }
    return new myPromise(function (resolve, reject) {
      let promiseNum = promises.length;
      let resolvedCount = 0;
      let resolveValues = new Array(promiseNum);
      try {
        for (let i = 0; i < promiseNum; i++) {
          promises[i].then(function (value) {
            resolveValues[i] = value;
            if (++resolvedCount === promiseNum) {
              resolve(resolveValues);
            }
          });
        }
      } catch (error) {
        reject(error);
      }
    });
  }

  race(promises) {
    if (!Array.isArray(promises)) {
      throw new Error("promises must be an array!!!");
    }
    let resolved = false;
    return new myPromise(function (resolve, reject) {
      try {
        promises.forEach((p) =>
          p.then((data) => {
            if (!resolved) {
              resolved = true;
              resolve(data);
            }
          })
        );
      } catch (error) {
        reject(error);
      }
    });
  }
}

function resolvePromise(promise2, x, resolve, reject) {
  // 如果相等了,说明return的是自己,抛出类型错误并返回
  if (promise2 === x) {
    return reject(
      new TypeError("Chaining cycle detected for promise #<Promise>")
    );
  }

  // 判断x是不是 myPromise 实例对象
  if (x instanceof myPromise) {
    // 执行 x,调用 then 方法,目的是将其状态变为 fulfilled 或者 rejected
    // x.then(value => resolve(value), reason => reject(reason))
    // 简化之后
    x.then(resolve, reject);
  } else {
    // 普通值
    resolve(x);
  }
}

// 导出
// export default myPromise;

call apply bind ​

javascript

let Person = {
  name: "Tom",
  say(a, b) {
    this.a = a;
    this.b = b;
    console.log(this);
    console.log(`我叫${this.name}, a: ${this.a}, b: ${this.b}`);
  }
};



// ----------------------------------------------------------------------------
/**
 * call
 * @param {*} ctx
 * 1.ctx 存在就使用 ctx window
 * 2.使用 Object(ctx) 将 ctx 转换成对象,并通过 ctx.fn 将 this 指向 ctx
 * 3.循环参数,注意从 1 开始,第 0 个是上下文,后面才是我们需要的参数
 * 4.将参数字符串 push 进 args
 * 5.拿到结果返回前,删除掉 fn
 */
/* eslint-disable */
Function.prototype.myCall = function (ctx) {
  ctx = ctx || window;
  const fn = Symbol(); //  Symbol属性来确定fn唯一。
  const args = [...arguments].slice(1);
  // console.log(this);
  ctx[fn] = this; // this 是调用 call 的函数 f say() {}
  const result = ctx[fn](...args);
  delete ctx[fn];
  return result;
};
// ----------------------------------------------------------------------------
let PersonA = {
  name: "Tom A"
};
Person.say.myCall(PersonA, "A1", "A2");



// ----------------------------------------------------------------------------
/**
 * apply
 * @param {*} ctx
 * @param {*} args
 * 1.apply 无需循环参数列表,传入的 args 就是数组
 * 2.但是 args 是可选参数,如果不传入的话,直接执行
 */
/* eslint-disable */
Function.prototype.myApply = function (ctx, args) {
  ctx = ctx || window;
  const fn = Symbol(); //  Symbol属性来确定fn唯一。
  ctx[fn] = this; // this 是调用 call 的函数 f say() {}
  let result;
  if (!args) {
    // 判断 args 是否存在
    result = ctx[fn]();
  } else {
    result = ctx[fn](...args);
  }
  delete ctx[fn];
  return result;
};
// ----------------------------------------------------------------------------

let PersonB = {
  name: "Tom B"
};
Person.say.myApply(PersonB, ["B1", "B2"]);



// ----------------------------------------------------------------------------
/**
 * bind
 * 1. 改变this指向
 * 2. 接受参数列表、
 * 3. return 一个函数
 * 4. 遇到new这样优先级高于bind方法的时候,bind改变this指向会无效。
 */
/* eslint-disable */
Function.prototype.myBind = function (ctx) {
  var self = this; // 因为之后要return一个函数,这里保存一下this防止混乱
  var args = Array.prototype.slice.call(arguments, 1); // 获取参数
  var fb = function () {
    var bindArgs = Array.prototype.slice.call(arguments);
    const target = this instanceof fb ? this : ctx;
    return self.apply(target, args.concat(bindArgs));
  };
  var fn = function () {};
  fn.prototype = this.prototype; // 让实例可以继承原型
  fb.prototype = new fn();
  return fb;
};
// ----------------------------------------------------------------------------
let PersonC = {
  name: "Tom C"
};
const fnC = Person.say.myBind(PersonC, "C1");
fnC("C2");

New ​

javascript
/**
 * new
 * 1.Constructor 就是 new 时传入的第一个参数,剩余的 arguments 是其他的参数
 * 2.使用obj.__proto__ = Constructor.prototype 继承原型上的方法
 * 3.将剩余的 arguments 传给 Constructor ,绑定 this 指向为 obj,并执行
 * 4.如果构造函数返回的是引用类型,直接返回该引用类型,否则返回 obj
 */
const myNew = function () {
  let Constructor = Array.prototype.shift.call(arguments);
  let obj = new Object();
  obj.__proto__ = Constructor.prototype;
  // console.log(Constructor, obj);
  let res = Constructor.apply(obj, arguments);
  return res instanceof Object ? res : obj;
};

function fun(a, b) {
  this.a = a;
  this.b = b;
  this.c = function () {
    console.log(this.a, this.b);
    return this;
  };
}

const test = myNew(fun, "A", "B");
console.log(test.c());