手写call、apply,函数柯里化,promiseAll,promiseRace

Function.prototype.myCall = function () {
  let thisVal = arguments[0] // 存call第一个参数执行上下文
  const isStrict = (function () { return this === undefined })() // 判断当前环境是否是严格模式
  if (!isStrict) { // 非严格模式
    if (thisVal === null || thisVal === undefined) { // thisVal 没传或者是null, undefined
      thisVal = (function () { return this })() // 则赋值为window或者node环境参数
    }
  } else { // 严格模式
    const thisValType = typeof thisVal // 先处理可能输入的不同数据格式
    if (thisValType === 'number') {
      thisVal = new Number(thisVal)
    }
    if (thisValType === 'string') {
      thisVal = new String(thisVal)
    }
    if (thisValType === 'boolean') {
      thisVal = new Boolean(thisVal)
    }
  }
  const otherParams = [...arguments].slice(1) // call其他参数
  const fn = this // 当前this就是调用call的方法 
  if (thisVal === null || thisVal === undefined) { // 严格模式 并且没有指定第一个参数或者第一个参数的值本身就是null或undefined,此时将目标函数当成普通函数执行并返回其结果即可
    return fn(...otherParams)
  }
  // 否则,让目标函数成为thisArg对象的成员方法,然后调用它 ???
  // 直观上来看,可以直接把目标函数赋值给对象属性,比如func属性,但是可能func属性本身就存在于thisArg对象上
  // 所以,为了防止覆盖掉thisArg对象的原有属性,必须创建一个唯一的属性名,可以用Symbol实现,如果环境不支持Symbol,可以通过uuid算法来构造一个唯一值。
  var uniquePropName = Symbol(thisVal)
  thisVal[uniquePropName] = fn
  return thisVal[uniquePropName](...otherParams)
}

Function.prototype.myApply = function () {
  let thisVal = arguments[0] // 存call第一个参数执行上下文
  const isStrict = (function () { return this === undefined })() // 判断当前环境是否是严格模式
  if (!isStrict) { // 非严格模式
    if (thisVal === null || thisVal === undefined) { // thisVal 没传或者是null, undefined
      thisVal = (function () { return this })() // 则赋值为window或者node环境参数
    }
  } else { // 严格模式
    const thisValType = typeof thisVal // 先处理可能输入的不同数据格式
    if (thisValType === 'number') {
      thisVal = new Number(thisVal)
    }
    if (thisValType === 'string') {
      thisVal = new String(thisVal)
    }
    if (thisValType === 'boolean') {
      thisVal = new Boolean(thisVal)
    }
  }
  const otherParams = Array.isArray(arguments[1]) ? [...arguments[1]] : arguments[1] // call其他参数
  const fn = this // 当前this就是调用call的方法 
  if (thisVal === null || thisVal === undefined) { // 严格模式 并且没有指定第一个参数或者第一个参数的值本身就是null或undefined,此时将目标函数当成普通函数执行并返回其结果即可
    return fn(...otherParams)
  }
  // 否则,让目标函数成为thisArg对象的成员方法,然后调用它 ???
  // 直观上来看,可以直接把目标函数赋值给对象属性,比如func属性,但是可能func属性本身就存在于thisArg对象上
  // 所以,为了防止覆盖掉thisArg对象的原有属性,必须创建一个唯一的属性名,可以用Symbol实现,如果环境不支持Symbol,可以通过uuid算法来构造一个唯一值。
  var uniquePropName = Symbol(thisVal)
  thisVal[uniquePropName] = fn
  return thisVal[uniquePropName](...otherParams)
}

function curry(fn) {
  let args = []
  function curried() {
    args = [...args, ...arguments]
    return curried
  }
  curried.toString = function(){
    return fn.myCall(null, ...args)
  }
  return curried
}
Promise.all = function (iterators) {
  return new Promise((resolve, reject) => {
    if (!iterators || iterators.length === 0) {
      resolve([]);
    } else {
      let count = 0; // 计数器,用于判断所有任务是否执行完成
      let result = []; // 结果数组
      for (let i = 0; i < iterators.length; i++) {
        // 考虑到iterators[i]可能是普通对象,则统一包装为Promise对象
        Promise.resolve(iterators[i]).then(
          (data) => {
            result[i] = data; // 按顺序保存对应的结果
            // 当所有任务都执行完成后,再统一返回结果
            if (++count === iterators.length) {
              resolve(result);
            }
          },
          (err) => {
            reject(err); // 任何一个Promise对象执行失败,则调用reject()方法
            return;
          }
        );
      }
    }
  });
};
Promise.race = function (iterators) {
  return new Promise((resolve, reject) => {
    for (const iter of iterators) {
      Promise.resolve(iter)
        .then((res) => {
          resolve(res);
        })
        .catch((e) => {
          reject(e);
        });
    }
  });
};
原文地址:https://www.cnblogs.com/wilsunson/p/14453313.html