四月javascript工具函数

1. 第一部分:数组

1. all:布尔全等判断
元素默认转为boolean值

Boolean(fn) //是true
const all = (arr,fn=Boolean)=>arr.every(fn)
var a = all([2,2,3,4],x=>x>1)
var b = all([2,2,3,4])
console.log(a); //true
console.log(b);//true

2 allEqual:检查数组各项相等

const allEqual = arr => arr.every(val=>val===arr[0])
var a = allEqual([1,2,3,4,5,6])
var b = allEqual([1,1,1,1,1])
console.log(a); //false
console.log(b); //true

3.approximatelyEqual:约等于

const approximatelyEqual = (v1,v2,epsilon = 0.001)=>Math.abs(v1-v2)<epsilon
var a = approximatelyEqual(Math.PI/2.0,1.5708)
console.log(a); //true

4.arrayToCSV:数组转CSV格式(带空格的字符串)

const arrayToCSV = (arr,delimiter=",")=>arr.map(v=>v.map(x=>`"${x}"`).join(delimiter)).join('\n')
let a = arrayToCSV([['a','b'],['c','d']])
let b = arrayToCSV([['a','b'],['c','d']],';')
console.log(a); //'a','b' \n 'c','d'
console.log(b);//'a';'b' \n 'c';'d'

5.arrayToHtmlList:数组转li列表

此代码段将数组的元素转换为<li>标签,并将其附加到给定ID的列表中。
const arrayToHtmlList = (arr,listID)=>(
    el => (
       (el = document.querySelector("#" + listID)),
       (el.innerHTML += arr.map(item => `<li>${item}</li>`).join(''))
    ))()

arrayToHtmlList(['item 1','item 2'],'myListID')

6. average:平均数

const average = (...nums)=>nums.reduce((acc,val)=>acc+val,0)/nums.length
let a = average(...[1,2,3])
let b = average(1,2,3)
console.log(a); //2
console.log(b); //2
cons**加粗样式**t average = (...nums)=>nums.reduce((acc,val)=>acc+val,0)/nums.length
let a = average(...[1,2,3])
let b = average(1,2,3)
console.log(a); //2
console.log(b); //2

7. averageBy:数组对象属性平均数

此代码段将获取数组对象属性的平均值
const averageBy = (arr,fn)=>
    arr.map(typeof fn === 'function'? fn : val => val[fn]).reduce((acc,val)=> acc + val,0)/arr.length
    
let a = averageBy([{n:4},{n:2},{n:8},{n:6}],o => o.n)
let b = averageBy([{n:4},{n:2},{n:8},{n:6}],'n')
console.log(a); //5
console.log(b); //5

8.bifurcate:拆分断言后的数组

可以根据每个元素返回的值,使用reduce()和push() 将元素添加到第二次参数fn中 。
判断函数的第二个参数数组  里面的元素如果是true,就把第一个数组对应的放到初始数组的第一个数组中,不然就是第二个
const bifurcate = (arr,filter)=>
    arr.reduce((acc, val, i) => (acc[filter[i] ? 0 : 1].push(val),acc),[[],[]]);
var a = bifurcate(['beep', 'boop', 'foo', 'bar'], [true, true, false, true]); 
console.log(a);

9. castArray:其它类型转数组

Array.isArray用于确定传递的值是否是一个 Array。
const castArray = val => (Array.isArray(val)? val : [val])
var a  = castArray('ffo')
var b  = castArray([1])
console.log(a);// ['ffo]
console.log(b); // [1]

10. compact:去除数组中的无效/无用值

Array 类中的 filter 方法使用目的是移除所有的 ”false“ 类型元素  (false, null, undefined, 0, NaN or an empty string)
const compact = arr => arr.filter(Boolean)
var a = compact([0,1,false,2,'',3,'a','e' *23,NaN,"s",34])
console.log(a);

11. countOccurrences:检测数值出现次数

const countOccurrences = (arr,val)=>arr.reduce((a,v)=>(v === val?a+1:a),0)
var a  = countOccurrences([1,2,1,2,1,2,1],1) //4
console.log(a);

12. deepFlatten:递归扁平化数组

