Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

每天一包 #28

Open
LeungKaMing opened this issue Sep 25, 2017 · 0 comments
Open

每天一包 #28

LeungKaMing opened this issue Sep 25, 2017 · 0 comments

Comments

@LeungKaMing
Copy link
Owner

LeungKaMing commented Sep 25, 2017

每天一包

Array

9.25

  1. array-first
// 该模块用于只取数组前几项,第一个参数是数组,第二个参数是选择第几个开始
var first = require('array-first')

console.log(first([1, 2, 3, 4]))  // 1

console.log(first([1, 2, 3, 4], 1)) // 1

console.log(first([1, 2, 3, 4], 3)) // [1, 2, 3]
  1. array-last
// 该模块用于只取数组后几项,第一个参数是数组,第二个参数是选择第几个开始
var last = require('array-last')

console.log(last([1, 2, 3]))  // 3

console.log(last([1, 2, 3], 1)) // 3

console.log(last([1, 2, 3], 2)) // [2, 3]
  1. arr-flatten
// // 该模块用于使多层嵌套数组变为单层嵌套,参数为一个带着多层嵌套的数组
// flatten - 使...平坦
// implementation  - 实现
var flatten = require('arr-flatten')

console.log(flatten(['a', ['b', ['c']], 'd', ['e']])) // [ 'a', 'b', 'c', 'd', 'e' ]
  1. array-each
/* 该模块用于遍历数组每一项,并且每一项都调用传入的函数
 * 1. 等同于lodash的_.each / _.forEach
 * 2. 没返回
 */
var each = require('array-each')

var temp = []
each([1, 2, 3, 4, 5], (item, index)=>{
  temp.push(`I am element ${item}`)
})
console.log(temp) // [ 'I am element 1','I am element 2','I am element 3','I am element 4','I am element 5' ]
  1. array-map
/* 原生JS的map方法相对较慢,而且相关数组map库都专注于浏览器的兼容,导致既臃肿又满足不到非浏览器的需求。
 * 1. 所以这个插件的实现会使在node.js运行中更轻更快
 * 2. 并且该插件通过映射返回一个新的数组,区别于each
 */
var map = require('arr-map')
const arr = ['a', 'b', 'c']

var result = map(arr, (item, index)=>{
  item = item + 's'
  return item
})
console.log(result) // [ 'as', 'bs', 'cs' ]
  1. arr-filter
/* 该模块用于过滤数组,筛选条件就是根据返回的值 */
const filter = require('arr-filter')
let result = []

result = filter([1, 2, 'd', 3, {a: 'I am a'}, 'c'], (item)=>{
  return typeof item === 'string'
})

console.log(result) // ['d', 'c']
  1. is-sorted
// 该模块用于判断数组是否按照一定规则排序
const sorted = require('is-sorted')

console.log(sorted([1, 2, 3]))  // true

console.log(sorted([3, 1, 2]))  // false

console.log(sorted([3, 2, 1], (a, b)=>b-a))  // true, 第二个参数为回调函数,返回一个倒序排列
  1. arr-diff
/* 该模块用于对比参数之间的不同,默认是拿第一个跟第二个参数做对比,放在前面的做参照物
 */
const diff = require('arr-diff')

const a = ['a', 'b', 'c', 1]
const b = ['a', 'c', 'h']

console.log(diff(a, b)) // ['b', 1]
console.log(diff(b, a)) // ['h']

9.26

  1. array-intersection
// 该模块用于 将数组间多次引用的元素提取并去重,生成一个新数组
const intersection = require('array-intersection')
console.log(intersection(['a', 'a', 'c']))  // ['a', 'c']
console.log(intersection(['a', 'b', 'c'], ['b', 'c', 'd', 'e']))  // ['b', 'c']
console.log(intersection(['a', 'a', 'c'], ['a', 'b', 'c'], ['b', 'c'])) // ['c']
  1. arr-reduce
