XingYun blog
  • JS基础

    • 图解js原型链
    • JS Event Loop
    • 对象的底层数据结构
    • 让你的JavaScript代码简单又高效
    • 函数参数按值传递
    • 判断数据类型
    • 浮点数精度问题和解决办法
    • 常用方法snippet
    • 实现Promise
    • 防抖和节流
    • 巧用sort排序
  • CSS && HTML

    • CSS也需要性能优化
    • class命名规范
    • em、px、rem、vh、vw 区别
    • CSS揭秘阅读笔记
  • 浏览器

    • 浏览器是如何渲染页面的
    • 重排和重绘
    • BOM浏览器对象模型
    • DOM事件
    • 浏览器存储
  • 数据结构

    • JS实现链表
    • JS实现栈与栈应用
    • JS实现常见排序
    • 哈夫曼编码
    • MD5算法
  • vue原理浅析

    • Vue虚拟dom与Diff算法
    • 前端打包文件的缓存机制
    • vue数组为什么不是响应式
    • v-for为什么不能用index做key
  • 前端工程化

    • 浏览器是如何渲染页面的
    • 前端打包需要gzip压缩吗
    • 前端打包文件的缓存机制
    • webpack loader和plugin
  • 轮子&&组件库

    • 实现水波浪进度球
  • 文字转语音mp3文件
  • 文件上传前后端实现
  • moment.js给定时间获取自然月、周的时间轴
  • 实现文件上传功能
  • 批量下载照片
  • leaflet改变坐标原点
  • 网络

    • 有了MAC地址 为什么还需要IP地址
    • 为什么IP地址老是变
    • 我们为什么需要IPV6
    • TCP与UDP
  • 计算机组成原理

    • ASCII、Unicode、UTF-8和UTF-16
  • VSCode

    • VSCode图片预览插件 Image preview
    • rsync:linux间的高效传输工具

XingYun

