npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

viperjs

v1.0.2

Published

常用js片段组成的工具库,代码是es6编写,可以拿出单条片段进行babel再使用。

Readme

viperjs

常用js片段组成的工具库,代码是es6编写,可以拿出单条片段进行babel再使用。

获取

# npm 
npm install viperjs

目录

ARRAY

BROWSER

FUNCTION

Math

OBJECT

OBJECT

Type

UTILITY

ARRAY

ArrayConcat

数组拼接

    viper.ArrayConcat = (arr, ...args) => [].concat(arr, ...args);
viper.ArrayConcat([1], [1, 2, 3, [4]]) //  [1, 2, 3, [4]]

⬆ Back to top

difference

数组比较 过滤出数组 a中数组b不包含的值

    viper.difference = (a, b) => {
        const s = new Set(b)
        return a.filter(x => !s.has(x))
    }
viper.difference([1,2,3], [1,2]) 
// [3]

⬆ Back to top

includes

数组|字符串包含

    viper.includes = (collection, val, formIdex=0) => collection.slice(formIdex).indexOf(val) != -1
viper.includes("30-seconds-of-code", "code") // true
viper.includes([1, 2, 3, 4], [1, 2], 1) // false

⬆ Back to top

intersection

数组交集 返回两数组中同时包含的值

    viper.intersection = (a, b) => { const s = new Set(b); return a.filter(x => s.has(x))}
viper.intersection([1,2,3], [4,3,2]) // [2,3] 

⬆ Back to top

remove

根据函数移除数组中的元素并返回移除元素

    viper.remove = (arr, fn) => Array.isArray(arr) ? arr.filter(fn).reduce((acc, val) => {
        arr.splice(arr.indexOf(val), 1); 
        return acc.concat(val)
    }, []) : []
viper.remove([1, 2, 3, 4], n => n % 2 == 0)  //  [2, 4]

⬆ Back to top

sample

随机获取数组或字符串中一个元素

    viper.sample = arr => arr[Math.floor(Math.random() * arr.length)]
viper.sample([1,2,3]) // 2 

⬆ Back to top

sampleSize

从数组中获取n个随机元素,最大为数组的大小

    viper.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);
};
viper.sampleSize([1, 2, 3], 2); // [1,3]
viper.sampleSize([1, 2, 3], 4); // [1,3,2]

⬆ Back to top

chunk

chunk分割成指定大小的数组, 如果不能整分,剩余的会组成一个新的数组

    viper.chunk = (arr, size) => Array.from({length: Math.ceil(arr.length / size)}, (v, i) =>{
        return arr.slice(i * size, i * size + size)
    })
viper.chunk([1, 2, 3, 4, 5], 2); // [[1,2],[3,4],[5]]

⬆ Back to top 

compact

删除数组中错误的值 false, null, 0, “”, undefined, and NaN

   viper.compact = arr => arr.filter(Boolean)
viper.compact([1, false, NaN]) //  [1]

⬆ Back to top

countOccurrences

统计数组中某个值出现的次数

    viper.countOccurrences = (arr, val) => arr.reduce((a, v)=>(v === val ? a + 1 : a + 0), 0);
viper.countOccurrences([1, 1, 2, 1, 2, 3], 1); // 3

⬆ Back to top

deepFlatten

深度平铺数组 转换为一维数组

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

⬆ Back to top

flatten

创建指定唯度的数组 默认为1

    viper.flatten = (arr, depth =1) => depth != 1 
        ? arr.reduce((a, v) => a.concat(Array.isArray(v) ? flatten(v, depth - 1) : v), [])
        : arr.reduce((a, v) => a.concat(v), [])
viper.flatten([1, [2, [3, [4, 5], 6], 7], 8], 2); // [1, 2, 3, [4, 5], 6, 7, 8]
viper.flatten([1, [2], 3, 4]); // [1, 2, 3, 4]

⬆ Back to top

forEachRight

从数组右边开始对每个元素执行指定函数

    viper.forEachRight = (arr, callback) => arr.slice(0).reverse().forEach(callback)
viper.forEachRight([1, 2, 3, 4], val => console.log(val)); // '4', '3', '2', '1'

⬆ Back to top

distinctValuesOfArray

数组去重

   viper.distinctValuesOfArray = arr => [...new Set(arr)]