/** 这个模块用于遍历数组每个元素,让第一个元素跟第二个元素相加得到的结果和第三个比较,以此类推,得到总值
 *  1. 跟原生数组的reduce用法差不多,只是更快了
 *  2. reduce的参数有三个:第一个是数组,第二个是回调函数,第三个是初始值;如果指定了初始值,则让初始值跟第一个元素相加得到的结果和第二个比较,以此类推
 */
const reduce = require('arr-reduce')

// 普通用法
let temp = reduce([1, 2, 3, 4, 5], (prev, curr)=>{
  return prev + curr
})
console.log(temp) // 15

// 初始值
let temp2 = reduce([1, 2, 3, 4, 5], (prev, curr)=>{
  return prev + curr
}, 6)
console.log(temp2)  // 21

// 遍历数组每一项跟初始数组通过数组合并的方法结合再返回
let temp3 = reduce(['b', 'c'], (prev, curr)=>{
  return prev.concat(curr)
}, ['a'])
console.log(temp3)  // ['a', 'b', 'c']
  1. array-union
// 该模块用于合并数组,等同于原生的concat,还自带去重
const union = require('arr-union')

// 一般用法
const result = union(['a'], ['b', 'c'], ['d', 'e', 'f'])
console.log(result) // [ 'a', 'b', 'c', 'd', 'e', 'f' ]

// 自带去重
const result2 = union(['a'], ['a', 'b', 'c'], ['d', 'b', 'e', 'f'])
console.log(result2) // [ 'a', 'b', 'c', 'd', 'e', 'f' ]
  1. array-unique
// 该模块用于去重
// 1. 直接去重的话,生成新数组的同时会影响原数组
var unique = require("array-unique")
var arr = ['a', 'b', 'c', 'c'];
console.log(unique(arr)) //=> ['a', 'b', 'c'] 
console.log(arr)         //=> ['a', 'b', 'c', 'c'] 

var unique2 = require("array-unique").immutable;
var arr2 = ['a', 'b', 'c', 'c'];
console.log(unique2(arr2)) //=> ['a', 'b', 'c'] 
console.log(arr2)         //=> ['a', 'b', 'c', 'c'] 
  1. arr-pluck
// 该模块用于 将数组里面的每个带有某个属性的元素检索出来,用它们的值生成新的数组
const pluck = require('arr-pluck');
const arr = [{'a': 1, 'b': 2, 'c': 3}, {'a': 0, 'b': 6}];
// 把带有属性名为a的元素检索出来,用它们的值生成新的数组
console.log(pluck(arr, 'a'))  // [1, 0]
  1. array-xor
/* 该模块用于对比数组,如果数组之间存在相同的值则忽略,先来先到,最后返回一个合并后的新数组
 */
const xor = require('array-xor')

const a = [1, 2, 3, 5, 9]
const b = [3, 4]
const c = [3, 5, 9, 4]

console.log(xor(a)) // [1, 2, 3, 5, 9]
console.log(xor(a, b)) // [1, 2, 5, 9, 4]
console.log(xor(a, c)) // [1, 2, 4]
console.log(xor(a, b, c)) // [1, 2, 3]
  1. collection-map => 自由定制数组
// 该模块用于 将对象任意一项转换成数组,第一个参数是对象,第二个参数是回调函数,回调函数的第一个参数是每项对象的值,第二个参数是每项对象的键,第三个参数是整个对象
const col = require('collection-map')

/*
 * foo a { a: 'foo', b: 'bar', c: 'baz' }
 * bar b { a: 'foo', b: 'bar', c: 'baz' }
 * baz c { a: 'foo', b: 'bar', c: 'baz' }
 */
let result = col({a: 'foo', b: 'bar', c: 'baz'}, (val, key, obj)=>{
  return val
})
console.log(result) // [ 'foo', 'bar', 'baz' ]

let result2 = col({a: 'foo', b: 'bar', c: 'baz'}, (val, key, obj)=>{
  return key
})
console.log(result2)  // ['a', 'b', 'c']
  1. dedupe
// 该模块用于数组去重,生产的新数组并不会影响原数组
const dedupe = require('dedupe')
const a = [1, 2, 2, 3, 6]
const b = dedupe(a)
console.log(a, b) // [1, 2, 2, 3, 6][1, 2, 3, 6]

