JS Common Methods (1)

This article is to record the common methods in JS, you can encapsulate them as your own utility functions for easy use in any project. The following methods are sorted out for the actual needs I encountered during my work, some of which have borrowed the essence of other people's codes (it's a long time ago, and some of the original texts can't be found), if you have a better method, welcome to leave a message for discussion! Space is limited, this article will continue to be updated.

1. Array deduplication

1.Set()

Applicable scenario: All elements in the array are of basic data types (reference types will be invalid)

let arr = [1, '2', 3, '2', false, false, true]
let newArr = [...new Set(arr)]
console.log(newArr)

2. Use object

Applicable scenario: All elements in the array are objects and have unique values

data source:

let arr = [{
  id: 1,
  name: 'zhangsan'
}, {
  id: 2,
  name: 'lisi'
}, {
  id: 1,
  name: 'zhangsan'
}]

 JS:

/** 
 * 数组去重
 * @param Array {arr} 原始数组
 * @param String {id} 数组元素的唯一标识,默认为id
 */
function arrDeduplication(arr, id = 'id') {
  if (!(arr instanceof Array)) return arr
  let obj = {}
  let newArr = []
  arr.forEach(k => {
    if (!obj[k[id]]) {
      obj[k[id]] = true  //这里仅为标记此属性已经被添加了
      newArr.push(k)
    }
  })
  return newArr
}

result: 

 There are many ways to deduplicate arrays, here are only the common and simple ones

 Second, the array is divided by a fixed length

Usage scenario: For example: sliding menu, 8 menus per page, each menu is dynamically rendered according to permissions

data source:

let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

JS:

/**
 * 数组按固定长度分割
 * @param Array {arr} 原始数组
 * @param Number {len} 长度
 */
function cutArray(arr, len) {
  if (!(arr instanceof Array) || !len) return arr
  let index = 0;
  let newArr = [];
  while (index < arr.length) {
    newArr.push(arr.slice(index, index += len));
  }
  return newArr;
}

console.log(cutArray(arr, 5))

result:

 

 3. Array permutation and combination

Applicable scene: commodity sku

data source: 

let arr = [
  ['中杯', '大杯', '超大杯'], //份量
  ['加珍珠', '加椰果', '加西米露'] //小料
]

 JS:

/** 
 * 数组排列组合
 * @param Array {arr} 原始数组(二维数组)
 */
function doCombination(arr) {
  var count = arr.length - 1; //数组长度(从0开始)
  var tmp = [];
  var totalArr = []; // 总数组
  return doCombinationCallback(arr, 0); //从第一个开始
  //js 没有静态数据,为了避免和外部数据混淆,需要使用闭包的形式
  function doCombinationCallback(arr, curr_index) {
    for (let val of arr[curr_index]) {
      tmp[curr_index] = val; //以curr_index为索引,加入数组
      //当前循环下标小于数组总长度,则需要继续调用方法
      if (curr_index < count) {
        doCombinationCallback(arr, curr_index + 1); //继续调用
      } else {
        totalArr.push(tmp); //(直接给push进去,push进去的不是值,而是值的地址)
      }
      //js  对象都是 地址引用(引用关系),每次都需要重新初始化,否则 totalArr的数据都会是最后一次的 tmp 数据;
      let oldTmp = tmp;
      tmp = [];
      for (let index of oldTmp) {
        tmp.push(index);
      }
    }
    return totalArr;
  }
}
console.log(doCombination(arr))

result:

4. Array sorting

1.sort

String data source:

let arr = ['张三', '李四', '安徒生', 'IKUN', 'FBI','Jay',
 'vitas', 'jack', 'mary', '123', '3', '24']

1.1 Numbers>Chinese characters>letters (press 1-9 for numbers, pinyin for Chinese, and aZ for English)

console.log(arr.sort((a, b) => a.localeCompare(b)))

Numeric data source:

let arr = [1, 3, 4, 5, 16, 6, 32]

1.2 Numbers are sorted from small to large

console.log(arr.sort((a, b) => a - b))

 1.3 Numbers are sorted from large to small

console.log(arr.sort((a, b) => b - a))

 1.4 Sorting the array according to a given rule

data source:

let arr = [{
  field: 'name',
  value: 2
}, {
  field: 'age',
  value: 3
}, {
  field: 'id',
  value: 1
}, {
  field: 'sex',
  value: 4
}]

