面试加工厂

手写代码Two

2021-04-22  本文已影响0人  斗伽

深拷贝、 hash解决深拷贝,循环引用

// 深拷贝,hash解决深拷贝,循环引用
function deepCopy(obj, hash = new WeakMap()) {
    let cloneObj
    let Constructor = obj.constructor
    switch(Constructor){
        case RegExp:
            cloneObj = new Constructor(obj)
            break
        case Date:
            cloneObj = new Constructor(obj.getTime())
            break
        default:
            if(hash.has(obj)) return hash.get(obj)
            cloneObj = new Constructor()
            hash.set(obj, cloneObj)
    }
    for (let key in obj) {
        cloneObj[key] = isObj(obj[key]) ? deepCopy(obj[key], hash) : obj[key];
    }
    return cloneObj
}
// 获取节点位置
const getPosition = el => {
  if (!el) return false;
  var rect = el.getBoundingClientRect();
  //获取元素距离文档顶部的距离
  var top =
    rect.top +
    (window.pageYOffset || document.documentElement.scrollTop) -
    (document.documentElement.clientTop || 0);
  var left =
    rect.left +
    (window.pageXOffset || document.documentElement.scrollLeft) -
    (document.documentElement.clientLeft || 0);

  return {
    top,
    left
  };
};

// 版本比较
const compareVersion = function(version1, version2) {
  let verision1Arr = version1.split(".");
  let verision2Arr = version2.split(".");
  let maxLen =
    verision1Arr.length > verision2Arr.length
      ? verision1Arr.length
      : verision2Arr.length;

  for (let i = 0; i < maxLen; i++) {
    let p1 = verision1Arr[i] >> 0 || 0;
    let p2 = verision2Arr[i] >> 0 || 0;
    if (p1 > p2) {
      return 1;
    } else if (p1 < p2) {
      return -1;
    }
  }
  return 0;
};




 

new 操作符做了这些事:

function myNew(fn, ...args) {
  let instance = Object.create(fn.prototype);
  let res = fn.apply(instance, args);
  return typeof res === 'object' ? res: instance;
}

实现 call 方法

调用 call 方法具体做了什么:

//实现一个call方法:
Function.prototype.myCall = function(context) {
  //此处没有考虑context非object情况
  context.fn = this;
  let args = [];
  for (let i = 1, len = arguments.length; i < len; i++) {
    args.push(arguments[i]);
  }
  context.fn(...args);
  let result = context.fn(...args);
  delete context.fn;
  return result;
};

实现 apply 方法

思路: 利用 this 的上下文特性。

//实现apply只要把下一行中的...args换成args即可 
Function.prototype.myCall = function(context = window, ...args) {
  let func = this;
  let fn = Symbol("fn");
  context[fn] = func;

  let res = context[fn](...args);//重点代码,利用this指向,相当于context.caller(...args)

  delete context[fn];
  return res;
}

实现 bind

bind 的实现对比其他两个函数略微地复杂了一点,因为 bind 需要返回一个函数,需要判断一些边界问题,以下是 bind 的实现

Function.prototype.myBind = function (context) {
  if (typeof this !== 'function') {
    throw new TypeError('Error')
  }
  const _this = this
  const args = [...arguments].slice(1)
  // 返回一个函数
  return function F() {
    // 因为返回了一个函数,我们可以 new F(),所以需要判断
    if (this instanceof F) {
      return new _this(...args, ...arguments)
    }
    return _this.apply(context, args.concat(...arguments))
  }
}

懒加载和预加载

// 懒加载
// <img src="default.png" data-src="https://xxxx/real.png">
function isVisible(el) {
  const position = el.getBoundingClientRect()
  const windowHeight = document.documentElement.clientHeight
  // 顶部边缘可见
  const topVisible = position.top > 0 && position.top < windowHeight;
  // 底部边缘可见
  const bottomVisible = position.bottom < windowHeight && position.bottom > 0;
  return topVisible || bottomVisible;
}

function imageLazyLoad() {
  const images = document.querySelectorAll('img')
  for (let img of images) {
    const realSrc = img.dataset.src
    if (!realSrc) continue
    if (isVisible(img)) {
      img.src = realSrc
      img.dataset.src = ''
    }
  }
}

// 测试
window.addEventListener('load', imageLazyLoad)
window.addEventListener('scroll', imageLazyLoad)
// or
window.addEventListener('scroll', throttle(imageLazyLoad, 1000))
//预加载

上一篇 下一篇

猜你喜欢

热点阅读