const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v)?deepFlatten(v):v)))
var a = deepFlatten([1,[2],[[3],4],5])
console.log(a);// [1, 2, 3, 4, 5]

13. difference:寻找差异

此代码段查找两个数组之间的差异。
const difference = (a,b)=>{
    const s = new Set(b)
    return a.filter(x => !s.has(x))
}
var a = difference([1,2,3],[1,2,4])
console.log(a); //[3]

14. differenceBy:先执行再寻找差异

在将给定函数应用于两个列表的每个元素之后,此方法返回两个数组之间的差异。
map方法会分别把数组的值作为参数执行函数  得出结果
const differenceBy = (a,b,fn)=>{
    // math函数库中的一个函数   
    const s = new Set(b.map(fn))
    return a.filter(x => !s.has(fn(x)))
}
var a = differenceBy([2.1,1.2],[2.3,3.4],Math.floor)
var b = differenceBy([{x:2},{x:1}],[{x:1}],v=>v.x)
console.log(a);//[1.2]
console.log(b); //[{x:2}]

15. dropWhile:删除不符合条件的值

此代码段从数组顶部开始删除元素,直到传递的函数返回为true。
const dropWhile = (arr,func)=>{
    while(arr.length>0&&!func(arr[0]))
    arr = arr.slice(1)
    return arr
}
let a = dropWhile([1,2,3,4],n=>n>=3)
console.log(a); //[3,4]

16. flatten:指定深度扁平化数组

此代码段第二参数可指定深度。
const flatten = (arr,depth = 1) =>
    arr.reduce((a,v)=> a.concat(depth>1&&Array.isArray(v)?flatten(v,depth-1):v),[])
var a = flatten([1,[2,3],4])
var b = flatten([1,[2,[3,[4,5],6],7],8],2)
console.log(a);
console.log(b);

17. indexOfAll:返回数组中某值的所有索引

此代码段可用于获取数组中某个值的所有索引,如果此值中未包含该值,则返回一个空数组。
const indexOfAll = (arr,val) => arr.reduce((acc,el,i)=>(el===val?[...acc,i]:acc),[])
let a = indexOfAll([1,2,3,4,5,1],1)
let b = indexOfAll([1,2,3,4,5,1],7)
console.log(a);//[0, 5]
console.log(b);//[]

18. intersection:两数组的交集

const intersection = (a,b)=>{
    const s = new Set(b)
    return a.filter(x=> s.has(x))
}
var a = intersection([1,2,3,4,5],[2,3,4,88,99])
console.log(a); //[2,3,4]

19. intersectionBy:两数组都符合条件的交集

此片段可用于在对两个数组的每个元素执行了函数之后,返回两个数组中存在的元素列表。
const intersectionBy = (a,b,fn)=>{
    const s = new Set(b.map(fn))
    return a.filter(x=>s.has(fn(x)))
}
 const a = intersectionBy([2.1,1.2],[2.3,3.4],Math.floor)
 console.log(a); //[2.1]

20. intersectionWith:先比较后返回交集

findIndex() 方法为数组中的每个元素都调用一次函数执行:
const intersectionWidth = (a,b,comp) =>a.filter(x=>b.findIndex(y=>comp(x,y))!==-1)
var a = intersectionWidth([1,1.2,1.5,3,0],[1.9,3,0,3.9],(a,b)=>Math.round(a)===Math.round(b))
console.log(a); //[1.5, 3, 0]

21. minN:返回指定长度的升序数组

sort() 方法用于对数组的元素进行排序。 数组在原数组上进行排序,不生成副本。
const minN = (arr,n=1)=>[...arr].sort((a,b)=>a-b).slice(0,n)
var a = minN([1,2,3],2)
console.log(a); //[1, 2]

22. negate:根据条件反向筛选

const negate = func => (...args)=> !func(...args)
var a = [1,2,3,4,5].filter(negate(n => n % 2 === 0))
console.log(a); //[1, 3, 5]

23. randomIntArrayInRange:生成两数之间指定长度的随机数组