Collation array:

// 排序规则数组
let order = ['id', 'name', 'job', 'age', 'city', 'sex']

JS:

console.log(arr.sort((a, b) => {
  return order.indexOf(a.field) - order.indexOf(b.field)
}))

result:

 There are many sorting methods, such as: quick sort, bubble sort, insertion sort, merge sort, etc.

 5. Convert flat array to tree structure (without recursion)

Applicable scenario: converting a tree structure into a one-dimensional array

Source: https://juejin.cn/post/6983904373508145189

data source:

let arr = [{
    id: 1,
    name: '部门1',
    pid: 0
  },
  {
    id: 2,
    name: '部门2',
    pid: 1
  },
  {
    id: 3,
    name: '部门3',
    pid: 1
  },
  {
    id: 4,
    name: '部门4',
    pid: 3
  },
  {
    id: 5,
    name: '部门5',
    pid: 4
  },
]

Ideas:

  1. The tree structure first needs to consider the top-level directory. The essence of a single top-level directory is an object, so we can first consider only the top-level directory and find out all the top-level directories
  2. After we have a top-level directory, we need to consider subdirectories. We can use children on the top-level directory to store
  3. The method to distinguish the top-level directory from the sub-directory is pid (parent id) and id , if pid is 0, it is the top-level directory, otherwise it is a sub-directory
  4. The subdirectory needs to use the id of the parent directory, that is, the pid
  5. Since it is a flattened array, we can implement it by borrowing object references without considering recursion . Use the id of the array element as the key of the object, and the array element as the value. Then in the process of traversing the object, we need to find a way to put each value in the corresponding position
  6. We can use the shallow copy of the object to realize the modification of the multi-level directory

Method 1: Double loop

function arrayToTree(items) {
  const result = []; // 存放结果集
  const itemMap = {}; // 
  // 先将数组转成对象存储
  for (const item of items) {
    itemMap[item.id] = {
      ...item
    }
  }
  for (const item of items) {
    const id = item.id;
    const pid = item.pid;
    const treeItem = itemMap[id];
    //pid === 0即当前为顶级目录
    if (pid === 0) {
      result.push(treeItem);
    } else {
      if (itemMap[pid]) {
        itemMap[pid].children = itemMap[pid].children ? itemMap[pid].children : []
        itemMap[pid].children.push(treeItem)
      }
    }
  }
  return result;
}

Method 2: Single loop

function arrayToTree2(items) {
  const result = []; // 存放结果集
  const itemMap = {}; // 
  for (const item of items) {
    const id = item.id;
    const pid = item.pid;
    if (!itemMap[id]) {
      itemMap[id] = {
        children: [],
      }
    }
    itemMap[id] = {
      ...item,
      children: itemMap[id]['children']
    }
    const treeItem = itemMap[id];
    //pid === 0即当前为顶级目录
    if (pid === 0) {
      result.push(treeItem);
    } else {
      if (!itemMap[pid]) {
        itemMap[pid] = {
          children: [],
        }
      }
      itemMap[pid].children.push(treeItem)
    }
  }
  return result;
}

result:

Code analysis:

1. First of all, both methods are implemented by using object references, by using the id of the element as the key and the element itself as the value.

2. The key of the code is after "if(pid === 0)". At first glance, it only modifies the value of itemMap, which seems to have no effect on the final returned result, but let's take a closer look. In the function, after assigning a value to the id attribute of itemMap, other operations essentially just change the reference of the object. The 5 department objects in itemMap have not changed in memory, so we directly perform these 5 department objects Modify, then as long as the data referencing them will be affected.

3. So we can directly modify the properties on the itemMap without considering the nesting relationship.

6. Date

Note: In versions below IOS16, the format "2022-03-27" is not supported in the parameters of new Date(), and needs to be replaced with "2022/03/27". The following methods do not use multi-parameter types. If you use TS, you can use function overloading.

dateStr = dateStr.replace(/\-/g, '/')

1. Date formatting

//年月日 时分秒
function formatDate(originVal) {
  const dt = new Date(originVal)

  const y = dt.getFullYear()
  const m = (dt.getMonth() + 1 + '').padStart(2, '0')
  const d = (dt.getDate() + '').padStart(2, '0')

  const hh = (dt.getHours() + '').padStart(2, '0')
  const mm = (dt.getMinutes() + '').padStart(2, '0')
  const ss = (dt.getSeconds() + '').padStart(2, '0')
  return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
}