冲!
  • JS基础

    • 图解js原型链
    • JS Event Loop
    • 对象的底层数据结构
    • 让你的JavaScript代码简单又高效
    • 函数参数按值传递
    • 判断数据类型
    • 浮点数精度问题和解决办法
    • 常用方法snippet
    • 实现Promise
    • 防抖和节流
    • 巧用sort排序
  • CSS && HTML

    • CSS也需要性能优化
    • class命名规范
    • em、px、rem、vh、vw 区别
    • CSS揭秘阅读笔记
  • 浏览器

    • 浏览器是如何渲染页面的
    • 重排和重绘
    • BOM浏览器对象模型
    • DOM事件
    • 浏览器存储
  • 数据结构

    • JS实现链表
    • JS实现栈与栈应用
    • JS实现常见排序
    • 哈夫曼编码
    • MD5算法
  • vue原理浅析

    • Vue虚拟dom与Diff算法
    • 前端打包文件的缓存机制
    • vue数组为什么不是响应式
    • v-for为什么不能用index做key
  • 前端工程化

    • 浏览器是如何渲染页面的
    • 前端打包需要gzip压缩吗
    • 前端打包文件的缓存机制
    • webpack loader和plugin
  • 轮子&&组件库

    • 实现水波浪进度球
  • 文字转语音mp3文件
  • 文件上传前后端实现
  • moment.js给定时间获取自然月、周的时间轴
  • 实现文件上传功能
  • 批量下载照片
  • leaflet改变坐标原点
  • 网络

    • 有了MAC地址 为什么还需要IP地址
    • 为什么IP地址老是变
    • 我们为什么需要IPV6
    • TCP与UDP
  • 计算机组成原理

    • ASCII、Unicode、UTF-8和UTF-16
  • VSCode

    • VSCode图片预览插件 Image preview
    • rsync:linux间的高效传输工具
  • leaflet改变坐标原点
  • 补间动画gsap与tween
  • 文字转语音mp3文件
  • JavaScript引入
  • JavaScript高级程序设计阅读笔记
  • Javascript函数参数按值传递传递
  • JS防抖和节流
  • 手写JS常用方法
    • 手写Promise
    • JS Event Loop
    • 重排和重绘
    • em、px、rem、vh、vw 区别
    • css也需要性能优化
    • 图解 js 原型链
    • js函数参数按值传递
    • BOM浏览器对象模型
    • DOM
    • 事件
    • js对象数组sort按需排序
    • 文件上传功能技术选型和前后端实现
    • 前端图片处理
    • 让你的JavaScript代码简单又高效
    • BEM:class命名规范
    • 前端规范-CSS属性那么多(杂),怎么排序
    • TypeScript Tips
    • jsx
    • canvas基础
    • 前端日志
    • 浏览器存储
    • CSS世界阅读笔记
    • CSS揭秘阅读笔记
    • js变量命名常用规范词
    • 你不知道的JavaScript阅读笔记
    • js对象的底层数据结构
    • js判断数据类型
    • JS浮点数精度问题和解决办法
    • js作用域
    • js堆栈溢出和内存泄漏
    • 浏览器是如何渲染页面的
    • 疑难杂症和踩坑问题合集
    • 免费在线API收集
    • 原生JS实现Ajax请求
    • cookie、session、localStorage、sessionStorage的区别
    • Sass与Less
    • arrayBuffer、blob、file对象
    • TypeScript基础
    • 前端
    XingYun
    2021-11-23
    目录

    手写JS常用方法

    # 判断数据类型
    function type(obj) {
      return Object.prototype.toString.call(obj).match(/\[object (.*?)\]/)[1]
    }
    
    console.log(type('')) // String*
    
    console.log(type(123)) // Number*
    
    console.log(type(true)) // Boolean*
    
    console.log(type(undefined)) // Undefined*
    
    console.log(type(null)) // Null
    
    console.log(type({})) // Object
    
    console.log(type([])) // Array
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    # 两个数组交叉对比求交集和差集

    ES6 中使用 Set 结构:

    let a = new Set([1, 2, 3]);
    let b = new Set([3, 5, 2]);
    
    // 并集
    let unionSet = new Set([...a, ...b]);
    //[1,2,3,5]
    
    // 交集
    let intersectionSet = new Set([...a].filter(x => b.has(x)));
    // [2,3]
    
    // ab差集
    let differenceABSet = new Set([...a].filter(x => !b.has(x)));
    // [1]
    
    再把Set转换为数组即可.let arr = Array.from(set);
    // 或 let arr = [...set];
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    # 函数柯里化

    其实就是将使用多个参数的函数转换成一系列使用一个参数的函数的技术

    function add(a, b, c) {
      return a + b + c
    }
    add(1, 2, 3)
    let addCurry = curry(add)
    addCurry(1)(2)(3)
    
    1
    2
    3
    4
    5
    6

    现在就是要实现 curry 这个函数,使函数从一次调用传入多个参数变成多次调用每次传一个参数。

    function curry(fn) {
      let judge = (...args) => {
        if (args.length == fn.length) return fn(...args)
        return (...arg) => judge(...args, ...arg)
      }
      return judge
    }
    
    1
    2
    3
    4
    5
    6
    7

    # 数字精度处理

    /**
     * 保留精度
     * @param value 值
     * @param precision 精度:2代表两位小数
     * @param multiplyer 乘数:100代表乘以100倍
     * @returns 返回保留精度的小数
     */
    export const precise = (
      value: number,
      precision: number = 0,
      multiplyer = 1
    ) => {
      const ratio = Math.pow(10, precision)
      return Math.round(value * multiplyer * ratio) / ratio
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

    # 判断图片能不能访问

    function checkImg(imgUrl) {
      return new Promise(function(resolve, reject) {
        var ImgObj = new Image()
        ImgObj.src = imgUrl
        ImgObj.onload = function(res) {
          resolve(res)
        }
        ImgObj.onerror = function(err) {
          reject(err)
        }
      })
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # 数组去重
    // 数组去重1
    function deduplicationArr(arr) {
      return arr.filter((item, index) => {
        return arr.indexOf(item) === index
      })
    }
    
    obj1 = {
      name: 111
    }
    
    let arr = [obj1, 1, 4, 524, 5, 64, 6, 24, 51, 324, 26, 3, 1, 33, 4, obj1]
    console.log(deduplicationArr(arr)) // [ { name: 111 }, 1, 4, 524, 5, 64, 6, 24, 51, 324, 26, 3, 33 ]
    
    // 数组去重2
    console.log([...new Set(arr)]) // [ { name: 111 }, 1, 4, 524, 5, 64, 6, 24, 51, 324, 26, 3, 33 ]
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # 深拷贝

    简单版本

    function deepClone(obj) {
      if (typeof obj !== 'object') return obj // 普通类型,直接返回
      if (obj === null || obj === undefined) return obj
      if (obj instanceof Date) return new Date(obj)
      if (obj instanceof RegExp) return new RegExp(obj)
    
      const res = new obj.constructor()
      for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
          res[key] = deepClone(obj[key])
        }
      }
      return res
    }
    
    console.log(deepClone({ name: 111, arr: [12, 5452, 3245, { name: 22 }] }))
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    完善版本:

    利用 Object.prototype.toString.call(obj) 获取对象的准确类型

    对每种类型单独处理

    const mapTag = '[object Map]'
    const setTag = '[object Set]'
    const arrayTag = '[object Array]'
    const objectTag = '[object Object]'
    const argsTag = '[object Arguments]'
    
    const boolTag = '[object Boolean]'
    const dateTag = '[object Date]'
    const numberTag = '[object Number]'
    const stringTag = '[object String]'
    const symbolTag = '[object Symbol]'
    const errorTag = '[object Error]'
    const regexpTag = '[object RegExp]'
    const funcTag = '[object Function]'
    
    const deepTag = [mapTag, setTag, arrayTag, objectTag, argsTag]
    
    function forEach(array, iteratee) {
      let index = -1
      const length = array.length
      while (++index < length) {
        iteratee(array[index], index)
      }
      return array
    }
    
    function isObject(target) {
      const type = typeof target
      return target !== null && (type === 'object' || type === 'function')
    }
    
    function getType(target) {
      return Object.prototype.toString.call(target)
    }
    
    function getInit(target) {
      const Ctor = target.constructor
      return new Ctor()
    }
    
    function cloneSymbol(targe) {
      return Object(Symbol.prototype.valueOf.call(targe))
    }
    
    function cloneReg(targe) {
      const reFlags = /\w*$/
      const result = new targe.constructor(targe.source, reFlags.exec(targe))
      result.lastIndex = targe.lastIndex
      return result
    }
    
    function cloneFunction(func) {
      const bodyReg = /(?<={)(.|\n)+(?=})/m
      const paramReg = /(?<=\().+(?=\)\s+{)/
      const funcString = func.toString()
      if (func.prototype) {
        const param = paramReg.exec(funcString)
        const body = bodyReg.exec(funcString)
        if (body) {
          if (param) {
            const paramArr = param[0].split(',')
            return new Function(...paramArr, body[0])
          } else {
            return new Function(body[0])
          }
        } else {
          return null
        }
      } else {
        return eval(funcString)
      }
    }
    
    function cloneOtherType(targe, type) {
      const Ctor = targe.constructor
      switch (type) {
        case boolTag:
        case numberTag:
        case stringTag:
        case errorTag:
        case dateTag:
          return new Ctor(targe)
        case regexpTag:
          return cloneReg(targe)
        case symbolTag:
          return cloneSymbol(targe)
        case funcTag:
          return cloneFunction(targe)
        default:
          return null
      }
    }
    
    function clone(target, map = new WeakMap()) {
      // 克隆原始类型
      if (!isObject(target)) {
        return target
      }
    
      // 初始化
      const type = getType(target)
      let cloneTarget
      if (deepTag.includes(type)) {
        cloneTarget = getInit(target, type)
      } else {
        return cloneOtherType(target, type)
      }
    
      // 防止循环引用
      if (map.get(target)) {
        return map.get(target)
      }
      map.set(target, cloneTarget)
    
      // 克隆set
      if (type === setTag) {
        target.forEach((value) => {
          cloneTarget.add(clone(value, map))
        })
        return cloneTarget
      }
    
      // 克隆map
      if (type === mapTag) {
        target.forEach((value, key) => {
          cloneTarget.set(key, clone(value, map))
        })
        return cloneTarget
      }
    
      // 克隆对象和数组
      const keys = type === arrayTag ? undefined : Object.keys(target)
      forEach(keys || target, (value, key) => {
        if (keys) {
          key = value
        }
        cloneTarget[key] = clone(target[key], map)
      })
    
      return cloneTarget
    }
    
    module.exports = {
      clone
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    # 扁平化数组
    function flatten(arr) {
      if (!arr || arr.length === 0) return arr
      let res = []
      for (let i = 0; i < arr.length; i++) {
        if (Array.isArray(arr[i])) {
          res = res.concat(flatten(arr[i]))
        } else {
          res.push(arr[i])
        }
      }
      return res
    }
    
    const res = flatten([111, [222, { name: '000' }, [52452345, { name: 111 }]]])
    console.log(res)
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

    # 发布订阅者模式

    class EventEmitter {
      constructor() {
        this.events = {}
      }
    
      on(eventName, fn) {
        if (this.events[eventName]) {
          this.events[eventName].push(fn)
        } else {
          this.events[eventName] = [fn]
        }
      }
    
      once(eventName, fn) {
        let that = this
        let func = function(args) {
          fn.call(this, args)
          that.off(eventName, func)
        }
        this.on(eventName, func)
      }
    
      emit(eventName, ...args) {
        if (this.events[eventName] && this.events[eventName].length > 0) {
          this.events[eventName].forEach((fn) => {
            fn.call(this, ...args)
          })
        }
      }
    
      off(eventName, fn) {
        if (this.events[eventName]) {
          let index = this.events[eventName].findIndex((func) => {
            return fn === func
          })
          if (index >= 0) {
            this.events[eventName].splice(index, 1)
          }
        }
      }
    }
    
    let bus = new EventEmitter()
    
    let test111 = function(text) {
      console.log(text, '111')
    }
    
    let test222 = function(text) {
      console.log(text, '222')
    }
    
    let test333 = function(text) {
      console.log(text, '333')
    }
    
    bus.on('click', test111)
    bus.on('click', test222)
    bus.once('click', test333)
    
    bus.emit('click', 'hello1')
    bus.off('click', test111)
    bus.emit('click', 'hello2')
    
    // hello1 111
    // hello1 222
    // hello1 333
    // hello2 222
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    #JavaScript
    上次更新: 2023/04/05, 09:41:10
    JS防抖和节流
    手写Promise

    ← JS防抖和节流 手写Promise→

    最近更新
    01
    JavaScript-test
    07-20
    02
    二维码的原理
    07-20
    03
    利用ChatGPT优化代码
    07-20
    更多文章>
    Theme by Vdoing | Copyright © 2021-2023 XingYun | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式