viper.distinctValuesOfArray([1, 2, 2, 3, 4, 4, 5]); // [1,2,3,4,5]

⬆ Back to top

sampleSize

从右删除指定位置n的元素, n默认为1

    viper.dropRight = (arr, n = 1) => arr.slice(0, -n)
};
viper.dropRight([1, 2, 3]); // [1,2]
viper.dropRight([1, 2, 3], 2); // [1]
viper.dropRight([1, 2, 3], 42); // []

⬆ Back to top

everyNth

返回数组中的每个第n个元素

    viper.everyNth = (arr, nth) => arr.filter((e, i) => i % nth === nth - 1);
viper.everyNth([1, 2, 3, 4, 5, 6], 2); // [ 2, 4, 6 ]

⬆ Back to top

ArrayConcat

返回数组中唯一值

    viper.filterNonUnique = arr => arr.filter( i => arr.indexOf(i) === arr.lastIndexOf(i))
viper.filterNonUnique([1, 2, 2, 3, 4, 4, 5]); // [1,3,5]

⬆ Back to top

11111111

indexOfAll

返回数组中val出现的所有索引

    viper.indexOfAll = (arr, val) => {
        const indices = []
        arr.forEach((el, i) => el === val && indices.push(i))
        return indices
    }
viper.indexOfAll([1, 2, 3, 1, 2, 3], 1); // [0,3]
viper.indexOfAll([1, 2, 3], 4); // []

⬆ Back to top

initial

返回除最后一个数组外的所有元素

    viper.initial = (arr) => arr.slice(0, -1)
initial([1, 2, 3]); // [1,2]

⬆ Back to top

initializeArrayWithRange

初始化一个包含指定范围中的数字的数组

    viper.initializeArrayWithRange = (end, start = 0, step = 1) => Array.from({length : Math.ceil((end + 1 -start) / step)}).map((v, i)=> i * step + start)
viper.initializeArrayWithRange(7, 3); // [3,4,5,6,7]
viper.initializeArrayWithRange(9, 0, 2); // [0,2,4,6,8]

⬆ Back to top

initializeArrayWithValues

初始化指定长度并填充初始值

    viper.initializeArrayWithValues = (n, val = 0) => Array(n).fill(val)
viper.initializeArrayWithValues(5, 2); // [2,2,2,2,2]

⬆ Back to top

isSorted

是否排序 正序返回1 降序返回-1 未排序返回0

    viper.isSorted = arr => {
        const direction = arr[0] > arr[1] ? -1 : 1;
        for(let [i, val] of arr.entries()){
            if(i === arr.length - 1){
                return direction
            } else if((val - arr[i + 1]) * direction > 0){
                return 0
            }
        }
    }
viper.isSorted([0, 1, 2, 2]); // 1
viper.isSorted([4, 3, 2]); // -1
viper.isSorted([4, 3, 5]); // 0

⬆ Back to top

join

使用分隔符和结束符拼接所有数组中的元素并返回拼接好的字符串

   viper.join = (arr, separator = ',', end = separator) => arr.reduce((acc, val, i) => i == arr.length - 2 ? acc + val + end : i == arr.length - 1 ? acc + val : acc + val + separator, '')
};
viper.join(['pen', 'pineapple', 'apple', 'pen'], ',', '&'); // "pen,pineapple,apple&pen"
viper.join(['pen', 'pineapple', 'apple', 'pen'], ','); // "pen,pineapple,apple,pen"
viper.join(['pen', 'pineapple', 'apple', 'pen']); // "pen,pineapple,apple,pen"

⬆ Back to top

last

返回最后一个元素

    viper.last = arr => arr[arr.length - 1];
viper.last([1, 2, 3]); // 3

⬆ Back to top 

longestItem

返回多个可迭代对象中长度最长的一个

   viper.longestItem = (...vals) => [...vals].sort((a, b) => b.length - a.length)[0]
viper.longestItem(...['a', 'ab', 'abc'], 'abcd'); // 'abcd'
viper.longestItem([1, 2, 3], [1, 2], [1, 2, 3, 4, 5]); // [1, 2, 3, 4, 5]
viper.longestItem([1, 2, 3], 'foobar'); // 'foobar'

⬆ Back to top

maxN

