前言
30-seconds 是一个学习系列,基本都是通过简短的代码实现某些功能, 包含
- 30-seconds-of-code
满足所有开发需求的简短JavaScript代码片段 - 30-seconds-of-css
满足所有开发需求的简短CSS代码片段 - 30-seconds-of-react
满足所有开发需求的简短React代码片段
等等,还有很多系列, 我们今天的主题是 30-seconds-of-code , 即简短的代码段。
挑选了我觉得比较有意思或者有意义的15个代码,我们一起开始简短代码之旅吧!
精选
URLJoin
地址拼接。 除此之外,URLSearchParams
或URL
都可以很好的处理QueryString, 更多详情参见 私藏的这些高级工具函数,你拥有几个?
const URLJoin = (...args) => args .join('/') .replace(/[\/]+/g, '/') .replace(/^(.+):\//, '$1://') .replace(/^file:/, 'file:/') .replace(/\/(\?|&|#[^!])/g, '$1') .replace(/\?/g, '&') .replace('&', '?'); 复制代码
示例
URLJoin('http://www.google.com', 'a', '/b/cd', '?foo=123', '?bar=foo'); // 'http://www.google.com/a/b/cd?foo=123&bar=foo' 复制代码
uncurry
减少嵌套函数调用次数,改变函数的传参方式。 这是反柯里化吗?
这个函数非常灵活,很有意思。
const uncurry = (fn, n = 1) => (...args) => { const next = acc => args => args.reduce((x, y) => x(y), acc); if (n > args.length) throw new RangeError('Arguments too few!'); return next(fn)(args.slice(0, n)); }; 复制代码
const add = x => y => z => x + y + z; const uncurriedAdd1 = uncurry(add, 1); uncurriedAdd1(1)(2)(3) // 6 const uncurriedAdd1 = uncurry(add, 2); uncurriedAdd1(1,2)(3) // 6 const uncurriedAdd3 = uncurry(add, 3); uncurriedAdd3(1, 2, 3); // 6 复制代码
onScrollStop
监听滚动停止事件,当停止滚动的时候,执行回调函数。
需要在停止滚动后,执行某些操作,还是很有用的。
const onScrollStop = callback => { let isScrolling; window.addEventListener( 'scroll', e => { clearTimeout(isScrolling); isScrolling = setTimeout(() => { callback(); }, 150); }, false ); }; 复制代码
onScrollStop(() => { console.log('The user has stopped scrolling'); }); 复制代码
byteSize
返回字符串字节数。
都知道,中文和英文所占的字节数是不一样的,有占两个的,三个的,四个的,一个的。
英文一般一个字节,中文一般三个。
const byteSize = str => new Blob([str]).size; 复制代码
byteSize('a') // 1 byteSize('س') // 2 byteSize('中') // 3 byteSize('😀'); // 4 byteSize('Hello World'); // 11 复制代码
这还涉及 Unicode编码的知识,为了验证更多字符,你可以查阅 Unicode对应表
runPromisesInSeries
顺序执行promise, 实际上应该生成Promise的函数。
const runPromisesInSeries = ps => ps.reduce((p, next) => p.then(next), Promise.resolve()); 复制代码
const delay = d => new Promise(r => setTimeout(r, d)); runPromisesInSeries([() => delay(1000), () => delay(2000)]); // Executes each promise sequentially, taking a total of 3 seconds to complete 复制代码
这个版本,不能传参,我在 私藏的这些高级工具函数,你拥有几个?, 实现了一个带参数版本。
function runPromises(promiseCreators, initData) { return promiseCreators .reduce((promise, next) => promise .then((data) => next(data)) , Promise.resolve(initData)); } 复制代码
var promise1 = function (data = 0) { return new Promise(resolve => { resolve(data + 1000); }); } var promise2 = function (data) { return new Promise(resolve => { resolve(data -500); }); } runPromises([promise1, promise2], 1).then(res=>console.log(res)); // 501 复制代码
stringifyCircularJSON
将包含循环引用的 JSON 对象序列化为 JSON 格式。
其思路是使用WeakSet
保存数据进行对比。
const stringifyCircularJSON = obj => { const seen = new WeakSet(); return JSON.stringify(obj, (k, v) => { if (v !== null && typeof v === 'object') { if (seen.has(v)) return; seen.add(v); } return v; }); }; 复制代码
const obj = { n: 42 }; obj.obj = obj; stringifyCircularJSON(obj); // '{"n": 42}' 复制代码
UUIDGeneratorBrowser
UUID生成器,除此之外URL.createObjectURL也可以生成UUID。这两种算是比较主流的方式。
const UUIDGeneratorBrowser = () => ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => ( c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4))) ).toString(16) ); 复制代码
UUIDGeneratorBrowser(); // '7982fcfe-5721-4632-bede-6000885be57d' 复制代码
function genUUID() { const url = URL.createObjectURL(new Blob([])); // const uuid = url.split("/").pop(); const uuid = url.substring(url.lastIndexOf('/')+ 1); URL.revokeObjectURL(url); return uuid; } genUUID() // cd205467-0120-47b0-9444-894736d873c7 复制代码
addDaysToDate
时间添加天数,返回的是字符串。
const addDaysToDate = (date, n) => { const d = new Date(date); d.setDate(d.getDate() + n); return d.toISOString().split('T')[0]; }; 复制代码
addDaysToDate('2020-10-15', 10); // '2020-10-25' addDaysToDate('2020-10-15', -10); // '2020-10-05' 复制代码
compose
从右到左的复合函数。 没记错的话和 redux的compose 极其类似。
毕竟嘛,思路是一样的。
onst compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args))); 复制代码
const add5 = x => x + 5; const multiply = (x, y) => x * y; const multiplyAndAdd5 = compose( add5, multiply ); multiplyAndAdd5(5, 2); // 15 复制代码
deepGet
获取对象的多级属性,属性参数是数组。
const deepGet = (obj, keys) => keys.reduce( (xs, x) => (xs && xs[x] !== null && xs[x] !== undefined ? xs[x] : null), obj ); let index = 2; const data = { foo: { foz: [1, 2, 3], bar: { baz: ['a', 'b', 'c'] } } }; deepGet(data, ['foo', 'foz', index]); // get 3 deepGet(data, ['foo', 'bar', 'baz', 8, 'foz']); // null 复制代码
当然 lodash 也提供了 .get, 当然实现的复杂度也高很对,其属性参数用的是字符串。
objectToQueryString
把对象转为 queryString,就这个queryString的转换,就有好几个牛气冲天的库。
下载量过 千万的 query-string 和 500万的 qs, 主要解决两个问题,其中一个就是 toQueryString。
const objectToQueryString = queryParameters => { return queryParameters ? Object.entries(queryParameters).reduce( (queryString, [key, val], index) => { const symbol = queryString.length === 0 ? '?' : '&'; queryString += typeof val === 'string' ? `${symbol}${key}=${val}` : ''; return queryString; }, '' ) : ''; }; 复制代码
objectToQueryString({ page: '1', size: '2kg', key: undefined }); // '?page=1&size=2kg' 复制代码
parseCookie
把cookie转为键值对。
作为一个操作前端,操作cookie是日常操作,我相信肯定有不少同志引入了第三方库,其实只需代几码就可以的。
const parseCookie = str => str .split(';') .map(v => v.split('=')) .reduce((acc, v) => { acc[decodeURIComponent(v[0].trim())] = decodeURIComponent(v[1].trim()); return acc; }, {}); 复制代码
parseCookie(document.cookie) // {_octo: "GH1.1.2059864283.1626332708", tz: "Asia/Shanghai"} parseCookie('foo=bar; equation=E%3Dmc%5E2'); // { foo: 'bar', equation: 'E=mc^2' } 复制代码
unfold
使用迭代器函数和初始种子值构建数组。
在造假数据或者随机数据的时候,比较有用。
const unfold = (fn, seed) => { let result = [], val = [null, seed]; while ((val = fn(val[1]))) result.push(val[0]); return result; }; 复制代码
var f = n => (n > 50 ? false : [-n, n + 10]); unfold(f, 10); // [-10, -20, -30, -40, -50] 复制代码
triggerEvent
触发给定元素上的特定事件,可以选择传递自定义数据。
这个在IE11以及一些低版本是有问题的,低版本使用的是 document.createEvent
const triggerEvent = (el, eventType, detail) => el.dispatchEvent(new CustomEvent(eventType, { detail })); 复制代码
triggerEvent(document.getElementById('myId'), 'click'); triggerEvent(document.getElementById('myId'), 'click', { username: 'bob' }); 复制代码
repeatGenerator
创建生成器,无限重复给定值。 有点意思,实用场景嘛,也许测试吧。
当然,中途你可以更新值。 这里想告诉大家的是 genetator有入参的概念。
const repeatGenerator = function* (val) { let v = val; while (true) { let newV = yield v; if (newV !== undefined) v = newV; } }; 复制代码
const repeater = repeatGenerator(5); repeater.next(); // { value: 5, done: false } repeater.next(); // { value: 5, done: false } repeater.next(4); // { value: 4, done: false } repeater.next(); // { value: 4, done: false } 复制代码
写在最后
如果你觉得不错,你的一赞一评就是我前行的最大动力。
技术交流群请到 这里来。 或者添加我的微信 dirge-cloud,一起学习。