【💎魔仙带你手写深浅拷贝/防抖节流/Ajax】

92 阅读2分钟

浅拷贝

浅拷贝 对于基础数据类型复制的值 引用类型复制的是内存地址

所以导致一个对象拷贝了 改变了内存地址会影响到另一个拷贝的对象

法1: ES6中的Object.assign(target,...sources) 
但是它不会拷贝继承的和不可枚举的属性/可以拷贝Symbol

法2: 扩展运算符 let cloneObj = { ...obj }

法3: concat 用于数组的浅拷贝
let arr = [1,{val:2},4]
let newArr = arr.concat()

法4: slice 数组的浅拷贝
let arr = [1,{val:2},4]
let newArr = arr.slice()

总结:浅拷贝只能实现第一层的拷贝 多层将无能为力

手写浅拷贝啦啦啦👩‍❤️‍👩

const shallowClone = (target) => {
  if(typeof target === 'object' && target !== null){
     let cloneTarget = Array.isArray(target)?[]:{}
     for(let prop in target){
        if(target.hasOwnProperty(prop)){
          cloneTarget[prop] = target[prop]
        }
     }
     return cloneTarget
     
  }else {
   return target
  }
}

深拷贝

无论拷贝多少份 又或者嵌套多少层 其中一个对象改变了内存地址 不会影响到另一个

1 let b = JSON.parse(JSON.stringify(a))
缺点 
1.会忽略symbol/undefined 2.拷贝Regexp会变成空对象/拷贝date类型会变成字符串
3.不能解决循环引用 4.无法拷贝不可枚举的属性/和原型链 ...

针对要解决的上述问题,手写深拷贝啦啦啦👩‍❤️‍👩
const isComplexType = (target)=> (typeof target === 'object' || typeof target === 'function') && (target !==  null)
const deepClone = function (target,hash=new weakMap()){
    if(target.constructor === Date){
      return new Date(target)
    }
    if(target.constructor === RegExp){
      return new RegExp(target)
    }
    if(hash.has(target)){
      return hash.get(target)
    }
    let allDesc = Object.getOwnPropertyDescriptors(target) //返回对象所有属性
    let cloneTarget = Object.create(Object.getPrototypeOf(target),allDesc) //继承原型和所有属性
    
    hash.set(target,cloneTarget)
    for(let prop of Reflect.ownKeys(target)){
      cloneTarget[prop] = (isComplexType(target[prop]) && typeof target[prop] !== 'function')? deepClone(target[prop],hash):target[prop]
    }
    return cloneTarget
    
}

防抖/节流

1.防抖 事件被触发n秒后执行回调 如果n秒内又触发了 则重新计时 用于防止重复点击
2.节流 规定的单位时间内无论事件被触发多少次 只生效一次 可以用于监听scroll事件 降低事件调用频率

手写防抖啦啦啦😢
function debounce(fn,wait){
 var timer = null
 return function(){
   var context = this,
       args = arguments;
     if(timer){
     clearTimeout(timer)
     timer = null
     }
     timer = setTimeout(()=>{
        fn.apply(context,args)
     },wait)
 }
}
手写节流😄
function throttle(fn,delay){
  var preTime = Date.now();
  return function(){
    var context = this,
        args = arguments,
        nowTime = Date.now();
     if(nowTime - preTime >= delay){
        preTime = Date.now() 
        return fn.apply(context,args)
     }
  }
}

Ajax

一种异步通信方法

手写原生Ajax啦啦啦啦啦👀👌
const xhr = window.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP') //兼容IE6以下
xhr.open('get','xxx.xml',true)
xhr.send(null)
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
 if(xhr.status === 200 || xhr.status === 304){
   console.log(xhr.responseXML)
 }
}

}