从提供的数组中返回n个最大元素 如果n大于或等于提供的数组长度,则返回原始数组(按降序排列)

    viper.maxN = (arr, n = 1) => [...arr].sort((a,b) => b - a).slice(0, n)
viper.maxN([1, 2, 3]); // [3]
viper.maxN([1, 2, 3], 2); // [3,2]

⬆ Back to top

minN

从提供的数组中返回n个最小元素。如果n大于或等于提供的数组长度,则返回原始数组(按升序排序)

    viper.minN = (arr, n =1) => [...arr].sort((a, b) => a - b).slice(0, n)
viper.minN([1, 2, 3]); // [1]
viper.minN([1, 2, 3], 2); // [1,2]

⬆ Back to top

nthElement

返回数组的第n个元素

    viper.nthElement = (arr, n = 0) => (n > 0 ? arr.slice(n , n + 1) : arr.slice(n)[0])
viper.nthElement(['a', 'b', 'c'], 1); // 'b'
viper.nthElement(['a', 'b', 'b'], -3); // 'a'

⬆ Back to top

partition

根据所提供的函数对每个元素的真实性将这些元素分成两个数组

    viper.partition = (arr, fn) =>{
        return  arr.reduce(
            (acc, val, i, arr) => {
                acc[fn(val, i, arr) ? 0 : 1].push(val)
                return acc
            },
            [[], []]
        )
    }
const users = [{ user: 'barney', age: 36, active: false }, { user: 'fred', age: 40, active: true }];
viper.partition(users, o => o.active); // [[{ 'user': 'fred',    'age': 40, 'active': true }],[{ 'user': 'barney',  'age': 36, 'active': false }]]

⬆ Back to top

pull

返回的过滤指定的值后的数组

   viper.pull = (arr, ...args) => {
        let argState = Array.isArray(args[0]) ? args[0] : args;
        let pulled = arr.filter((v, i) => !argState.includes(v));
        arr.length = 0;
        pulled.forEach(v => arr.push(v))
    }
let myArray = ['a', 'b', 'c', 'a', 'b', 'c'];
viper.pull(myArray, 'a', 'c'); // myArray = [ 'b', 'b' ]

⬆ Back to top

pullAtIndex

返回的过滤指定的索引后的数组, 返回过滤的值

    viper.pullAtIndex = (arr, pullArr) => {
        let removed = [];
        let pulled = arr.map((v, i) => pullArr.includes(i) ? removed.push(v) : v).filter((v, i)=> !pullArr.includes(i))
        arr.length = 0;
        pulled.forEach(v => arr.push(v))
        return removed
    }
};
let myArray = ['a', 'b', 'c', 'd'];
let pulled = viper.pullAtIndex(myArray, [1, 3]); // myArray = [ 'a', 'c' ] , pulled = [ 'b', 'd' ]

⬆ Back to top

pullAtValue

改变原始数组以过滤出指定的值,返回删除的元素

    viper.pullAtValue = (arr, pullArr) => {
        let removed = [],
            pushToRemove = arr.forEach((v, i)=> (pullArr.includes(v) ? removed.push(v) : v)),
            mutateTo = arr.filter((v,i) => !pullArr.includes(v));
        arr.length = 0
        mutateTo.forEach(v => arr.push(v))
        return removed
    }
let myArray = ['a', 'b', 'c', 'd'];
let pulled = viper.pullAtValue(myArray, ['b', 'd']); // myArray = [ 'a', 'c' ] , pulled = [ 'b', 'd' ]

⬆ Back to top

reducedFilter

根据条件过滤一个对象数组,同时过滤未指定的键

    viper.reducedFilter = (data, keys, fn) => data.filter(fn).map(el => keys.reduce((acc, key) => {
        acc[key] = el[key]
        return acc
    }, {}))
const data = [
  {
    id: 1,
    name: 'john',
    age: 24
  },
  {
    id: 2,
    name: 'mike',
    age: 50
  }
];

viper.reducedFilter(data, ['id', 'name'], item => item.age > 24); // [{ id: 2, name: 'mike'}]

⬆ Back to top

shuffle

洗牌数组

   viper.shuffle = ([...arr]) => {
        let m = arr.length;
        while (m) {
            const i = Math.floor(Math.random() * m--);
            [arr[m], arr[i]] = [arr[i], arr[m]];
        }
        return arr
    }
