数组遍历方法实现记录

浅拷贝

  • Object.assign()
  • Array.prototype.concat()
  • Array.prototype.slice()
  • ES6 扩展运算符

深拷贝

cloneDeep

function cloneDeep(origin, hashMap = new WeakMap()) {
  // 非 undefined null 引用值,返回 origin
  if (origin == undefined || typeof origin !== 'object') {
    return origin;
  }
  // 日期对象
  if (origin instanceof Date) {
    return new Date(origin);
  }
  // 正则对象
  if (origin instanceof RegExp) {
    return new RegExp(origin);
  }
  // hashMap 中是否已存在本次要拷贝的对象 origin
  const hashKey = hashMap.get(origin);
  // 存在,返回该对象
  if (hashKey) {
    return hashKey;
  }
  // 对象和数组通过 origin 构造器新建
  const target = new origin.constructor();
  // 将对象存入hashMap
  hashMap.set(origin, target);
  // 遍历 origin 对象
  for (let k in origin) {
    // 排除 prototype 上的属性
    if (origin.hasOwnProperty(k)) {
      // 递归处理嵌套对象
      target[k] = cloneDeep(origin[k], hashMap);
    }
	}
  // 返回深拷贝后的对象
  return target;
}

const test1 = {};
const test2 = {};

test1.test2 = test2;
test2.test1 = test1;

const res = cloneDeep(test1);
console.log(res);

使用WeakMap解决相互引用的对象,在深拷贝过程中被重复克隆,从而引起Maximum call stack size exceeded的问题。与Map不同的是WeakMapkey只能是一个引用类型,这也是WeakMap中垃圾回收的意义所在。

res打印结果

weakMap

阮一峰-JavaScript 内存泄漏教程

const oBtn1 = document.querySelector("#btn1");
const oBtn2 = document.querySelector("#btn2");

// 创建WeakMap
const oBtnMap = new WeakMap();

// 弱引用
oBtnMap.set(oBtn1, handleBtn1Click);
oBtnMap.set(oBtn2, handleBtn2Click);

// 绑定事件处理函数
oBtn1.addEventListener("click", oBtnMap.get(oBtn1), false);
oBtn2.addEventListener("click", oBtnMap.get(oBtn2), false);

function handleBtn1Click() {}
function handleBtn2Click() {}

// 移除DOM
oBtn1.remove();
oBtn2.remove();

array-methods

forEach

Array.prototype.myForEach = function (cb) {
  var _arr = this;
  var _len = _arr.length;
  var _arg2 = arguments[1] || window;
  var _item;

  for (var i = 0; i < _len; i++) {
    _item = cloneDeep(_arr[i]);
    cb.apply(_arg2, [_item, i, _arr]);
  }
}

map

Array.prototype.myMap = function (cb) {
  var _arr = this;
  var _len = _arr.length;
  var _arg2 = arguments[1] || window;
  var _item;
  var _newArr = [];

  for (var i = 0; i < _len; i++) {
    _item = cloneDeep(_arr[i]);
    _newArr.push(cb.apply(_arg2, [_item, i, _arr]));
  }

  return _newArr;
}

filter

Array.prototype.myFilter = function (cb) {
  var _arr = this;
  var _len = _arr.length;
  var _arg2 = arguments[1] || window;
  var _item;
  var _newArr = [];

  for(var i = 0; i < _len; i++) {
    _item = cloneDeep(_arr[i]);
    cb.apply(_arg2, [_item, i, _arr])
      ? _newArr.push(_item)
      : '';
  }

  return _newArr;
}

every

Array.prototype.myEvery = function (cb) {
  var _arr = this;
  var _len = _arr.length;
  var _arg2 = arguments[1] || window;
  var _item;
  var _res = true;
  
  for (var i = 0; i < _len; i++) {
    _item = cloneDeep(_arr[i]);
    if (!cb.apply(_arg2, [_item, i, _arr])) {
      _res = false;
      break;
    };
  }

  return _res;
}

some

Array.prototype.mySome = function (cb) {
  var _arr = this;
  var _len = _arr.length;
  var _arg2 = arguments[1] || window;
  var _item;
  var _res = false;

  for (var i = 0; i < _len; i++) {
    _item = cloneDeep(_arr[i]);
    if (cb(_arg2, [_item, i, _arr])) {
      _res = true;
      break;
    }
  }

  return _res;
}

reduce

Array.prototype.myReduce = function (cb, initialVal) {
  var _arr = this;
  var _len = _arr.length;
  var _arg3 = arguments[2] || window;
  var _item;

  for (var i = 0; i < _len; i++) {
    _item = cloneDeep(_arr[i]);
    initialVal = cb.apply(_arg3, [initialVal, _item, i, _arr]);
  }

  return initialVal;
}

reduceRight

Array.prototype.myReduceRight = function (cb, initialVal) {
  var _arr = this;
  var _len = _arr.length;
  var _arg3 = arguments[2] || window;
  var _item;

  for (var i = _len - 1; i >= 0; i--) {
    _item = cloneDeep(_arr[i]);
    initialVal = cb.apply(_arg3, [initialVal, _item, i, _arr]);
  }

  return initialVal;
}

防抖、节流

防抖

function debounce(fn, delay) {
  let timer = null;

  return function () {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      fn.apply(this, arguments);
      timer = null;
    }, delay);
  };
}

节流

function throttle(fn, delay) {
  let timer = null;
  
  return function () {
    if (timer) {
      return;
    }
    timer = setTimeout(() => {
      fn.apply(this, arguments);
      timer = null;
		}, delay);
	};
}

> cd ..