现在我们得到了一个从0开始到我们定义的任意范围的数据。我们想要一个介于7-11的数值,但是现在只得到了0-5。为了把它变成7-10,我们只需要把任意我们得到的值加上7。7是我们的最小值。
调用 Array.from() 方法,传入一个类数组对象 { length }执行函数的次数 和 返回初始化值的函数。
const randomIntArrayInRange = (min,max,n=1)=>
    Array.from({length:n},()=>Math.floor(Math.random()*(max-min+1))+min)

var a = randomIntArrayInRange(7,11,5)
console.log(a);

24. sample:在指定数组中获取随机数

const sample = arr =>arr[Math.floor(Math.random()*arr.length)]
var a = sample([5,8,9,24])
console.log(a);

25. sampleSize:在指定数组中获取指定长度的随机数

此代码段可用于从数组中获取指定长度的随机数,直至穷尽数组。
使用Fisher-Yates算法对数组中的元素进行随机选择。

const sampleSize = ([...arr],n = 1)=>{
    let m = arr.length;
    while(m){
        const i = Math.floor(Math.random() * m--);
        [arr[m],arr[i]]= [arr[i],arr[m]]
    } 
    return arr.slice(0,n)
}
var a = sampleSize([1,2,3],2)
console.log(a); // [3, 2]

26. shuffle:“洗牌” 数组

此代码段使用Fisher-Yates算法随机排序数组的元素。
const shuffle = ([...arr])=>{
    let m = arr.length
    while(m){
        let i = Math.floor(Math.random()*m--);
        [arr[i],arr[m]] = [arr[m],arr[i]]
    }
    return arr
}
var a = shuffle([1,2,3])
console.log(a); //[1,3,2]

27. nest:根据parent_id生成树结构(阿里一面真题)

根据每项的parent_id,生成具体树形结构的对象。
const nest = (items,id= null,link = "parent_id")=>
items.filter(item=>item[link] ===id).map(item=>({...item,children:nest(items,item.id)}))
const comments = [
    {id:1,parent_id:null},
    {id:2,parent_id:1},
    {id:6,parent_id:1},
    {id:3,parent_id:2},
    {id:4,parent_id:3},
    {id:5,parent_id:4},
]
const a = nest(comments)
console.log(a);

2. 第二部分:函数

1.attempt:捕获函数运行异常

该代码段执行一个函数,返回结果或捕获的错误对象。
const attempt = (fn,...args) => {
    try{
        return fn(...args)
    }catch(e){
        return e instanceof Error? e :new Error(e)
    }
}
var elements = attempt(function(selector){
    return document.querySelectorAll(selector)
},'>_<')
if(elements instanceof Error) elements = [] //elements = []

2. defer:推迟执行

此代码段延迟了函数的执行,直到清除了当前调用堆栈。
第三个及以后的参数都可以作为setTimeout函数的参数。
console.log简单函数
const defer = (fn,...args) => setTimeout(fn,1,...args);
defer(console.log,'a');
console.log("b"); //lolgs b  then a

3. runPromisesInSeries:运行多个Promises

使用 Array.reduce() 通过创建 promise 链来运行连续的 promises,其中每个 promise 在 resolved 时返回下一个 promise 。
const runPromisesInseries = ps => ps.reduce((p,next)=> p.then(next),Promise.resolve());
const delay = d => new Promise(r => setTimeout(r,d))
const a = runPromisesInseries([()=>delay(1000),()=>delay(2000)])
console.log(a);

4. timeTaken:计算函数执行时间

const timeTaken = callback =>{
    console.time("timeToken")
    const r = callback()
    console.timeEnd('timeToken');
    return r
}
var a = timeTaken(()=>Math.pow(2,10))
console.log(a); //1024   timeToken: 0.016357421875ms

5. createEventHub:简单的发布/订阅模式

