• 【知识总结】开发提效50%的Javascript常用函数


    1、简单的数组去重

    扩展运算符 + es6

    const arr = ['a','b','c','a','b'];
    const newArr = [...new Set(arr)]
    
    • 1
    • 2

    Array.from + Set

    const arr = ['a','b','c','a','b'];
    const newArr = Array.from(new Set(arr))
    
    • 1
    • 2

    2、数组深拷贝

    只拷贝一层,适合简单的拷贝,不适用于数组对象

    const arr = [1,2,3]
    
    const arr1 = arr.slice(0)
    const arr2 = arr.concat()
    const arr3 = [...arr]
    const arr4 = Array.from(arr)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    使用JSON:

    const arr = [{age: 1}, {age: 2}, {age: 3}];
    const newArr = JSON.parse(JSON.stringify(arr))
    
    • 1
    • 2

    ⚠️注意:这种方式不可靠,需要注意以下几种情况

    const obj = {
      nan: NaN, // NaN拷贝后变成null
      infinityMax:1.7976931348623157E+10308,  // 浮点数的最大值拷贝后变成null
      infinityMin:-1.7976931348623157E+10308, // 浮点数的最小值拷贝后变成null
      undef: undefined, // 拷贝后直接丢失
      fun: () => 'func', // 拷贝后直接丢失
      date:new Date, // 时间类型拷贝后会被变成字符串类型数据
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    JSON.stringify 的目的是将数据转成 json 格式,而 json 有自己的规范,并不是 js 专属,它是跨语言的,各种语言都用统一的 json 格式来通信,所以只能支持各种语言常用的数据类型。

    更可靠的实现方式:

    function deepClone(target){
    	if(Array.isArray(target)){	//处理数组
    		return target.map(item => deepClone(item))
    	}
    	if(Object.prototype.toString.call(target)==='[object Object]'){
    	//先将对象转化为二维数组,再将二维数组转化为对象
    	//所以map方法将二维数组里的元素进行深拷贝完了再转化为对象
    		return Object.fromEntries(Object.entries(target).map(([k, v]) => [k, deepCopy(v)]))
    	}
    	return target
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3、数组合并

    扩展运算符,不改变原数组:

    const arr1 = [1, 2];
    const arr2 = [3, 4];
    const arr3 = [...arr1, ...arr2]
    
    • 1
    • 2
    • 3

    扩展运算符,改变原数组:

    const arr1 = [1, 2];
    const arr2 = [3, 4];
    arr1.push(...arr2)
    
    • 1
    • 2
    • 3

    concat方法:

    const arr1 = [1, 2];
    const arr2 = [3, 4];
    const newArr = arr1.concat(arr2)
    
    • 1
    • 2
    • 3

    apply方法:

    const arr1 = [1, 2];
    const arr2 = [3, 4];
    arr1.push.apply(arr1, arr2)
    
    • 1
    • 2
    • 3

    4、对象数组去重

    arrDistinctByKey(arr, key){
    	const temp = new Map()	//使用Map可以对比多类型,不限于字符串
    	return arr.filter((item) => !temp.has(item[key]) && temp.set(item[key], true))
    }
    //常用于过滤列表
    const list = [{id: 1, name: 'xiaoming'}, {id: 1, name: 'xiaoming'}, {id: 2, name: 'xiaoliang'}];
    const newArr = arrDistinctByKey(list, 'id');
    // newArr: [{id: 1, name: 'xiaoming'}, {id: 2, name: 'xiaoliang'}]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    5、对象数组取交集

    arrIntersectionByKey(arr1,arr2,key){
    	const arr2Keys = arr2.map(item => item[key])
    	return arr1.filter(item => arr2Keys.includes(item[key]))
    }
    
    const receivedCoupons = [{ name: '立减券' },{ name: '折扣券' }]; 
    const welfareCoupons = [{ stockId: '立减券' }];
    
    arrIntersectionByKey(receivedCoupons,welfareCoupons, 'name');
    // [{ name: '立减券' }]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    6、使用flat和flatMap方法处理嵌套数组

    数据样例:

    // 选项组数组,这是一个筛选组件的数据
    const optionsGroup = [
      {
        groupTitle: '资源类型',
        groupId: 'current',
        mode: 'multi',
        options: [
          { text: '直流桩', value: [1, 3], active: true },
          { text: '交流桩', value: [2, 4, 5], active: false },
        ],
      },
      {
        groupTitle: '通勤方式',
        groupId: 'commute',
        mode: 'multi',  // 多选
        options: [
          { text: '公交', value: 0, active: true },
          { text: '地铁', value: 1, active: true },
          { text: '驾车', value: 1, active: false },
        ],
      },
    ];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    尝试将上面数组处理为下面这样的数据结构:

    [
      { text: '公交', value: 0, active: true, groupId: 'commute' },
      ...
    ],
    
    • 1
    • 2
    • 3
    • 4

    使用flatMap:相当于在map的功能基础上,加上了flat方法的效果,flat方法的效果是将数组降维一层

    const activated = optionGroup
    	.flatMap(item => item.options.map(option => ({...option, groupId: item.groupId}) ))
    	.filter(item => item.active)
    
    • 1
    • 2
    • 3

    7、快速创建一个指定长度的数组并填充内容

    const array = new Array(100).fill('');
    // (100) ['', '', ..., '']
    
    • 1
    • 2
    const array = Array.from(new Array(100).keys())
    
    • 1
    const array = Array.from({length: 100}, (v,i) => i);
    
    • 1

    8、利用数组交换值

    [a,b] = [b,a]
    
    • 1

    9、替代短路或,使用includes,该方式也是可避免代码复杂度过高的有效方法之一

    if(from == 'a' || from == 'b' || from == 'c'){}
    
    if([a,b,c].includes(from)){}
    
    • 1
    • 2
    • 3

    10、使用Map代替switch或多个if判断,该方式也是可避免代码复杂度过高的有效方法之一

    switch写法:

    function getStatusText(status) {
      switch (status) {
        case 1:
          return '待发货';
        case 2:
          return '已发货';
        case 3:
          return '已完成';
        default:
          return '';
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    Map写法:

    const statusMap = new Map([
      [1, '待发货'],
      [2, '已发货'],
      [3, '已完成'],
    ]); // 这种写法的内部执行的算法实际上也是循环执行set
    const statusText = statusMap.get(statusMap)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    注意区分 Object 和 Map,只有模拟现实世界的实体对象时,才使用 Object。如果只是需要key: value的数据结构,使用 Map 结构。因为 Map 有内建的遍历机制。

    11、更可靠的判断数据类型

    typeof 检测一些基本的数据类型,正则、{}、[]、null输出结果为object:

     console.log(typeof /\d/); //object
     console.log(typeof {}); //object
     console.log(typeof []); //object
     console.log(typeof (null)); //object
     console.log(typeof 123); //number
     console.log(typeof true); //boolean
     console.log(typeof function () {}); //function
     console.log(typeof (undefined)); //undefined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    A instanceof B 判断a的构造器是否为b:

    function b = {}
    let a = new b
    console.log(a instanceof b); //true
    console.log(b instanceof Object); //true
    let arr = [1,2,3,4];
    console.log(arr instanceof Array); //true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    以上两种方法有有其局限性,推荐使用更可靠的判断数据类型方法

    function judgeDataType(val, type) {
      const dataType = Object.prototype.toString.call(val).replace(/\[object (\w+)\]/, "$1").toLowerCase();
      return type ? dataType === type : dataType;
    }
    console.log(judgeDataType("young")); // "string"
    console.log(judgeDataType(20190214)); // "number"
    console.log(judgeDataType(true)); // "boolean"
    console.log(judgeDataType([], "array")); // true
    console.log(judgeDataType({}, "array")); // false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    12、检查是否为空对象

    Object.keys({}).length //0
    JSON.stringify({})==='{}'
    
    • 1
    • 2

    13、校验数据类型

    export const typeOf = function(obj){
    	return Object.prototype.toString.call(obj).slice(8,-1).toLowerCase()
    }
    
    • 1
    • 2
    • 3

    14、防抖

    export const debounce = (()=>{
    	let timer = null
    	return (callback, wait = 800)=>{
    		timer && cleartTimeout(timer)
    		timer = setTimeout(callback, wait)
    	}
    })()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    使用:

    const loadList =()=>{
        debounce(() => {
          console.log('加载数据')
        }, 500)
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    15、节流

    export const throttle =(()=>{	
    	let last = 0
    	return (callback, wait = 800) =>{
    		let now = + new Date()
    		if(now - last > wait){
    			callback()
    			last = now
    		}
    	}
    })()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    16、滚动到页面顶部

    export const scrollToTop =()=>{
    	const height = document.documentElement.scrllTop || document.body.scrollTop
    	if(height>0){
    		window.requestAnimationFrame(scrollTop)
    		window.scrollTo(0, height - height/8)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    17、滚动到元素位置

    export const smoonthScroll = element => {
    	document.querySelector(element).scrollIntoView({
    		behavior: 'smooth'
    	})
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    使用:

    smoothScroll('#target'); // 平滑滚动到 ID 为 target 的元素
    
    • 1

    18、遍历树节点

    export const foreachTree = (data, callback, childrenName = 'children'){
    	for(let i=0; i<data.length; i++){
    		callback(data[i])
    		if(data[i][childrenName] && data[i][childrenName].length > 0){
    			foreachTree(data[i][childrenName], callback, childrenName)
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    假设我们要从树状结构数据中查找 id 为 9 的节点:

    const treeData = [{
      id: 1,
      label: '一级 1',
      children: [{
        id: 4,
        label: '二级 1-1',
        children: [{
          id: 9,
          label: '三级 1-1-1'
        }, {
          id: 10,
          label: '三级 1-1-2'
        }]
      }]
     }, {
      id: 2,
      label: '一级 2',
      children: [{
        id: 5,
        label: '二级 2-1'
      }, {
        id: 6,
        label: '二级 2-2'
      }]
      }, {
        id: 3,
        label: '一级 3',
        children: [{
          id: 7,
          label: '二级 3-1'
        }, {
          id: 8,
          label: '二级 3-2'
        }]
    }],
    
    let result
    foreachTree(data, (item) => {
      if (item.id === 9) {
        result = item
      }
    })
    console.log('result', result)  // {id: 9,label: "三级 1-1-1"}   
    
    • 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

    19、获取数组最后一项

    const arr = [1, 2, 3, 4, 5];
    arr[arr.length - 1]  // 5
    
    • 1
    • 2
    arr.slice(-1) // [5]
    
    • 1

    slice 也并不会修改原来的数组

    20、循环执行异步操作后执行

    在执行异步任务的时候,都会返回一个可以停止事件的函数,调用函数就可以停止任务。任务的多少是取决于实际操作的,而不是你决定的。你需要将这些任务都关闭后,再去做其他操作。

    const queue = [fn1, fn2, ...]
    async function start(){
    	await Promise.all(
    		queue.map(async(callback)=>{
    			await callback()
    		})
    	)
    	do something()
    }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    21、异步队列执行

    有时候频繁接收一些任务,但是还没来得及执行,所以需要把这些任务都放到队列里面,然后再按顺序执行。这时候就可以写一个数组来存储这些任务。

    const queue = [fn1, fn2, ...]
    async function start(){
    	if(queue.length == 0) return
    	await queue[0]()
    	queue.shift()
    	start()
    }
    for(let i=0; i<queue.length; i++){
    	await queue[0]()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 相关阅读:
    C现代方法(第9章)笔记——函数
    Django中序列化器or模型单独使用
    股票交易接口使用步骤
    Matlab/C++源码实现RGB通道与HSV通道的转换(效果对比Halcon)
    pool = multiprocessing.Pool()报错:module object has no attribute Pool
    《安富莱嵌入式周报》第278期:基于RUST编程语言RTOS,固态继电器芯片,微软发布物联网组件框架,支持多款蜂窝,LoRa和WiFi芯片工业物联网4.0书籍
    [JavaScript]_[初级]_[不使用JQuery原生Ajax提交表单]
    在云服务器中搭建MQTT平台
    【C++ Primer Plus学习记录】数组的替代品vector、array
    AIE有机荧光探针/荧光高分子纳米微球AIE-PEN FPNs/AIE有机荧光分子带电荷微球
  • 原文地址:https://blog.csdn.net/weixin_42224055/article/details/126381806