const foo = [1, 2, 3];
viper.shuffle(foo); // [2,3,1], foo = [1,2,3]

⬆ Back to top

similarity

获取数组交集

    viper.similarity = (arr, values) => arr.filter(v => values.includes(v))
};
viper.similarity([1, 2, 3], [1, 2, 4]); // [1,2]

⬆ Back to top

symmetricDifference

返回两个数组之间的不同值

    viper.symmetricDifference = (a, b) => {
        const sA = new Set(a), 
            sB = new Set(b);
        return [...a.filterx(x => !sB.has(x)), ...b.filter(x => !sA.has(x))]
    }
viper.symmetricDifference([1, 2, 3], [1, 2, 4]); // [3,4]

⬆ Back to top

tail

返回数组中除第一个元素外的所有元素

    viper.tail = arr => (arr.length > 1 ? arr.slice(1) : arr)
viper.tail([1, 2, 3]); // [2,3]
viper.tail([1]); // [1]

⬆ Back to top

take

返回从头开始删除n个元素的数组

    viper.take = (arr, n = 1) => arr.slice(0 ,n)
viper.take([1, 2, 3], 5); // [1, 2, 3]
viper.take([1, 2, 3], 0); // []

⬆ Back to top

takeRight

返回从最后删除n个元素的数组

    viper.takeRight = (arr, n = 1) => arr.slice(arr.length - n, arr.length)
viper.takeRight([1, 2, 3], 2); // [ 2, 3 ]
viper.takeRight([1, 2, 3]); // [3]

⬆ Back to top

union

返回数组合集

    viper.union = (a ,b) => Array.from(new Set([...a, ...b]))
viper.union([1, 2, 3], [4, 3, 2]); // [1,2,3,4]

⬆ Back to top

without

创建一个排除所有给定值的数组

    viper.without = (arr, ...args) => arr.filter(v => args.indexOf(v) === -1)
viper.without([2, 1, 2, 3], 1, 2); // [3]

⬆ Back to top

zip

根据原始数组中的位置进行分组创建新的数组 如果参数数组的长度不一致,那么在未找到值的地方使用undefined

    viper.zip = (...arrays) => {
        const maxLength = Math.max(...arrays.map(x => x.length));
        return Array.from({length : maxLength}).map((_, i) => {
            return Array.from({length : arrays.length}, (_, k) => arrays[k][i])
        })
    }
viper.zip(['a', 'b'], [1, 2], [true, false]); // [['a', 1, true], ['b', 2, false]]
viper.zip(['a'], [1, 2], [true, false]); // [['a', 1, true], [undefined, 2, false]]

⬆ Back to top

zipObject

给定一组有效的属性标识符和一个值数组,返回一个将属性关联到值的对象,未找到值的地方使用undefined

   viper.zipObject = (props, values) => props.reduce((obj, prop, index) => ((obj[prop] = values[index]), obj), {})
};
viper.zipObject(['a', 'b', 'c'], [1, 2]); // {a: 1, b: 2, c: undefined}
viper.zipObject(['a', 'b'], [1, 2, 3]); // {a: 1, b: 2}

⬆ Back to top

average

求数字数组的平均数

    viper.average = arr => arr.reduce((acc, val) => acc + val, 0) / arr.length
viper.average([1,2,3]) // 2

⬆ Back to top 

BROWSER

copyToClipboard

复制字符串到剪贴板

    viper.copyToClipboard = str => {
        const el = document.createElement('textarea')
        el.value = str
        el.setAttribute('readonly', '')
        el.style.position = 'absolute'
        el.style.left ='-9999px'
        document.body.appendChild(el)

        const selected = document.getSelection().rangeCount > 0 ? document.getSelection().getRangeAt(0) : false

        el.select()
        document.execCommand('copy')
        document.body.removeChild(el)
        if(selected){
            document.getSelection().removeAllRanges()
            document.getSelection().addRange(selected)
        }
    }
viper.copyToClipboard('111') //  111复制到了剪贴板

⬆ Back to top

getScrollPosition

返回当前页面的滚动位置

    viper.getScrollPosition = (el = window) =>({
        x: el.pageXOffset !== undefined ? el.pageXOffset : el.scrollLeft,
        y: el.pageYOffset !== undefined ? el.pageYOffset : el.scrollTop
    })