// 对数组内对象元素进行去重
const c = [{a: 2}, {a: 1}, {a: 1}, {a: 1}]
const d = dedupe(c)
console.log(c, d)

// 还能对数组内带有特定键名的对象元素进行去重
const e = [{a: 2, b: 1}, {a: 1, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}]
const f = dedupe(e, value => value.a)
console.log(e, f)
  1. array-range
// 该模块可以将给定范围的数字生成一个数组;只传一个参数,默认从0到参数之间的范围;传两个参数,从第一个参数到第二个参数之间的范围。
const range = require('array-range')
console.log(range(3)) // [ 0, 1, 2 ]
console.log(range(1, 10)) // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

// 多用于函数式编程,例如es6
console.log(range(3).map( x => x*x )) // [ 0, 1, 4 ]
console.log(range(1, 10).filter( x => x%2===0 )) // [ 2, 4, 6, 8 ]

// 什么都不传,默认返回空数组
console.log(range())

// 接受负数
console.log(range(-3, 3))
  1. filled-array
// 该模块用于根据指定参数生成数组;第一个参数为数字/字符串时,第二个参数表示循环次数;第一个参数为函数时,第二个参数表示循环次数
const filledArray = require('filled-array')

// 字符串
console.log(filledArray('ljm', 3))  // [ 'ljm', 'ljm', 'ljm' ]
// 数字
console.log(filledArray(23, 3)) // [23, 23, 23]
// 函数
console.log(filledArray((item) => {
  return (++item % 3 ? item : 'nomatch') || item
}, 10)) // [ 1, 2, 'nomatch', 4, 5, 'nomatch', 7, 8, 'nomatch', 10 ]

9.27

qs

该包专门用于转换url参数。但有更多奇淫技巧。

  1. qs.parse(string, [options]),参数:第一个参数是字符串,例如'a=1&b=2';第二个参数为可选选项
var qs = require('qs');
console.log(qs.parse('a=1&b=2')); // { a: '1', b: '2' }
console.log(qs.stringify({ a: '1', b: '2' })); // 'a=1&b=2'

1. 参数转换为对象

// 可以多层嵌套
console.log(qs.parse('foo[bar]=baz'))  // { foo: { bar: baz } }
console.log(qs.parse('foo[bar][baz]=foobarbaz'))  // { foo: { bar: { baz: 'foobarbaz' } } }
// 但嵌套只转换前3层,大于3层以上是不会进行转换的;但可以通过添加可选选项depth进行嵌套层数的挑选
console.log(qs.parse('a[b][c][d][e][f][g][h][i]=j', {depth: 1}))  // { a: { b: { c: [Object] } } }
console.log(qs.parse('a[b][c][d][e][f][g][h][i]=j'))  // { a: { b: { c: [Object] } } }

// 可以转换uri encoded格式的字符串
console.log(qs.parse('a%5Bb%5D=c')) // { a: { b: 'c' } }

// 限制转换参数
console.log(qs.parse('a=b&c=d', { parameterLimit: 1 })) // { a: 'b' }

// 是否转换带符号的字符串
console.log(qs.parse('?a=b&c=d', { ignoreQueryPrefix: true })) // { 'a': 'b', c: 'd' }
console.log(qs.parse('?a=b&c=d', { ignoreQueryPrefix: false })) // { '?a': 'b', c: 'd' }

// 以某个分隔符作为划分界限
console.log(qs.parse('a=b;c=d', { delimiter: ';' }))  // { a: 'b', c: 'd' }
// 还能用来做正则过滤
console.log(qs.parse('a=b;c=d,e=f', { delimiter: /[;,]/ })) // { a: 'b', c: 'd', e: 'f' }

// 开启小标点模式
console.log(qs.parse('a.b=c', { allowDots: true })) // { a: { b: 'c' } },等同于a[b]=c

2. 参数转换为数组
// 对比于a[b]=c => a{ b: c },既然没有键名,那就会被转换成数组
console.log(qs.parse('a[]=b&a[]=c'))  // { a: [ 'b', 'c' ] }

