JS API原理及实现


API

  1. new
  2. Promise.all
  3. Function.prototype.apply()
  4. 深拷贝

new

  • 以构造器的 prototype 属性为原型,创建新对象
  • 将 this 和调用参数传给构造器执行
  • 如果构造器没有手动返回对象,则返回第一步的对象
function new() {
    // 获取函数调用时的第一个参数,即为构造函数 fn
    const fn = Array.prototype.shift.call(arguments)
    if(typeof constructor !== 'function'){
        throw new TypeError(fn + ' is not a constructor')
    }
    // 以构造器的原型为原型,创建新对象
    const obj = Object.create(fn.prototype)
    fn.apply(obj, arguments)
    return obj
}

Promis.all

function myPromisAll(iterable) {
  let result = [];
  let fulfilledCount = 0;
  const promises = Array.from(iterable);
  return new Promise((resolve, reject) => {
    promises.forEach((prom, i) => {
      Promise.resolve(prom).then(
        (data) => {
          console.log(data, i);
          result[i] = data;
          fulfilledCount++;
          if (fulfilledCount === promises.length) {
            resolve(result);
          }
        },
        (reason) => {
          reject(reason);
        }
      );
    });
    if (promises.length === 0) {
      resolve(result);
    }
  });
}

Function.prototype.apply()

Function.prototype.myApply = function (targetObject, args = []) {
  // 判断调用对象是否为函数
  if (typeof this !== "function") {
    console.error("type error!");
  } // 判断绑定的对象
  if (targetObject === undefined || targetObject === null) {
    targetObject = window;
  } // 因为 apply(2)也有值,但是数字不能添加属性,所以用 Object包装
  targetObject = Object(targetObject); // 确保 targetFnKey唯一,防止覆盖掉原有的属性
  const targetFnkey = Symbol();
  targetObject.targetFnkey = this; // 将执行结果保存并返回
  let result = targetObject.targetFnkey(...args); // 删除暂时增加的属性
  delete targetObject.targetFnkey;
  return result;
};

深拷贝

这里有三点需要注意:

  1. new obj.constructor () 构造函数新建一个空的对象,而不是使用{}或者[],这样可以保持原形链的继承;
  2. obj.hasOwnProperty(key) :判定自身是否含有这个属性,会忽略掉那些从原型链上继承到的属性,因为 for..in..也会遍历其原型链上的可枚举属性。
  3. 上面的函数用到递归算法,在函数有名字,而且名字以后也不会变的情况下,这样定义没有问题。但问题是这个函数的执行与函数名 factorial 紧紧耦合在了一起。为了消除这种紧密耦合的现象,需要使用 arguments.callee
//方法一
function deepCopy(obj) {
  var newobj = obj.constructor === Array ? [] : {};
  if (typeof obj !== "object") {
    return obj;
  } else {
    for (var i in obj) {
      if (typeof obj[i] === "object") {
        //判断对象的这条属性是否为对象
        newobj[i] = deepCopy(obj[i]); //若是对象进行嵌套调用
      } else {
        newobj[i] = obj[i];
      }
    }
  }
  return newobj; //返回深度克隆后的对象
}

//方法二
var clone = function (obj) {
  if (obj === null) return null;
  if (typeof obj !== "object") return obj;
  if (obj.constructor === Date) return new Date(obj);
  if (obj.constructor === RegExp) return new RegExp(obj);
  var newObj = new obj.constructor(); //保持继承链
  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      //不遍历其原型链上的属性
      var val = obj[key];
      // 使用arguments.callee解除与函数名的耦合
      newObj[key] = typeof val === "object" ? arguments.callee(val) : val;
    }
  }
  return newObj;
};

文章作者: .Paly
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 .Paly !
  目录