viper.getScrollPosition() //  {x: 3, y: 6023}

⬆ Back to top

getStyle

返回指定元素的CSS规则的值

    viper.getStyle = (el, ruleName) => getComputedStyle(el)[ruleName]
viper.getStyle(document.querySelector('p'), 'font-sise') // 16px

⬆ Back to top

hasClass

元素是否包含类

    viper.hasClass = (el, className) => el.classList.contains(className)}
viper.hasClass(document.querySelector('p.box'), 'box') // ture

⬆ Back to top

hide

隐藏指定所有元素

    viper.hide = (...el) => [...el].forEach( e => (e.style.display = 'node'))s
viper.hide(document.querySelectorAll('img')) // 页面中的所以img被隐藏

⬆ Back to top

scrollToTop

平滑返回顶部

    viper.scrollToTop  = () => {
        const c = document.documentElement.scrollTop || document.body.scrollTop
        if(c > 0){
            window.requestAnimationFrame(scrollToTop)
            window.scrollTo(0, c - c / 8)
        }
    }
viper.scrollToTop() // 页面返回顶部

⬆ Back to top

steStyle

设置元素的css样式

    viper.steStyle = (el, ruleNmae, val) =>{ el.style[ruleNmae] = val }
viper.steStyle(document.querySelector('p'), 'font-size', '18px') // 第一个p元素字体大小为18像素

⬆ Back to top

show

显示所有指定的元素

    viper.show = (...el) => [...el].forEach(e.style.display = '')
viper.show(document.querySelectorAll('img')) // 显示所有img标签

⬆ Back to top 

toggleClass

切换元素类名

   viper.toggleClass = (el, className) => el.classList.toggleClass(className)
viper.toggleClass(document.querySelector('div.box'), 'box') // 切换box类名

⬆ Back to top

FUNCTION

once

确保函数只调用一次

    viper.once = fn => {
        let called = false;
        return function(...args){
            if(called) return
            called = true
            return fn.call(this, args)
        }
    }
document.body.addEventListener('click', once(()=>{console.log(111)})) // 函数只会调用一次

⬆ Back to top

debounce

防抖

    viper.debounce = (func, wait, immediate) => {

        var timeout, result;

        return function () {
            var context = this;
            var args = arguments;

            if (timeout) clearTimeout(timeout);
            if (immediate) {
                // 如果已经执行过,不再执行
                var callNow = !timeout;
                timeout = setTimeout(function(){
                    timeout = null;
                }, wait)
                if (callNow) func.apply(context, args)
            }
            else {
                timeout = setTimeout(function(){
                    func.apply(context, args)
                }, wait);
            }
        }
    }
var count = 1;
var container = document.body;

function getUserAction() {
    console.log(count)
};

container.onmousemove = viper.debounce(getUserAction, 1000);

⬆ Back to top

MATH

factorial

阶乘

    viper.factorial = n => n <= 1 ? 1 : n * factorial(n - 1)
viper.factorial(6) // 720

⬆ Back to top

gcd

最大公约数

    viper.gcd = (x, y) => !y ? x : gcd(y, x % y);
viper.gcd(8, 36) // 4
viper.gcd(...[8, 36, 12]) // 4

⬆ Back to top

inRange

是否在指定范围内

    viper.inRange = (n, start, end = null) => {
        if(end && start > end) end = [start, (start = end)][0]
        return end == null ? n >= 0 && n < start : n >= start && n < end 
    }
viper.inRange(3, 4, 5) // false
viper.inRange(3, 4) // true

⬆ Back to top

isDivisible

数值2能否否能整除数值1

    viper.isDivisible = (first, second) => second % first === 0
viper.isDivisible(3, 9) // true

⬆ Back to top

randomIntegerInRange

随机获取指定范围内的整数

     viper.randomIntegerInRange = (min, max) => Math.floor(Math.random() * ( max - min + 1)) + min
viper.randomIntegerInRange(2, 5) // 3

⬆ Back to top

randomNumberInRange

随机获取指定范围内的小数

    viper.randomNumberInRange = (min, max) => Math.random() * (max - min) + min
viper.randomNumberInRange(2, 10); // 6.0211363285087005

⬆ Back to top

round