//年月日
function formatDate2(originVal) {
  const dt = new Date(originVal)

  const y = dt.getFullYear()
  const m = (dt.getMonth() + 1 + '').padStart(2, '0')
  const d = (dt.getDate() + '').padStart(2, '0')
  return `${y}-${m}-${d}`
}

2. The day before

//dateStr为当前日期
formatTime2(new Date(dateStr).getTime() - 24 * 60 * 60 * 1000)

 3. The next day

//dateStr为当前日期 
formatTime2(new Date(dateStr).getTime() + 24 * 60 * 60 * 1000)

7. Throttle and anti-shake

 Source: uview2

  • Throttling
    means that the trigger is only triggered once within a specified time. For example, if we set 500ms, within this time, no matter how many times the button is clicked, it will only be triggered once. The specific scenario can be during panic buying. Since countless people click the button quickly, if a request is sent every time they click, it will cause huge pressure on the server. However, after we throttle, the number of requests will be greatly reduced.

  • Anti-
    shake Anti-shake means that in continuous operation, no matter how long it takes, only if there is no further operation within the specified time after a certain operation, this time will be judged valid. In specific scenarios, you can request the server to match the search results in real time during the process of entering keywords in the search box. If no processing is performed, the content of the input box keeps changing, resulting in sending requests all the time. If anti-shake processing is performed, the result is that after we input the content, there is no further input for a certain period of time (such as 500ms), and then the request is triggered.

let timer; let
    flag
/**
 * 节流原理:在一定时间内,只能触发一次
 *
 * @param {Function} func 要执行的回调函数
 * @param {Number} wait 延时的时间
 * @param {Boolean} immediate 是否立即执行
 * @return null
 */
function throttle(func, wait = 500, immediate = true) {
    if (immediate) {
        if (!flag) {
            flag = true
            // 如果是立即执行,则在wait毫秒内开始时执行
            typeof func === 'function' && func()
            timer = setTimeout(() => {
                flag = false
            }, wait)
        }
    } else if (!flag) {
        flag = true
        // 如果是非立即执行,则在wait毫秒内的结束处执行
        timer = setTimeout(() => {
            flag = false
            typeof func === 'function' && func()
        }, wait)
    }
}
let timeout = null

/**
 * 防抖原理:一定时间内,只有最后一次操作,再过wait毫秒后才执行函数
 *
 * @param {Function} func 要执行的回调函数
 * @param {Number} wait 延时的时间
 * @param {Boolean} immediate 是否立即执行
 * @return null
 */
function debounce(func, wait = 500, immediate = false) {
    // 清除定时器
    if (timeout !== null) clearTimeout(timeout)
    // 立即执行,此类情况一般用不到
    if (immediate) {
        const callNow = !timeout
        timeout = setTimeout(() => {
            timeout = null
        }, wait)
        if (callNow) typeof func === 'function' && func()
    } else {
        // 设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时wait毫秒后执行func回调方法
        timeout = setTimeout(() => {
            typeof func === 'function' && func()
        }, wait)
    }
}

 Eight, deep clone

data source:

let obj = {
  a: 123,
  b: 'zhangsan',
  c: () => {
    console.log('ccc')
  },
  d: [1, '2', {
    name: 'linxi',
    age: 18,
    info: {
      city: 'zz'
    }
  }],
  e: null,
  f: '',
  g: false,
  h: Symbol('h'),
  i: undefined,
  j: NaN
}

1. JSON.parse(JSON.stringify())

Applicable scenarios: There are no four types of function, Symbol, undefined, and NaN in the object attribute

JSON.parse(JSON.stringify(obj))

 

 2. Full version

function deepCopy(value) {
  if (value instanceof Function) return value
  else if (value instanceof Array) {
    var newValue = []
    for (let i = 0; i < value.length; ++i) newValue[i] = deepCopy(value[i])
    return newValue
  } else if (value instanceof Object) {
    var newValue = {}
    for (let i in value) newValue[i] = deepCopy(value[i])
    return newValue
  } else return value
}

 

Guess you like

Origin blog.csdn.net/Linxi_001/article/details/130922744