创建一个发布/订阅(发布-订阅)事件集线,有emit,on和off方法。
Object.create(null) 创建了一个没有继承关系的空对象
1. 使用Object.create(null)创建一个空的hub对象。
2.emit,根据event参数解析处理程序数组,然后.forEach()通过传入数据作为参数来运行每个处理程序
3. on,为事件创建一个数组(若不存在则为空数组),然后.push()将处理程序添加到该数组
4 off,用.findIndex()在事件数组中查找处理程序的索引,并使用.splice()删除。
const createEventHub = () => ({
    hub: Object.create(null),
    emit(event,data){
        (this.hub[event] || []).forEach(handler => handler(data))
    },
    on(event,handler){
        if(!this.hub[event]) this.hub[event] = [];
        this.hub[event].push(handler)
    },
    off(event,handler){
        const i = (this.hub[event]||[]).findIndex(h=>h===handler);
// splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目。会改变原始数组。
        if(i>-1) this.hub[event].splice(i,1);
        if(this.hub[event].length ===0) delete this.hub[event];
    }
})

const handler = data => console.log(data);
const hub = createEventHub();
let increment = 0;

//订阅 监听不同事件
hub.on('message',handler);
hub.on('message',()=>console.log('Message event fired'));
hub.on('increment',()=>console.log(++increment));
//发布:发出事件以调用所有订阅给它们的处理程序 并将数据作为参数传递给他们
hub.emit('message','hello world') //打印'hello world' 'Message event fired'
hub.emit('message',{hello:'word'}) //对象    'Message event fired'
hub.emit('increment');//1
//停止订阅
hub.off('message',handler)

6.memoize:缓存函数

通过实例化一个Map对象来创建一个空的缓存。
通过检查输入值的函数输出是否已缓存,返回存储一个参数的函数 该参数将被提供给已记忆的函数;如果没有,则存储并返回它。
const memoize = fn => {
    const cache = new Map()
    const cached = function(val){
        return cache.has(val)?cache.get(val):cache.set(val,fn.call(this,val)) && cache.get(val)
    }
    cached.cache = cache
    return cached
}

Ps: 这个版本可能不是很清晰,还有Vue源码版的:

Create a cached version of a pure function
export function cached < F:Function>(fn:F):F{
    const cache = Object.create(null)
    return (function cacheFn (str:string){
        const hit  = cache[str]
        return hit || (cache[str] = fn(str))
    }:any)
}

7. once:只调用一次的函数

const once = fn => {
    let called = false 
    return function(){
        if(!called){
            called = true
            fn.apply(this,arguments)
        }
    }
}

8.flattenObject:以键的路径扁平化对象

使用递归。
1 利用Object.keys(obj)联合Array.prototype.reduce(),以每片叶子节点转换为扁平的路径节点。
2 如果键的值是一个对象,则函数使用调用适当的自身prefix以创建路径Object.assign()3 否则,它将适当的前缀键值对添加到累加器对象。
4 prefix除非您希望每个键都有一个前缀,否则应始终省略第二个参数。

const flattenObject = (obj,prefix='')=>
    Object.keys(obj).reduce((acc,k)=>{
        const pre = prefix.length ? prefix + '.' :''
        if(typeof obj[k] === 'object')  Object.assign(acc,flattenObject(obj[k],pre + k));
        else acc[pre+k] = obj[k]
        return acc
    },{});
    let a = flattenObject({a:{b:{c:1}},d:1})
    console.log(a);//{a.b.c: 1, d: 1}

9. unflattenObject:以键的路径展开对象

// 与上面的相反,展开对象。
const unflattenObject = obj =>
  Object.keys(obj).reduce((acc, k) => {
    if (k.indexOf('.') !== -1) {
      const keys = k.split('.');
      Object.assign(
        acc,
        JSON.parse(
          '{' +
            keys.map((v, i) => (i !== keys.length - 1 ? `"${v}":{` : `"${v}":`)).join('') +
            obj[k] +
            '}'.repeat(keys.length)
        )
      );
    } else acc[k] = obj[k];
    return acc;
  }, {});
let a = unflattenObject({'a.b.c':1,b:1})
console.log(a);//{a: {b:{c:1}}, b: 1}
// 这个的用途,在做Tree组件或复杂表单时取值非常舒服。

第三部分:字符串

1.byteSize:返回字符串的字节长度

const byteSize = str => new Blob([str]).size;
console.log(byteSize('hello world')); //11
console.log(byteSize('😀')); //4

2. capitalize:首字母大写

const capitalize = ([first,...rest])=>
first.toUpperCase() + rest.join('')
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值