返回指定位数的小数,省略第二个参数 四舍五入为整数

    viper.round = (n, decimals=0) => Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`)
viper.round(4.22) // 4
viper.round(1.005, 2); // 1.01

⬆ Back to top

OBJECT

pick

从对象中挑选与给定键对应的键值对

    viper.pick = (obj, arr) => arr.reduce((acc, curr)=> (curr in obj && (acc[curr] = obj[curr]), acc), {})
viper.pick({ a: 1, b: '2', c: 3 }, ['a', 'c']); // { 'a': 1, 'c': 3 }

⬆ Back to top

cleanObj

删除指定属性外的其他属性

    viper.cleanObj = (obj, keysToKeep = [], childIndicator) => {
        Object.keys(obj).forEach(key => {
            if(key === childIndicator) {
                cleanObj(obj[key], keysToKeep, childIndicator)
            } else if(!keysToKeep.includes(key)){
                delete obj[key]
            }
        })
        return obj
    }
const testObj = { a: 1, b: 2, children: { a: 1, b: 2 } };
viper.cleanObj(testObj, ['a'], 'children'); // { a: 1, children : { a: 1}}

⬆ Back to top

invertKeyValues

反转key和value

    viper.invertKeyValues = obj => Object.keys(obj).reduce((acc, key)=> {
        acc[obj[key]] = key
        return acc
    },{})
viper.invertKeyValues({ name: 'John', age: 20 }); // { 20: 'age', John: 'name' }

⬆ Back to top

lowercaseKeys

小写所有key

    viper.lowercaseKeys = obj => Object.keys(obj).reduce((acc, key)=> {
        acc[key.toLowerCase()] = obj[key]
        return acc
    },{})
const myObj = { Name: 'Adam', sUrnAME: 'Smith' };
const myObjLower = viper.lowercaseKeys(myObj); // {name: 'Adam', surname: 'Smith'};

⬆ Back to top

merge

合并两个或者多个对象

    viper.merge = (...objs) => [...objs].reduce(
        (acc, obj) => Object.keys(obj).reduce(
            (a, k) => {
                 acc[k] = acc.hasOwnProperty(k) ? [].concat(acc[k]).concat(obj[k]) : obj[k];
                 return acc
            },{}),
        {}
    )
const object = {
  a: [{ x: 2 }, { y: 4 }],
  b: 1
};
const other = {
  a: { z: 3 },
  b: [2, 3],
  c: 'foo'
};
viper.merge(object, other); // { a: [ { x: 2 }, { y: 4 }, { z: 3 } ], b: [ 1, 2, 3 ], c: 'foo' }

⬆ Back to top

size

获取对象、数组、字符串的大小

    viper.size = val => Array.isArray(val) ? val.length : val && typeof val === 'object' ? val.size || val.length || Object.keys(val).length : typeof val === 'string' ? new Blob([val]).size : 0
viper.size([1, 2, 3, 4, 5]); // 5
viper.size('size'); // 4
viper.size({ one: 1, two: 2, three: 3 }); // 3

⬆ Back to top

STRING

digitize

将数值字符串转换成数组

    viper.digitize = n => [...`${n}`].map(i => parseInt(i))
viper.digitize(123); // [1, 2, 3]

⬆ Back to top

anagrams

生成一个字符串所有的排列组合

    viper.anagrams = str => {
        if(str.length <= 2) return str.length === 2 ? [str, str[1] + str[0]] : str
        return str.split('').reduce((acc, letter, i) => acc.concat(anagrams(str.slice(0, i) + str.slice(i + 1)).map(val => letter + val)), [])
    }
viper.anagrams('abc'); // ['abc','acb','bac','bca','cab','cba']

⬆ Back to top

byteSize

返回字节大小

    viper.byteSize = str => new Blob([val]).size
viper.byteSize('😀'); // 4
viper.byteSize('Hello World'); // 11

⬆ Back to top

Capitalize

首字母大写

    viper.Capitalize = ([first, ...rest], lowerRest = false) => first.toUpperCase() + (lowerRest ? rest.join('').toLowerCase() : rest.join(''))
viper.Capitalize('fooBar'); // 'FooBar'
viper.Capitalize('fooBar', true); // 'Foobar'

⬆ Back to top

capitalizeEveryWord

大写单词的每个首字母

    viper.capitalizeEveryWord = str => str.replace(/\d[a-z]/g, char => char.toUpperCase())
viper.capitalizeEveryWord('hello world!'); // 'Hello World!'

⬆ Back to top

decapitalize

首字母小写

    viper.decapitalize = ([first, ...rest], upperRest = false) => first.toLowerCase() + (upperRest ? rest.join('').toUpperCase() : rest.join(''));
viper.decapitalize('FooBar'); // 'fooBar'
viper.decapitalize('FooBar', true); // 'fOOBAR'

⬆ Back to top

escapeHTML

转义HTML

    viper.escapeHTML = str => str.replace(
        /[&<>'"]/g,
        tag => ({
            '&': '&amp;',
            '<': '&lt;',
            '>': '&gt;',
            "'": '&#39;',
            '"': '&quot;'
        })([tag] || tag)
    )
viper.escapeHTML('<a href="#">Me & you</a>'); // '&lt;a href=&quot;#&quot;&gt;Me &amp; you&lt;/a&gt;'

⬆ Back to top

fromCamelCase

将驼峰字符改成字符串

   viper.fromCamelCase = (str, separator = '_') => str.replace(/([a-z\d])(A-Z)/g, '$1' + separator + '$2').replace(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1' + separator + '$2').toLowerCase()
viper.fromCamelCase('someDatabaseFieldName', ' '); // 'some database field name'
viper.fromCamelCase('someLabelThatNeedsToBeCamelized', '-'); // 'some-label-that-needs-to-be-camelized'
viper.fromCamelCase('someJavascriptProperty', '_'); // 'some_javascript_property'

⬆ Back to top

mask

用指定的字符替换除最后指定个字符以外的所有字符

    viper.mask = (str, num = 4, mask = '*') => {
        return ('' + str).slice(0, -num).replace(/./g, mask) + ('' + str).slice(-num)
    }
viper.mask(1234567890); // '******7890'
viper.mask(1234567890, 3); // '*******890'
viper.mask(1234567890, -4, '$'); // '$$$$567890'

⬆ Back to top

palindrome

检查回文

     viper.palindrome = (str) => {
        const s = str.toLowerCase().replace(/[\W_]/g, '')
        return (
            s === s.split().reverse().join('')
        )
    }
viper.palindrome('taco cat'); // true

⬆ Back to top

reverseString

反转字符串

    viper.reverseString = (str) => [...str].reverse().join('')
viper.reverseString('viper') // repiv

⬆ Back to top

sortString

按字母顺序排列字符串中的字符

    viper.sortString = (str) => [...str].sort((a, b) => a.localeCompare(b)).join('')
viper.sortString('cabbage'); // 'aabbceg'

⬆ Back to top

toCamelCase

将字符串改为驼峰字符串

    viper.toCamelCase = (str) => {
        let s = 
            str && 
            str
            .match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
            .map(x => x.slice(0, 1).toUpperCase() + x.slice(1).toLowerCase())
            .join('');
        return s.slice(0, 1).toLowerCase() + s.slice(1)
    }
viper.toCamelCase('some_database_field_name'); // 'someDatabaseFieldName'
viper.toCamelCase('Some label that needs to be camelized'); // 'someLabelThatNeedsToBeCamelized'
viper.toCamelCase('some-javascript-property'); // 'someJavascriptProperty'

⬆ Back to top

truncateString

截断字符串在后面添加…

    viper.truncateString = (str, num) => {
        return str.length > num ? str.slice(0, num > 3 ? num -3 : num) + '...' : str
    }
truncateString('boomerang', 7); // 'boom...'

⬆ Back to top

unescapeHTML

反转义HTML字符串

   viper.unescapeHTML = (str) => str.replace(
        /&amp;|&lt;|&gt;|&#39;|&quot;/g,
        tag =>
        ({
            '&amp;': '&',
            '&lt;': '<',
            '&gt;': '>',
            '&#39;': "'",
            '&quot;': '"'
        }[tag] || tag)
    )
viper.unescapeHTML('&lt;a href=&quot;#&quot;&gt;Me &amp; you&lt;/a&gt;'); // '<a href="#">Me & you</a>'

⬆ Back to top

TYPE

digitize

校验字符是否是json

      viper.isValidJSON = obj => {
        try {
            JSON.parse(obj)
        } catch (e) {
            return false
        }
    }
viper.isValidJSON('{"name":"Adam","age":20}'); // true
viper.isValidJSON('{"name":"Adam",age:"20"}'); // false
viper.isValidJSON(null); // true

⬆ Back to top

getType

获取类型 undefined、null、NaN 直接返回 其他返回小写的构造函数的名称

    viper.getType = v => v !== v ? 'NaN' : v === undefined ? 'undefined' : v === null ? 'null' : v.constructor.name.toLowerCase()
viper.getType(new Set([1, 2, 3])); // 'set'
viper.getType({}) // object
viper.getType([]) // array

⬆ Back to top

UTILITY

coalesce

返回第一个非null非undefined的值

    viper.coalesce = (...args) => args.find( _ => ![undefined, null].includes(_))
viper.coalesce(null, undefined, '', NaN, 'Waldo'); // ""

⬆ Back to top

coalesceFactory

返回第一个符合过滤函数的值

    viper.coalesceFactory = valid => (...args) => args.find(valid)
const customCoalesce = coalesceFactory(_ => ![null, undefined, '', NaN].includes(_));
viper.customCoalesce(undefined, null, NaN, '', 'Waldo'); // "Waldo"

⬆ Back to top

extendHex

将3位数的hex颜色值转换成6为数的值

    viper.extendHex = shortHex => '#' + shortHex.slice(shortHex.startsWith('#') ? 1 : 0).split('').map(x => x + x ).join('')
viper.extendHex('#03f'); // '#0033ff'

⬆ Back to top

getURLParams

返回对象包含url上的参数

   viper.getURLParams = url => url.match(/([^?=&]+)(=([^&]*))/g).reduce(
        (a, v) => ((a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1 )),a), {}
    )
viper.getURLParams('http://url.com/page?name=Adam&surname=Smith'); // {name: 'Adam', surname: 'Smith'}

⬆ Back to top

hexToRGB

hex转rgb

    viper.hexToRGB = hex => {
        let alpha = false,
        h = hex.slice(hex.startsWith('#') ? 1 : 0);
        if (h.length === 3) h = [...h].map(x => x + x).join('');
        else if (h.length === 8) alpha = true;
        h = parseInt(h, 16);
        return (
            'rgb' +
            (alpha ? 'a' : '') +
            '(' +
            (h >>> (alpha ? 24 : 16)) +
            ', ' +
            ((h & (alpha ? 0x00ff0000 : 0x00ff00)) >>> (alpha ? 16 : 8)) +
            ', ' +
            ((h & (alpha ? 0x0000ff00 : 0x0000ff)) >>> (alpha ? 8 : 0)) +
            (alpha ? `, ${h & 0x000000ff}` : '') +
            ')'
        );
    }
viper.hexToRGB('#27ae60ff'); // 'rgba(39, 174, 96, 255)'
viper.hexToRGB('27ae60'); // 'rgb(39, 174, 96)'
viper.hexToRGB('#fff'); // 'rgb(255, 255, 255)'

⬆ Back to top

randomHexCode

随机生成hex颜色值

    viper.randomHexCode = () => {
        let n = ((Math.random() * 0xfffff) | 0).toString(16)
        return '#' + (n.length !== 6 ? ((Math.random() * 0xf) | 0).toString(16) + n : n)
    }
viper.randomHexCode()  // "#e34155"

⬆ Back to top

RGBToHex

RGB转hex色值

    viper.RGBToHex = (r, g, b) => ((r << 16) + (g << 8) + b).toString(16).padStart(6, '0')
viper.RGBToHex(255, 165, 1); // 'ffa501'

⬆ Back to top

timeTaken

返回函数运行时长

    viper.timeTaken = callback => {
        console.time('timeTaken')
        const cb = callback()
        console.timeEnd('timeTaken')
        return cb
    }
viper.timeTaken(() => Math.pow(2, 10)); // 1024, (logged): timeTaken: 0.02099609375ms

⬆ Back to top

UUIDGeneratorBrowser

使用crypto API 生成UUID 符合RFC4122 版本 4

    viper.UUIDGeneratorBrowser = () => {
       return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
            (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
        )
    }
viper.UUIDGeneratorBrowser() // '7982fcfe-5721-4632-bede-6000885be57d'

⬆ Back to top

validEmail

邮箱验证

   viper.validEmail = str => /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(str)
viper.validEmail('[email protected]') //  true

⬆ Back to top