// 键名只要是数字,也会被转换成数组;并且数字表示转换后数组的排列顺序
console.log(qs.parse('a[1]=c&a[0]=b'))  // { a: [ 'b', 'c' ] }
// 键名是数字,但是由于qs限制数组里的索引最大不能超过20,所以21会被转换成对象的键名 => 注意这种情况只要有一个参数存在,其余参数也会被转换成 键名为索引 的对象
console.log(qs.parse('a[21]=b')) // { a: { 21: 'b' } } 
console.log(qs.parse('a[21]=b&a[10]=c')) // { a: { '10': 'c', '21': 'b' } }

// 正常情况下
console.log(qs.parse('a[1]=b')) // {a: ['b']}
// 限制转换参数
console.log(qs.parse('a[1]=b', { arrayLimit: 0 })) // {a: { 1: 'b'}}

// 参数的键名既是数字,又是变量的话,则统一当成对象处理
console.log(qs.parse('a[0]=b&a[b]=c'))  // { a: {0: b, b: c} }

// 创建对象数组
console.log(qs.parse('a[][b]=c')) // { a: [{b: c}] }

// 值不填,也会被转换成数组
console.log(qs.parse('a[]=&a[]=b')) // { a: [ '', 'b' ] }

// 
console.log(qs.parse('a=b', { decoder: (str)=>{
  console.log(str)  // 依次分别是a 和 b
  return str
} })) // {a: 'b'}

// 2. qs.stringify(object, [options])
// 正常转换单层对象
console.log(qs.stringify( {a: 'b'} )) // a=b

// 转换多层对象,默认是会对括号进行uri加密
console.log(qs.stringify({a: {b: 'c'}}))  // a%5Bb%5D=c
// 转换多层对象,不对括号进行uri加密
console.log(qs.stringify({a: {b: 'c'}}, { encode: false }))  // a[b]=c

// 多层嵌套
console.log(qs.stringify({ a: { b: { c: 'd', e: 'f' } } }, {encode: false}))  // a[b][c]=d&a[b][e]=f

// false表示对嵌套都做uri加密处理
console.log(qs.stringify({ a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] }, { encodeValuesOnly: false })) // a=b&c%5B0%5D=d&c%5B1%5D=e%3Df&f%5B0%5D%5B0%5D=g&f%5B1%5D%5B0%5D=h
// true表示对嵌套不做uri加密处理
console.log(qs.stringify({ a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] }, { encodeValuesOnly: true })) // a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h

// 自定义加密处理规则,encode如果设置为false则自定义规则不生效
let result = qs.stringify({ a: { b: 'c' } }, { encoder: function (str) {
  // Passed in values `a`, `b`, `c`
  console.log(str)  // 依次分别是a[b] 和 'c'
  return str// Return encoded string
}})
console.log(result) // a[b] = c

// 如何将转换成的数组索引去掉
console.log(qs.stringify({ a: ['b', 'c', 'd'] }, { encode: false }))  // a[0]=b&a[1]=c&a[2]=d
console.log(qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false })) // a=b&a=c&a=d

