一些常见的 JS 手写实现

163 阅读4分钟

总结一下平时积累的 JS 中常见的一些手写实现

实现原生方法

实现 new

function myNew(constructor, ...args) {
  // 创建一个空对象,并将其原型设置为构造函数的原型
  const obj = Object.create(constructor.prototype);
  
  // 调用构造函数,并将 this 指向新创建的对象
  const result = constructor.apply(obj, args);
  
  // 如果构造函数返回了一个对象,则返回该对象;否则返回新创建的对象
  return typeof result === 'object' && result !== null ? result : obj;
}

实现 typeof

const typeof = (obj) => {
  return prototype.toString.call(obj).slice(8, -1).toLowerCase();
};

实现 instanceOf

const instanceOf = (left, right) => {
  if (typeof left !== 'object' || left === null) {
    return false;
  }
  // 获取原型
  let proto = Object.getPrototyprof(left);
  let targetProto = right.prototype;
  while(true) {
    if (proto === null) {
      return false;
    }
    if (proto === targetProto) {
      return true;
    }
    proto = Object.getPrototyprof(proto);
};

实现 forEach

Array.prototype.forEach1 = function (fn, args) {
  if(!this || !Array.isArray(this)) {
    throw 'need an array';
  }
  if(!fn instanceof Function) {
    throw 'need a function'
  }
  const arr = this.slice();
  let i = 0;
  while(i < arr.length) {
    fn.call(this, args, arr[i], i++, arr);
  }
}

实现 map

Array.prototype.map1 = function (fn, args) {
  if(!this || !Array.isArray(this)) {
    throw 'need an array';
  }
  if(!fn instanceof Function) {
    throw 'need a function'
  }
  const arr = this.slice();
  let i = 0;
  let results = []
  while(i < arr.length) {
    results.push(fn.call(this, args, arr[i], i++, arr));
  }
  return results;
}

实现 filter

Array.prototype.filter1 = function (fn, args) {
  if(!this || !Array.isArray(this)) {
    throw 'need an array';
  }
  if(!fn instanceof Function) {
    throw 'need a function'
  }
  const arr = this.slice();
  let i = 0;
  let results = []
  while(i < arr.length) {
    if(fn.call(this, args, arr[i], i, arr)) {
      results.push(arr[i])
    }
    i++
  }
  return results;
}

实现 Object.assign

Object.assign1 = function (target, ...args) {
  if (!target) {
    throw 'need a object';
  }

  args.forEach((item) => {
    if (item) {
      for (let key in item) {
        if (item.hasOwnProperty(key)) {
          target[key] = item[key];
        }
      }
    }
  });

  return target;
};

实现 Promise

const PENDING = 'pending';
const FULLFILLED = 'fullfiled';
const REJECTED = 'rejected';

class MyPromise {
  constructor (executor) {
    try {
      executor(this.resolve, this.reject);
    } catch (error) {
      this.reject(error);
    }
  }

  /** 状态 */
  status = PENDING
  /** 成功的值 */
  value = null
  /** 失败的原因 */
  reason = null

  /** 存储成功回调 */
  onFulfilledCallbacks = [];
  /** 存储失败回调 */
  onRejectedCallbacks = [];

  resolve = (value) => {
    // 如果状态不是等待,阻止程序向下执行
    if (this.status !== PENDING) {
      return;
    }
    this.status = FULLFILLED;
    this.value = value;

    // 将所有成功的回调拿出来执行
    while(this.onFulfilledCallbacks.length) {
      this.onFulfilledCallbacks.shift()?.(value);
    }
  }

  reject = (reason) => {
    // 如果状态不是等待,阻止程序向下执行
    if (this.status !== PENDING) {
      return;
    }
    this.status = REJECTED;
    this.reason = reason;

    // 将所有失败的回调拿出来执行
    while(this.onRejectedCallbacks.length) {
      this.onRejectedCallbacks.shift()?.(reason);
    }
  }

  then(onFulfilled, onRejected) {
    const promise2 = new MyPromise((resolve, reject) => {
      // 成功回调
      if(this.status === FULLFILLED) {
        // 模拟异步
        setTimeout(() => {
          try {
            const val = onFulfilled(this.value);
            resolvePromise(promise2, val, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            const val = onRejected(this.reason);
            resolvePromise(promise2, val, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else {
        // 等待状态
        this.onFulfilledCallbacks.push(onFulfilled);
        this.onRejectedCallbacks.push(onRejected);
      }
    });
    return promise2;
  }
}

function resolvePromise(promise, val, resolve, reject) {
  if (promise === val) {
    return reject(new TypeError('Chaining cycle detected for promise'));
  }
  if (val instanceof MyPromise) {
    val.then(resolve, reject);
  } else {
    resolve(val);
  }
}

实现 Promise.all

只要有一个失败就失败

Promise.all1 = function(promises) {
  if (!Array.isArray(promises)) {
    throw 'need an array';
  }

  let index = 0;
  let results = [];

  return new Promise((resolve, reject) => {
    promises.forEach((p, i) => {
      Promise.resolve(p).then(
        val => {
          index++;
          results[i] = val;
          // 所有的都成功了 
          if(index === promises.length) {
            resolve(results);
          }
        },
        err => {
          // 有一个失败就失败
          reject(err);
        }
      );
    });
  });
}

实现 Promsie.race

只要有一个relovereject,返回的promiserelovereject

Promise.race1 = function(promises) {
  if (!Array.isArray(promises)) {
    throw 'need an array';
  }

  return new Promise((resolve, reject) => {
    promises.forEach(p => {
      Promise.resolve(p).then(
        val => {
          resolve(val);
        },
        err => {
          reject(err);
        }
      );
    });
  });
}

实现 Promsie.any

只要有一个relove,返回的promiserelove

Promise.any1 = function(promises) {
  if (!Array.isArray(promises)) {
    throw 'need an array';
  }

  let errors = [];

  return new Promise((resolve, reject) => {
    promises.forEach(p => {
      Promise.resolve(p).then(
        val => {
          resolve(val);
        },
        err => {
          errors.push(err);
          if (errors.length === promises.length) {
            reject(errors);
          }
        }
      );
    });
  });
}

实现 Promise.allSettled

只有全部完成才reslove

Promise.allSettled1 = function(promises) {
  if (!Array.isArray(promises)) {
    throw 'need an array';
  }

  let results = [];

  return new Promise((resolve, reject) => {
    promises.forEach((p, i) => {
      Promise.resolve(p).then(
        val => {
          results.push({
            status: 'fulfilled',
            value: val,
          });

          if(results.length === promises.length) {
            resolve(results);
          }
        },
        err => {
          results.push({
            status: 'rejected',
            value: val,
          });

          if(results.length === promises.length) {
            resolve(results);
          }
        }
      );
    });
  });
}

实现防抖

const debounce = (fn, time) => {
  if (!fn instanceOf function) {
    return false;
  }
  
  let timer = null;
  return function(...args) {
    timer && clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, time)
  }
};

实现节流

// 使用时间戳
const throttle = (fn, time) => {
  if (!fn instanceOf function) {
    return false;
  }
  
  let lastTime = 0;
  return function(...args) {
    let now = Date.now();
    if (now - lastTime > time) {
      lastTime = now;
      fn.apply(this, args);
    }
  }
};

// 使用定时器
const throttle = (fn, time) => {
  if (!fn instanceof function) {
    return false;
  }
  // 节流标识
  let limited = false;
  let start = Date.now();
  let timer = null;
  return function(...args) {
    limited = limited && (Date.now() - start < time);
    // 处在节流中
    if (limited) {
      timer && clearTimeout(timer);
      timer = setTimeout(() => {
        fn.apply(this, args);
        limited = true;
        start = Date.now();
      }, time);
    } else {
      limited = true;
      start = Date.now();
      fn.apply(this, args);
    }
  }
};

扁平化

数组扁平化

const flat = (arr, dep) => {
  if(dep <= 0 || !Array.isArray(arr)) {
    return arr;
  }
  return arr.reduce((pre, cur) => pre.concat(Array.isArray(cur) ? flat(cur, dep- 1) : cur) , []);
};

const arr1 = [1, [2, 3], [4, 5, [6, 7]]]; 
const depth1 = 1; 
console.log(flat(arr1, depth1)); // 输出: [1, 2, 3, 4, 5, [6, 7]]

对象扁平化

const objectFlat = (obj) => {
  const res = {};
  const process = (key, value) => {
    if (typeof value !== 'object' || value == null) {
      if (key) {
        res[key] = value;
      }
    } else if (Array.isArray(value)) {
      value.forEach((item, index) => {
        process(`${key}[${index}]`, item);
      });
      if (value.length === 0) {
        res[key] = [];
      }
    } else {
      const keys = Object.keys(value);
      keys.forEach(item => {
        process(key ? `${key}.${item}` : `${item}`, value[item]);
      });

      if (keys.length && key) {
        res[key] = {};
      }
    }
  };

  process('', obj);
  return res;
};

const obj1 = { a: 1, b: { c: 2, d: { e: 3, f: { g: 4 } } } }; 
console.log(objectFlat(obj1)); // 输出: { "a": 1, "b.c": 2, "b.d.e": 3, "b.d.f.g": 4 }

柯里化


const curry = (fn) => {
  const curryInner = (...args) => {
    // 当参数长度一致时 (函数的length表示形参的个数)
    if (args.length === fn.length) {
      return fn(...args);
    }
    // 递归返回处理剩余参数
    return (...args1) => curryInner(...args, ...args1);
  };
  return curryInner();
}

const add = curry((x, y, z) => x + y + z);
add(1)(2)(3) // 6

layzyMan

class lazyMan {
  constructor(name) {
    this.tasks = [];
    this.name = name;
    console.log(`Hi Im ${name}`);
    setTimeout(() => {
     this.next(); 
    });
  }

  sleep(time) {
    // 定时器实现 sleep
    this.tasks.push(() => {
      console.log('sleep');
      setTimeout(() => {
        this.next();
      }, time);
    });
    // 实现链式的关键
    return this;
  }

  eat(food) {
    this.tasks.push(() => {
      console.log(`eat ${food}`);
      this.next();
    });
    return this;
  }

  next() {
    const fn = this.tasks.shift();
    fn && fn();
  }
}


const lazyMan = new LazyMan('John'); 
// 输出: Hi im John  
lazyMan.sleep(2000).eat('breakfast'); 
// 等待2秒后输出: sleep 
// 然后输出: eat breakfast  
lazyMan.eat('lunch').sleep(3000).eat('dinner'); 
// 输出: eat lunch 
// 等待3秒后输出: sleep 
// 然后输出: eat dinner

去重

普通数组去重

// 用 filter 实现
const uniqueArray0 = (arr) => {
  return arr.filter((item, index) => arr.indexOf(item) === index);
}

// 用 reduce 实现
const uniqueArray1 = (arr) => {
  return arr.reduce((pre, cur) => pre.includes(cur) ? pre : [...pre, cur], []);
};

// 双重循环
const uniqueArray2 = (arr) => {
  const result = [];
  for (let i = 0; i < arr.length; i++) {
    let isDuplicate = false;
    for (let j = i + 1; j < arr.length; j++) {
      if (arr[i] === arr[j]) {
        isDuplicate = true;
        break;
      }
    }
    if (!isDuplicate) {
      result.push(arr[i]);
    }
  }
  return result;
};

// 键值对
const uniqueArray3 = (arr) => {
  const obj = {};
  for (let i = 0; i < arr.length; i++) {
    obj[arr[i]] = true;
  }
  return Object.keys(obj)
};

对象数组去重

只要对象内的所有属性的值相同,就算相同元素。

const isEqual = (left, right) => {
  if (left === right) {
    return true;
  }

  if (typeof left !== typeof right) {
    return false;
  }

  if (typeof left !== 'object' || left === null || right === null) {
    return left === right;
  }

  const leftKeys = Object.keys(left);
  const rightKeys = Object.keys(right);

  if (leftKeys.length !== rightKeys.length) {
    return false;
  }

  for (let key of leftKeys) {
    if (!right.hasOwnProperty(key)) {
      return false;
    }

    if (!isEqual(left[key], right[key])) {
      return false;
    }
  }

  return true;
};

const uniqueObject = (arr) => {
  return arr.filter((item, index) => {
    for (let i = 0; i < index; i++) {
      if (isEqual(item, arr[i])) {
        return false;
      }
    }
    return true;
  });
};

实现一个deepClone

const deepClone = (obj, map = new WeakMap()) => {
  const toString = Object.prototype.toString;
  // null, undefined, {}, function
  if(!obj || typeof obj !== 'object') {
     return obj;
  }

  // 日期格式
  if(toString.call(obj) === '[object Date]') {
    return new Date(obj.getTime());
  }

  // 正则表达式
  if(toString.call(obj) === '[object RegExp]') {
    var flags = [];
    if(obj.global) {
      flags.push('g');
    }
    if(obj.multiline) {
      flags.push('m');
    }
    if(obj.ignoreCase) {
      flags.push('i');
    }
    return new RegExp(obj.source, flags.join(''))
  }
  
  let cloneObj = obj instanceof Array ? [] : {}
  // 防止循环引用
  if (map.get(obj)) {
    return obj;
  }
  map.set(obj, cloneObj);

  for(let i in obj) {
    if(obj.hasOwnProperty(i)) {
      cloneObj[i] = deepClone(obj[i], map);
    }
  }
  return cloneObj;
}

实现一个深比较

function deepEqual(obj1, obj2) {
  if (typeof obj1 !== typeof obj2) {
    return false;
  }

  if (typeof obj1 !== 'object' || obj1 === null) {
    // 若为基本类型、函数或日期对象,则直接比较值
    if (obj1 instanceof Date && obj2 instanceof Date) {
      return obj1.getTime() === obj2.getTime();
    }
    return obj1 === obj2;
  }

  if (obj1 instanceof RegExp && obj2 instanceof RegExp) {
    return obj1.toString() === obj2.toString();
  }

  const keys1 = Object.keys(obj1);
  const keys2 = Object.keys(obj2);

  if (keys1.length !== keys2.length) {
    return false;
  }

  for (let key of keys1) {
    if (!deepEqual(obj1[key], obj2[key])) {
      return false;
    }
  }

  return true;
}

实现千分位

const formatNumber = (num) => {
  const str = String(num);
  let result = [];
  for(let i = str.length - 1, j = 1; i >= 0; i--, j++) {
    result.push(str[i]);
    if(j % 3 === 0 && i !== 0) {
      result.push(',');
    }
  }

  return result.reverse().join('');
};

// 正则实现
const formatNumber = (num) => {
    return num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
}
 
const number = 1234567; // 要格式化的数字
console.log(formatNumber(number)); // 输出结果为 "1,234,567"

模拟红绿灯

// 定时器实现
const changeColor = (color) => {
  console.log('color:', color);
};

const main = () => {
  changeColor('red');
  setTimeout(() => {
    changeColor('yellow');
    setTimeout(() => {
      changeColor('green');
      setTimeout(main, 1000);
    }, 1000);
  }, 2000);
};

// Promise 实现
const sleep = (duration) => {
  return new Promise(resolve => setTimeout(resolve, duration));
};

const changeColor = async (color, duration) => {
  console.log('color:', color);
  await sleep(duration);
};

const main = () => {
  while(true) {
    await changeColor('red', 2000);
    await changeColor('yellow', 1000);
    await changeColor('green', 3000);
  }
}

main()