手写

87 阅读2分钟

- 深拷贝

/* checkType方法,一个参数,用于检查数据的类型,返回数据类型。 */
function checkType(target) {
  /* toString后得到字符串[object xxx],用slice(左闭右开)(左起0)将字符串中的xxx截取出来。 */
  return Object.prototype.toString.call(target).slice(8, -1)
}
/* clone方法,一个参数,用于判断是否要克隆 */
function clone(target) {
  let result,
    targetType = checkType(target)
  if (targetType === 'Object') {
    result = {}
  } else if (targetType === 'Array') {
    result = []
  } else {
    return target
  }
  //遍历克隆
  for (let i in target) {
    let value = target[i]
    if (checkType(value) === 'Object' || checkType(value) === 'Array') {
      result[i] = clone(value) //是Object或Array类型的则调用clone方法克隆value
    } else {
      result[i] = value //非Object或Array则直接克隆
    }
  }
  return result
}

const obj = {'name': 'zhou',say: ()=>{console.log('what?')}}
console.log(JSON.parse(JSON.stringify(obj)));
console.log(clone(obj));

- 大数求和

function bigNumAdd(a, b) {
    let temp = 0,//每位相加产生的进位,初始化为0
        res = [];
    let s1 = a.split('').reverse();
    let s2 = b.split('').reverse();
    
    let format = (val) => {
        if (!isNaN(Number(val))) return Number(val)
        return 0
    }
    /* 注意此处是 i <= Math.max(s1.length, s2.length) */
    for (let i = 0; i <= Math.max(s1.length, s2.length); i++) {
        let addRes = format(s1[i]) + format(s2[i]) + temp;
        res[i] = addRes % 10;
        temp = addRes >= 10 ? 1 : 0;
    }
    res.reverse();
    /* 判断是否相加产生了进位 */
    const resultNum = res[0] > 0 ? res.join('') : res.slice(1).join('');
    return resultNum;
}

console.log(bigNumAdd('13254', '4354325'));

- 数组去重

// 法 1
Array.prototype.unique = function () {
  return this.filter((x,y) => this.indexOf(x) === y)
}

// 法 2
Array.prototype.unique = function () {
  const res = []
  /* for (let index = 0; index < this.length; index++) {
    if (res.indexOf(this[i]) === -1) {
      res.push(this[i])
    }
  } */
  this.forEach(it => {
    if (res.indexOf(it) === -1) {
      res.push(it)
    }
  })
  return res
}

// 法 3
new Set(arr)

- map方法

- shuffle

var numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411];
var numbers_ = numbers.slice(); // 深拷贝
numbers_ = numbers_.sort(function(){ return Math.random() - 0.5});
// 0 < Math.random() < 1

- 节流

function throttle(fn, time) {
  // 记录上一次函数调用时间
  let lastTime = 0;
  return function throttled() {
    // 记录当前函数调用的时间
    const nowTime = Date.now();
  // 判断间隔
    if (nowTime - lastTime > time) {
      // 修改函数this和参数
      fn.apply(this, arguments);
      // 同步时间
      lastTime = nowTime;
    }
  };
}

- 防抖

/**
  封装防抖/节流函数
    fn 要处理的目标函数
    time 单位时间
*/
function debounce(fn, time) {
  // 存储上一次定时器的timer
  let timer = null;
  // debounced是事件的回调函数,所以有event和this
  return function debounced() {
    console.log('event', event);
    console.log('this', this);
    const _self = this;//input
    const args = arguments;//inputEvent
    // 将上一次的定时器清除
    clearTimeout(timer);
    timer = setTimeout(function() {
      // 需要修改目标函数 fn 的 this指向 和 参数。
      //zl:因为原来setTimeout中的回调函数是匿名函数,this指向window,event为undefined(没传嘛)。所以要改变this和event,由此在上面定义了_self和args(arguments是保存实参的伪数组,可以作为apply的第二个参数)。
      fn.apply(_self, args);
    }, time);
  };
}

- 事件绑定

Function.prototype.eventbus = function () {
  let allEvents = {} // { ename: [c1,c2,c3……] }
  this.on = function (ename, callback) { // 绑定
    if (!allEvents[ename]) {
      allEvents[ename] = []
    } else {
      allEvents[ename].push(callback)
    }
  }
  this.emit = function (ename, data) { // 分发
    if (allEvents[ename] && allEvents[ename].length > 1) {
      allEvents[ename].forEach(it => {
        it(data)
      })
    }
  }
  this.off = function (ename) { // 解绑
    if (ename) {
      delete allEvents[ename]
    } else {
      allEvents = {}
    }
  }
}

- call、apply、bind

// call 
Function.prototype.myCall = function(context, ...args) {
  context.__proto__._fn = this // 将当前调用 myCall 的函数赋值给这个属性
  const result = context._fn(...args)
  delete context.__proto__._fn
  return result
}