// 通过指定格式转换
console.log(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices', encode: false })) // a[0]=b&a[1]=c
console.log(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets', encode: false }))  // a[]=b&a[]=c
console.log(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat', encode: false }))  // a=b&a=c

// 转换成小数点
console.log(qs.stringify({ a: { b: { c: 'd', e: 'f' } } }, { allowDots: true }))  // a.b.c=d&a.b.e=f

// 空值
console.log(qs.stringify({ a: '' }))  // a=
console.log(qs.stringify( { a: [] } ))  // ''
console.log(qs.stringify( { a: {} } ))  // ''
console.log(qs.stringify( { a: [{}] } ))  // ''
console.log(qs.stringify( { a: { b: []} } ))  // ''
console.log(qs.stringify( { a: { b: {}} } ))  // ''
console.log(qs.stringify({ a: null, b: undefined }))  // a=

// 加入请求标记
console.log(qs.stringify({ a: 'b', c: 'd' }, { addQueryPrefix: true })) // ?a=b&c=d

// 0929
// 转换成以某个操作符做间隔的字符串,替代&
console.log(qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' })) // a=b;c=d

// 可通过serialzeDate 自定义转换时间规则
console.log(qs.stringify({ a: new Date(7) })) // a=1970-01-01T00%3A00%3A00.007Z
console.log(qs.stringify({ a: new Date(7) }, { serializeDate: function (d) { console.log(d);return d.getTime(); } })) // a=7

// 可通过自定义规则进行排序
// srcStr.localeCompare(tarStr) srcStr < tarStr,返回-1;srcStr > tarStr,返回大于0的数;srcStr = tarStr,返回0
function alphabeticalSort(a, b) {
  console.log(a, b) // 分别代表各自键名,用键名进行比较
  return a.localeCompare(b);
}
console.log(qs.stringify({ a: 'c', z: 'y', b : 'f' }, { sort: alphabeticalSort }))  // a=c&b=f&z=y

// 可通过过滤规则进行筛选转换后的字符串,一般传递的是一个跟在最终生成字符串存在的数组,也可以传递的是一个函数
/* prefix - 键名 value - 值
 * 首先将整个对象看成prefix,然后遍历对象的每个键名作为prefix,对应的键值作为value,最后通过return代表每次遍历的拼接字符串方式
 */
function filterFunc(prefix, value) {
  console.log(`Filter:key: ${prefix}, value: ${value}`)
  if (prefix == 'b') {
      // Return an `undefined` value to omit a property.
      return;
  }
  if (prefix == 'e[f]') {
      return value.getTime();
  }
  if (prefix == 'e[g][0]') {
      return value * 2;
  }
  return value;
}
// 通过encodeValuesOnly不对结果进行uri加密
console.log(qs.stringify({ a: 'b', c: 'd', e: { f: new Date(123), g: [2] } }, { filter: filterFunc, encodeValuesOnly: true }))  // a=b&c=d&e[f]=123&e[g][0]=4
console.log(qs.stringify({ a: 'b', c: 'd', e: 'f' }, { filter: ['a', 'e'] })) // a=b&e=f,只过滤跟数组元素吻合的键值对
console.log(qs.stringify({ a: ['b', 'c', 'd'], e: 'f' }, { filter: ['a', 0, 2], encodeValuesOnly: true }))  // a[0]=b&a[2]=d,只过滤跟数组元素吻合的键值对

// 3. 处理空值
// 转成字符串时:null或者空值 会被当成空字符串
console.log(qs.stringify({a: null, b: ''})) // a=&b=
// 使用strictNullHandling,能把值为null转换后的值 去除=
console.log(qs.stringify({a: null, b: ''}, { strictNullHandling: true })) // a&b=

// 转成对象时:键值不存在或者等于空 会被当成空字符串
console.log(qs.parse('a&b=')) // {a: '', b: ''}
// 使用strictNullHandling,能把值为null转换后的值 去除=
console.log(qs.parse('a&b=', { strictNullHandling: true })) // { a: null, b: '' }

// 忽略值为null的进行转换
console.log(qs.stringify({ a: 'b', c: null}, { skipNulls: true }))  // a=b

// 运用特定模块进行加密转换
console.log(qs.stringify({ a: 'こんにちは!' }, { encoder: encoder }))
// 运用特定模块进行解密转换
console.log(qs.parse('a=%82%B1%82%F1%82%C9%82%BF%82%CD%81I', { decoder: decoder })) // { a: 'こんにちは!' }

// 对空格进行RFC 3986 或者 RFC 1738的加密,默认使用RFC 3986加密
console.log(qs.stringify({ a: 'b c' })) // a=b%20c
console.log(qs.stringify({ a: 'b c' }, { format : 'RFC3986' })) // a=b%20c
console.log(qs.stringify({ a: 'b c' }, { format : 'RFC1738' })) // a=b+c

file-type

/* 该模块用于对 【文件流 / 图片流】 做类型校验
 * 返回一个带着两个键值对的对象 => ext: 支持的文件类型 mime: 支持的媒体类型;如果不匹配会返回null
 * 支持的文件类型如下:(不包含svg,针对判断是否为svg的文件类型可以使用这个模块:https://github.com/sindresorhus/is-svg)
 * jpg
 * png
 * gif
 * webp
 * flif
 * cr2
 * tif
 * bmp
 * jxr
 * psd
 * zip
 * tar
 * rar
 * gz
 * bz2
 * 7z
 * dmg
 * mp4
 * m4v
 * mid
 * mkv
 * webm
 * mov
 * avi
 * wmv
 * mpg
 * mp3
 * m4a
 * ogg
 * opus
 * flac
 * wav
 * amr
 * pdf
 * epub
 * exe
 * swf
 * rtf
 * woff
 * woff2
 * eot
 * ttf
 * otf
 * ico
 * flv
 * ps
 * xz
 * sqlite
 * nes
 * crx
 * xpi
 * cab
 * deb
 * ar
 * rpm
 * Z
 * lz
 * msi
 * mxf
 * mts
 * wasm
 * blend
 * bpg
 * docx
 * pptx
 * xlsx
 */
// Node.js核心模块
const fs = require('fs')

// 第三方模块
const readChunk = require('read-chunk');  // 跟fs.readFileSync / fs.readFile有什么分别
const fileType = require('file-type');
const http = require('http')

// 使用第三方模块同步读取文件(应该是封装了fs.read*方法)
const buffer = readChunk.sync('../unicorn.jpg', 0, 4100);
console.log(fileType(buffer)) // { ext: 'jpg', mime: 'image/jpeg' },ext表示后缀,mime表示媒体类型
// 使用核心模块同步读取文件
const file = fs.readFileSync('../unicorn.jpg')
console.log(fileType(file)) // { ext: 'jpg', mime: 'image/jpeg' },ext表示后缀,mime表示媒体类型

const url = 'http://assets-cdn.github.com/images/spinners/octocat-spinner-32.gif';
http.get(url, res => {
   res.once('data', chunk => {
      console.log(chunk)  // <Buffer 47 49 46 38 39 61 20 00 20 00 a2 07 00 82 82 82 b3 b3 b3 f8 f8 f8 e2 e2 e2 99 99 99 cc cc cc ca ca ca ff ff ff 21 ff 0b 4e 45 54 53 43 41 50 45 32 2e ... >
      console.log(fileType(chunk)) // {ext: 'gif', mime: 'image/gif'}
      res.destroy()
   })
})

read-chunk

// 该模块用于 从文件内读取块 => 为什么不用fs.readFile?因为
const readChunk = require('read-chunk')

/* 直接readChunk.sync得出的结果是一个Buffer类型的数据。
 * 如果是单一Buffer(只读文件,而不是服务端监听并接收客户端请求的参数),则可以通过toString()方法来把Buffer数据转换成字符串输出;
 * 如果是流类型的Buffer(服务端监听并接收客户端请求的参数),则需要通过string_decoder这个模块来把流类型的Buffer数据转换成字符串输出,详情:https://stackoverflow.com/questions/12121775/convert-streamed-buffers-to-utf8-string;
 * 参数:filepath 文件路径 position 开始读的位置 length读取多少个数量的bytes
 */
// 1. readChunk(filepath, position, length) 返回一个Promise形式的Buffer
console.log(readChunk('./test.txt', 1, 3))  // Promise { <pending> }

// 2. readChunk.sync(filepath, position, length) 返回Buffer
console.log(readChunk.sync('./test.txt', 1, 3))  // <Buffer 65 6c 6c>
console.log(readChunk.sync('./test.txt', 1, 3).toString('utf8'))  // ell

余下的有:
学习资源:
https://github.com/node-modules
https://github.com/parro-it/awesome-micro-npm-packages
https://github.com/sindresorhus/awesome-nodejs
跟markdown相关的有:
https://github.com/jonschlinkert/remarkable;
比较出名的有:
ioredis
redis
@LeungKaMing LeungKaMing changed the title 0925 每天一包 Sep 26, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant