JS手写

apply

function myApply(obj,args){
    /*
    1. this指向调用者
    2. 使用隐式绑定 obj.fn = this
    3. obj.fn()
    4. 调用完以后删除fn
    */
    // 确保obj是一个对象
    obj = (obj===null || obj === undefined) ? window:Object(obj)
    
    
    obj.fn = this
    obj.fn(...args)
    delete obj.fn
}

// 添加到Function原型上
Function.prototype.myApply = myApply

call

Function.prototype.myCall = function(obj,...args){
    obj = (obj===null || obj === undefined) ? window:Object(obj)
    obj.fn = this
    obj.fn(...args)
    delete obj.fn
}

bind

Function.prototype.myBind = function(obj,...args){
    // 判断是否为对象类型
    obj = obj ===null||obj ===undefined ? window:Object(obj)
    obj.fn = this
    return (...fnArgs)=>{
        obj.fn(...args,...fnArgs)
    }
}

new

function myNew(fn){
    /*
    0. 判断是否是一个函数
    1. 创建一个空对象,对象的原型指向fn的原型
    2. fn绑定this
    3. 返回对象或fn的返回值
    */
    if (typeof fn !== 'function') {
        throw 'must be a function'
    }
    var obj = Object.create(fn.prototype)
    var args = [...arguments].slice(1)
    var result = fn.apply(obj,args)
    
    if ((typeof result ==='object' && typeof result !== null) || typeof result ==='function') {
        return result
    }
    return obj
}

防抖函数

function debounce(fn, wait = 500, immediate = true) {
  let timer = null
  let isInvoke = false
  
  
  const _debounce = function (...args) {
    if (timer) clearTimeout(timer)
      
    if (immediate && !isInvoke) {
      fn.apply(this, args)   // this 参数 绑定
      isInvoke = true
      return
  	}
      
    timer = setTimeout(() => {
      fn.apply(this, args)   // this 参数 绑定
      timer = null
      isInvoke = false
    }, wait)
  }
  _debounce.cancle = function(){
      if (timer) clearTimeout(timer)
      timer = null
      isInvoke = false
  }
  return _debounce
}
const inp = document.querySelector('input')
inp.oninput = debounce(function (event) {
  console.log(this.value)
}, 1000)

节流函数

function throttle(fn, interval, immediate = true, trailing = false) {
  let startTime = 0
  let timer = null
  let res = null
  const _throttle = function (...args) {
    return new Promise((resolve, reject) => {
      try {
        let endTime = new Date().getTime()

        if (!immediate && startTime === 0) {
          startTime = endTime
        }

        let wait = interval - (endTime - startTime)
        if (wait <= 0) {
          if (timer) clearTimeout(timer)
          res = fn.apply(this, args)
          resolve(res)
          startTime = endTime
          timer = null
          return
        }

        // 判断是否执行尾部 
        if (trailing && !timer) {
          timer = setTimeout(() => {
            res = fn.apply(this, args)
            resolve(res)
            startTime = new Date().getTime()
            timer = null
          }, wait)
        }
      } catch (error) {
        reject(error)
      }
    })
  }


  // 取消功能
  _throttle.cancel = function () {
    if (timer) clearTimeout(timer)
    timer = null
    startTime = 0
  }

  return _throttle
}
const inp = document.querySelector('input')
inp.oninput = throttle(function () {
    console.log(this.value)
}, 1000)

深拷贝

1. JSON方法:JSON.parse(JSON.stringify(obj)) 创建出一个全新的对象
缺点:
1.1 对一些数据无力,如:函数、Symbol 
1.2 如果存在对象的循环引用,会报错
function isObject(value){
    const valueType = typeof value
    return (value !== null) && (value === 'object' || value === 'function')
}

function deepCopy(obj,map=new weakMap()){
    // Symbol
    if (typeof obj === 'symbol') {
        return Symbol(obj.description)
    }
    
    if (!isObject(obj)) {
        return obj
    }
    
    // Set 集合
    if (obj instanceof Set) {
        const newSet = new Set()
        for (let item of obj) {
            newSet.add(item)
        }
        return newSet
    }
    
    // Map
    if (obj instanceof Map) {
       	return new Map(obj) 
    }
    if (map.get(obj)) {
        return map.get(obj)
    }
    const newObj = Array.isArray(obj)?[]:{}
    map.set(obj,newObj)
    // 遍历普通对象
    for (const key in obj) {
        newObj[key] = deepCopy(obj[key],map)
    }
    
    // 遍历Symbol
    let objSymbols = Object.getOwnpropertySymbols(obj)
    for (const key of objSymbols) {
        objSymbols[key.description] = deepCopy(obj[key],map)
    }
    return newObj
}

事件总线

event-bus: 跨文件、跨组件通信
class EventBus {
    constructor(){
        this.eventObj = {}
    }
    on(eventName,eventFn){
        let eventFns = this.eventObj[eventName]
        if (!eventFns) {
            this.eventObj[eventName] = []
        }
        eventFns.push(eventFn)
    }
    off(eventName,eventFn){
        let eventFns = this.eventObj[eventName]
         
        if (!eventFns) {
            Reflect.delete(this.eventObj,eventName)
            return
        }
        for (let i=0;i<eventFns.length;i++){
            const fn = eventFns[i]
            if (fn === eventFn) {
                eventFns.splice(i,1)
                break
            }
        }
    }
    emit(eventName,...args){
        const eventFns = this.eventObj[eventName]
        if (!eventFns) return
        for (let fn in eventFns) {
            fn(...args)
        }
    }
}

jsonp封装

// 类似jq中$.ajax请求

class MyJsonp {
  constructor(config={}){
    let {url,jsonp,jsonpCallback,data,success} = config
    console.log("config",config)
    // 请求地址
    this.url = url
    if (!this.url) {
      throw Error
    }
    // jsonp回调函数key
    this.jsonp = jsonp || 'cb'

    // jsonp回调函数名称
    this.jsonpCallback = jsonpCallback || this.getRandomStr()

    // 获取参数
    this.data = data || {}
    this.success = success
    this.createScript()
    
  }
  getRandomStr(){
    return "JQ"+(Math.random()+'').replace('.','')
  }
  // 动态生成script标签
  createScript(){
    let oScript = document.createElement('script')
    oScript.src = this.setJsonpRequestUrl()
    document.body.appendChild(oScript);

    window[this.jsonpCallback] = (data)=>{
      // 删除jsonp script
      document.body.removeChild(oScript)

      // 调用成功函数
      this.success(data)

      // 调用失败函数
      // this.fail(data)
    }
  }
  // jsonp完整路径
  setJsonpRequestUrl(){
    let data = this.setReqData()
    return `${this.url}?${this.jsonp}=${this.jsonpCallback}${data}`
  }

  // 解析data数据
  setReqData(){
    let dataStr = Object.keys(this.data).map((key)=>`${key}=${this.data[key]}`).join('&')
    return "&"+dataStr
  }

}
posted @ 2023-03-25 23:49  转角90  阅读(10)  评论(0编辑  收藏  举报