跳至主要內容

单行代码就能实现的 JavaScript 实用程序

星火燎原@vxhly大约 28 分钟webJavaScriptCodeES6

Array

检查数组是否为空

// `arr` is an array
const isEmpty = (arr) => !Array.isArray(arr) || arr.length === 0;

// Examples
isEmpty([]); // true
isEmpty([1, 2, 3]); // false

克隆数组

// `arr` is an array
const clone = (arr) => arr.slice(0);

// Or
const clone = (arr) => [...arr];

// Or
const clone = (arr) => Array.from(arr);

// Or
const clone = (arr) => arr.map((x) => x);

// Or
const clone = (arr) => JSON.parse(JSON.stringify(arr));

// Or
const clone = (arr) => arr.concat([]);

比较两个数组, 而不考虑顺序

// `a` and `b` are arrays
const isEqual = (a, b) => JSON.stringify(a.sort()) === JSON.stringify(b.sort());

// Examples
isEqual([1, 2, 3], [1, 2, 3]); // true
isEqual([1, 2, 3], [1, 3, 2]); // true
isEqual([1, 2, 3], [1, "2", 3]); // false

比较两个数组

// `a` and `b` are arrays
const isEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b);

// Or
const isEqual = (a, b) =>
  a.length === b.length && a.every((v, i) => v === b[i]);

// Examples
isEqual([1, 2, 3], [1, 2, 3]); // true
isEqual([1, 2, 3], [1, "2", 3]); // false

将数组转换为单个对象

const toObject = (arr, key) =>
  arr.reduce(
    (a, b) => ({
      ...a,
      [b[key]]: b,
    }),
    {}
  );

// Example
toObject(
  [
    {
      id: "1",
      name: "Alpha",
      gender: "Male",
    },
    {
      id: "2",
      name: "Bravo",
      gender: "Male",
    },
    {
      id: "3",
      name: "Charlie",
      gender: "Female",
    },
  ],
  "id"
);
/* 
{
    '1': { id: '1', name: 'Alpha', gender: 'Male' },
    '2': { id: '2', name: 'Bravo', gender: 'Male' },
    '3': { id: '3', name: 'Charlie', gender: 'Female' },
}
*/

将字符串数组转换成数字

const toNumbers = (arr) => arr.map(Number);

// Or
const toNumbers = (arr) => arr.map((x) => +x);

// Example
toNumbers(["2", "3", "4"]); // [2, 3, 4]

按对象数组的属性计数

const countBy = (arr, prop) =>
  arr.reduce(
    (prev, curr) => ((prev[curr[prop]] = ++prev[curr[prop]] || 1), prev),
    {}
  );

// Example
countBy(
  [
    {
      branch: "audi",
      model: "q8",
      year: "2019",
    },
    {
      branch: "audi",
      model: "rs7",
      year: "2020",
    },
    {
      branch: "ford",
      model: "mustang",
      year: "2019",
    },
    {
      branch: "ford",
      model: "explorer",
      year: "2020",
    },
    {
      branch: "bmw",
      model: "x7",
      year: "2020",
    },
  ],
  "branch"
);

// { 'audi': 2, 'ford': 2, 'bmw': 1 }

计算数组中的某个值的出现

const countOccurrences = (arr, val) =>
  arr.reduce((a, v) => (v === val ? a + 1 : a), 0);

// Examples
countOccurrences([2, 1, 3, 3, 2, 3], 2); // 2
countOccurrences(["a", "b", "a", "c", "a", "b"], "a"); // 3

计算数组元素的出现次数

const countOccurrences = (arr) =>
  arr.reduce((prev, curr) => ((prev[curr] = ++prev[curr] || 1), prev), {});

// Examples
countOccurrences([2, 1, 3, 3, 2, 3]); // { '1': 1, '2': 2, '3': 3 }
countOccurrences(["a", "b", "a", "c", "a", "b"]); // { 'a': 3, 'b': 2, 'c': 1 }

创建一个累积和的数组

const accumulate = (arr) =>
  arr.map(
    (
      (sum) => (value) =>
        (sum += value)
    )(0)
  );

// Or
const accumulate = (arr) =>
  arr.reduce((a, b, i) => (i === 0 ? [b] : [...a, b + a[i - 1]]), []);

// Or
const accumulate = (arr) =>
  arr.reduce((a, b, i) => (i === 0 ? [b] : [...a, b + a[i - 1]]), 0);

// Example
accumulate([1, 2, 3, 4]); // [1, 3, 6, 10]
// 1             = 1
// 1 + 2         = 3
// 1 + 2 + 3     = 6
// 1 + 2 + 3 + 4 = 10

给定范围内创建一个数字数组

const range = (min, max) =>
  [...Array(max - min + 1).keys()].map((i) => i + min);

// Or
const range = (min, max) =>
  Array(max - min + 1)
    .fill(0)
    .map((_, i) => min + i);

// Or
const range = (min, max) =>
  Array.from(
    {
      length: max - min + 1,
    },
    (_, i) => min + i
  );

// Example
range(5, 10); // [5, 6, 7, 8, 9, 10]

空数组

const empty = (arr) => (arr.length = 0);

// Or
arr = [];

在数组中查找最接近的数字

// Find the number from `arr` which is closest to `n`
const closest = (arr, n) =>
  arr.reduce((prev, curr) =>
    Math.abs(curr - n) < Math.abs(prev - n) ? curr : prev
  );

// Or
const closest = (arr, n) =>
  arr.sort((a, b) => Math.abs(a - n) - Math.abs(b - n))[0];

// Example
closest([29, 87, 8, 78, 97, 20, 75, 33, 24, 17], 50); // 33

查找数字中最长字符串的长度

const findLongest = (words) => Math.max(...words.map((el) => el.length));

// Example
findLongest(["always", "look", "on", "the", "bright", "side", "of", "life"]); // 6

从一个数组中找到最大的元素

const max = (arr) => Math.max(...arr);

从一个数组中找到最小的元素

const min = (arr) => Math.min(...arr);

展平数组

const flat = (arr) =>
  [].concat.apply(
    [],
    arr.map((a) => (Array.isArray(a) ? flat(a) : a))
  );
// Or
const flat = (arr) =>
  arr.reduce((a, b) => (Array.isArray(b) ? [...a, ...flat(b)] : [...a, b]), []);

// Or
// See the browser compatibility at https://caniuse.com/#feat=array-flat
const flat = (arr) => arr.flat();

// Example
flat(["cat", ["lion", "tiger"]]); // ['cat', 'lion', 'tiger']

获取数组的平均值

const average = (arr) => arr.reduce((a, b) => a + b, 0) / arr.length;

获取数组的交集

const getIntersection = (a, ...arr) =>
  [...new Set(a)].filter((v) => arr.every((b) => b.includes(v)));

// Examples
getIntersection([1, 2, 3], [2, 3, 4, 5]); // [2, 3]
getIntersection([1, 2, 3], [2, 3, 4, 5], [1, 3, 5]); // [3]

获取数字数组的总和

const sum = (arr) => arr.reduce((a, b) => a + b, 0);

获取数组的唯一值

const unique = (arr) => [...new Set(arr)];

// Or
const unique = (arr) => arr.filter((el, i, array) => array.indexOf(el) === i);

// Or
const unique = (arr) =>
  arr.reduce((acc, el) => (acc.includes(el) ? acc : [...acc, el]), []);

获取数组的并集

const union = (...arr) => [...new Set(arr.flat())];

// Example
union([1, 2], [2, 3], [3]); // [1, 2, 3]

通过键将对象数组分组

const groupBy = (arr, key) =>
  arr.reduce(
    (acc, item) => ((acc[item[key]] = [...(acc[item[key]] || []), item]), acc),
    {}
  );

// Example
groupBy(
  [
    {
      branch: "audi",
      model: "q8",
      year: "2019",
    },
    {
      branch: "audi",
      model: "rs7",
      year: "2020",
    },
    {
      branch: "ford",
      model: "mustang",
      year: "2019",
    },
    {
      branch: "ford",
      model: "explorer",
      year: "2020",
    },
    {
      branch: "bmw",
      model: "x7",
      year: "2020",
    },
  ],
  "branch"
);

/*
{
    audi: [
        { branch: 'audi', model: 'q8', year: '2019' },
        { branch: 'audi', model: 'rs7', year: '2020' }
    ],
    bmw: [
        { branch: 'bmw', model: 'x7', year: '2020' }
    ],
    ford: [
        { branch: 'ford', model: 'mustang', year: '2019' },
        { branch: 'ford', model: 'explorer', year: '2020' }
    ],
}
*/

合并两个数组

// Merge but don't remove the duplications
const merge = (a, b) => a.concat(b);
// Or
const merge = (a, b) => [...a, ...b];

// Merge and remove the duplications
const merge = [...new Set(a.concat(b))];
// Or
const merge = [...new Set([...a, ...b])];

根据条件对数组进行分区

const partition = (arr, criteria) =>
  arr.reduce((acc, i) => (acc[criteria(i) ? 0 : 1].push(i), acc), [[], []]);

// Example
partition([1, 2, 3, 4, 5], (n) => n % 2); // [[2, 4], [1, 3, 5]]

从数组中删除虚假值

const removeFalsy = (arr) => arr.filter(Boolean);

// Example
removeFalsy([
  0,
  "a string",
  "",
  NaN,
  true,
  5,
  undefined,
  "another string",
  false,
]); // ['a string', true, 5, 'another string']

随机排列数组

const shuffle = (arr) =>
  arr
    .map((a) => ({
      sort: Math.random(),
      value: a,
    }))
    .sort((a, b) => a.sort - b.sort)
    .map((a) => a.value);

// Or
const shuffle = (arr) => arr.sort(() => 0.5 - Math.random());

// Example
shuffle([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); // [9, 1, 10, 6, 8, 5, 2, 3, 7, 4]

排序数字数组

const sort = (arr) => arr.sort((a, b) => a - b);

// Example
sort([1, 5, 2, 4, 3]); // [1, 2, 3, 4, 5]

将数组拆分为大块

const chunk = (arr, size) =>
  arr.reduce(
    (acc, e, i) => (
      i % size ? acc[acc.length - 1].push(e) : acc.push([e]), acc
    ),
    []
  );

// Examples
chunk([1, 2, 3, 4, 5, 6, 7, 8], 3); // [[1, 2, 3], [4, 5, 6], [7, 8]]
chunk([1, 2, 3, 4, 5, 6, 7, 8], 4); // [[1, 2, 3, 4], [5, 6, 7, 8]]

交换矩阵的行和列

const transpose = (matrix) =>
  matrix[0].map((col, i) => matrix.map((row) => row[i]));

// Or
const transpose = (matrix) =>
  matrix[0].map((col, c) => matrix.map((row, r) => matrix[r][c]));

// Or
const transpose = (matrix) =>
  matrix.reduce(
    (prev, next) => next.map((item, i) => (prev[i] || []).concat(next[i])),
    []
  );

// Example
transpose([
  // [
  [1, 2, 3], //      [1, 4, 7],
  [4, 5, 6], //      [2, 5, 8],
  [7, 8, 9], //      [3, 6, 9],
]); //  ]

解压缩数组中的数组

const unzip = (arr) =>
  arr.reduce(
    (acc, c) => (c.forEach((v, i) => acc[i].push(v)), acc),
    Array.from(
      {
        length: Math.max(...arr.map((a) => a.length)),
      },
      (_) => []
    )
  );

// Example
unzip([
  ["a", 1],
  ["b", 2],
  ["c", 3],
  ["d", 4],
  ["e", 5],
]); // [['a', 'b', 'c', 'd', 'e'], [1, 2, 3, 4, 5]]

/*
    a     1
     b   2
      c 3
      d 4
      e 5
*/

压缩多个数组

const zip = (...arr) =>
  Array.from(
    {
      length: Math.max(...arr.map((a) => a.length)),
    },
    (_, i) => arr.map((a) => a[i])
  );

// Example
zip(["a", "b", "c", "d", "e"], [1, 2, 3, 4, 5]); // [['a', 1], ['b', 2], ['c', 3], ['d', 4], ['e', 5]]

/*
Does it look like a zipper?
        a 1
        b 2
       c   3
      d     4
     e       5
*/

日期时间

计算两个日期之间的差异天数

const diffDays = (date, otherDate) =>
  Math.ceil(Math.abs(date - otherDate) / (1000 * 60 * 60 * 24));

// Example
diffDays(new Date("2014-12-19"), new Date("2020-01-01")); // 1839

计算两个日期之间的月数

const monthDiff = (startDate, endDate) =>
  Math.max(
    0,
    (endDate.getFullYear() - startDate.getFullYear()) * 12 -
      startDate.getMonth() +
      endDate.getMonth()
  );

// Example
monthDiff(new Date("2020-01-01"), new Date("2021-01-01")); // 12

比较两个日期

// `a` and `b` are `Date` instances
const compare = (a, b) => a.getTime() > b.getTime();

// Example
compare(new Date("2020-03-30"), new Date("2020-01-01")); // true

将日期转换为 yyyy-mm-dd 格式

// `date` is a `Date` object
const formatYmd = (date) => date.toISOString().slice(0, 10);

// Example
formatYmd(new Date()); // 2020-05-06

将秒转换为 hh:mm:ss 格式

// `s` is number of seconds
const formatSeconds = (s) => new Date(s * 1000).toISOString().substr(11, 8);

// Or
const formatSeconds = (s) =>
  new Date(s * 1000).toUTCString().match(/(\d\d:\d\d:\d\d)/)[0];

// Or
const formatSeconds = (s) =>
  [parseInt(s / 60 / 60), parseInt((s / 60) % 60), parseInt(s % 60)]
    .join(":")
    .replace(/\b(\d)\b/g, "0$1");

// Examples
formatSeconds(200); // 00:03:20
formatSeconds(500); // 00:08:20

从日期中提取年月日时分秒和毫秒

// `date` is a `Date` object
const extract = (date) =>
  date
    .toISOString()
    .split(/[^0-9]/)
    .slice(0, -1);

// `extract` is an array of [year, month, day, hour, minute, second, millisecond]

格式化给定语言环境的日期

// `date` is a `Date` object
// `locale` is a locale (en-US, pt-BR, for example)
const format = (date, locale) => new Intl.DateTimeFormat(locale).format(date);

// Example
format(new Date(), "pt-BR"); // 06/05/2020

以秒为单位获取当前时间戳

const ts = () => Math.floor(new Date().getTime() / 1000);

从日期获取一年中的某天

// `date` is a Date object
const dayOfYear = (date) =>
  Math.floor(
    (date - new Date(date.getFullYear(), 0, 0)) / (1000 * 60 * 60 * 24)
  );

// Example
dayOfYear(new Date(2020, 04, 16)); // 137

获取日期的月份名称

// `date` is a Date object
const getMonthName = (date) =>
  [
    "January",
    "February",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    " November",
    "December",
  ][date.getMonth()];

获取给定月份的天数

// `month` is zero-based index
const daysInMonth = (month, year) => new Date(year, month, 0).getDate();

获取明天的日期

const tomorrow = ((d) => new Date(d.setDate(d.getDate() + 1)))(new Date());

// Or
const tomorrow = new Date(new Date().valueOf() + 1000 * 60 * 60 * 24);

获取日期的工作日

// `date` is a Date object
const getWeekday = (date) =>
  [
    "Sunday",
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday",
  ][date.getDay()];

获取昨天的日期

const yesterday = ((d) => new Date(d.setDate(d.getDate() - 1)))(new Date());

// Or
const yesterday = new Date(new Date().valueOf() - 1000 * 60 * 60 * 24);

排序日期数组

// `arr` is an array of `Date` items
const sortDescending = (arr) => arr.sort((a, b) => a.getTime() > b.getTime());
const sortAscending = (arr) => arr.sort((a, b) => a.getTime() < b.getTime());

检查日期是否为工作日

const isWeekday = (date) => date.getDay() % 6 !== 0;
console.log(isWeekday(new Date(2021, 0, 11)));
// Result: true (Monday)
console.log(isWeekday(new Date(2021, 0, 10)));
// Result: false (Sunday)

从日期中获取时间

const timeFromDate = (date) => date.toTimeString().slice(0, 8);
console.log(timeFromDate(new Date(2021, 0, 10, 17, 30, 0)));
// Result: "17:30:00"
console.log(timeFromDate(new Date()));
// Result: will log the current time

DOM

检查一个元素是否是另一个元素的后代

const isDescendant = (child, parent) => parent.contains(child);

检查元素是否获得焦点

const elementIsInFocus = (el) => el === document.activeElement;
elementIsInFocus(anyElement);
// Result: will return true if in focus, false if not in focus

检查是否支持触摸事件

const touchSupported = () => {
  "ontouchstart" in window ||
    (window.DocumentTouch && document instanceof window.DocumentTouch);
};
console.log(touchSupported());
// Result: will return true if touch events are supported, false if not

检测 Internet Explorer 浏览器

const isIE = !!document.documentMode;

检测 macos 浏览器

const isAppleDevice = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
console.log(isAppleDevice);
// Result: will return true if user is on an Apple device

获取元素的所有同级

const siblings = (ele) =>
  [].slice.call(ele.parentNode.children).filter((child) => child !== ele);

获取所选文本

const getSelectedText = () => window.getSelection().toString();

返回上一个页面

history.back();

// Or
history.go(-1);

隐藏元素

// Pick the method that is suitable for your use case
const hide = (ele) => (ele.style.display = "none");

// Or
const hide = (ele) => (ele.style.visibility = "hidden");

在另一个元素之后插入一个元素

const insertAfter = (ele, anotherEle) =>
  anotherEle.parentNode.insertBefore(ele, anotherEle.nextSibling);

// Or
const insertAfter = (ele, anotherEle) =>
  anotherEle.insertAdjacentElement("afterend", ele);

在其他元素之前插入元素

const insertBefore = (ele, anotherEle) =>
  anotherEle.parentNode.insertBefore(ele, anotherEle);

// Or
const insertBefore = (ele, anotherEle) =>
  anotherEle.insertAdjacentElement("beforebegin", ele);

在元素后插入给定的 html

const insertHtmlAfter = (html, ele) => ele.insertAdjacentHTML("afterend", html);

在元素之前插入给定的 html

const insertHtmlBefore = (html, ele) =>
  ele.insertAdjacentHTML("beforebegin", html);

重定向到另一个页面

const goTo = (url) => (location.href = url);

重新加载当前页面

const reload = () => location.reload();

// Or
const reload = () => (location.href = location.href);

替换元素

const replace = (ele, newEle) => ele.parentNode.replaceChild(newEle, ele);

滚动到页面顶部

const goToTop = () => window.scrollTo(0, 0);
goToTop();
// Result: will scroll the browser to the top of the page

显示元素

const show = (ele) => (ele.style.display = "");

从给定的文本中删除 HTML

const stripHtml = (html) =>
  new DOMParser().parseFromString(html, "text/html").body.textContent || "";

切换元素

const toggle = (ele) =>
  (ele.style.display = ele.style.display === "none" ? "block" : "none");

检查当前 Tab 页是否在前台

const isBrowserTabInView = () => document.hidden;
isBrowserTabInView();
// Result: returns true or false depending on if tab is in view / focus

功能

装箱机

const boxHandler = (x) => ({
  next: (f) => boxHandler(f(x)),
  done: (f) => f(x),
});

// Example 1
const getPercentNumber = (str) =>
  boxHandler(str)
    .next((str) => str.replace(/\%/, ""))
    .next((str) => parseFloat(str))
    .done((res) => res * 0.01);

getPercentNumber("50%"); // 0.5

// Example 2
const getMoney = (price) => Number.parseFloat(price.replace(/\$/, ""));
const getPercent = (percent) => Number.parseFloat(percent.replace(/\%/)) * 0.01;

const getDiscountPrice = (price, discount) =>
  boxHandler(getMoney(price))
    .done((cents) =>
      boxHandler(getPercent(discount)).next((save) => cents - cents * save)
    )
    .done((res) => res);

getDiscountPrice("$6.00", "20%"); // 4.8

检查值是否为函数

const isFunction = (v) =>
  [
    "[object Function]",
    "[object GeneratorFunction]",
    "[object AsyncFunction]",
    "[object Promise]",
  ].includes(Object.prototype.toString.call(v));

// Examples
isFunction(function () {}); // true
isFunction(function* () {}); // true
isFunction(async function () {}); // true

检查值是否是生成器函数

const isGeneratorFunction = (v) =>
  Object.prototype.toString.call(v) === "[object GeneratorFunction]";

// Examples
isGeneratorFunction(function () {}); // false
isGeneratorFunction(function* () {}); // true

检查值是否是异步函数

const isAsyncFunction = (v) =>
  Object.prototype.toString.call(v) === "[object AsyncFunction]";

// Examples
isAsyncFunction(function () {}); // false
isAsyncFunction(function* () {}); // false
isAsyncFunction(async function () {}); // true

从左到右编写功能

// Compose functions from left to right
const pipe =
  (...fns) =>
  (x) =>
    fns.reduce((y, f) => f(y), x);

// Example
const lowercase = (str) => str.toLowerCase();
const capitalize = (str) => `${str.charAt(0).toUpperCase()}${str.slice(1)}`;
const reverse = (str) => str.split("").reverse().join("");

const fn = pipe(lowercase, capitalize, reverse);

// We will execute `lowercase`, `capitalize` and `reverse` in order
fn("Hello World") === "dlrow olleH";

撰写功能

// Compose functions from right to left
const compose =
  (...fns) =>
  (x) =>
    fns.reduceRight((y, f) => f(y), x);

// Example
const lowercase = (str) => str.toLowerCase();
const capitalize = (str) => `${str.charAt(0).toUpperCase()}${str.slice(1)}`;
const reverse = (str) => str.split("").reverse().join("");

const fn = compose(reverse, capitalize, lowercase);

// We will execute `lowercase`, `capitalize` and `reverse` in order
fn("Hello World") === "dlrow olleH";

创建一个空函数

const noop = () => {};

// Or
const noop = Function();
// calling Function() might be detected as using eval by some security tools

咖喱功能

const curry = (fn, ...args) =>
  fn.length <= args.length ? fn(...args) : curry.bind(null, fn, ...args);

// Example
const sum = (a, b, c) => a + b + c;
curry(sum)(1)(2)(3); // 6
curry(sum)(1, 2, 3); // 6
curry(sum, 1)(2, 3); // 6
curry(sum, 1)(2)(3); // 6
curry(sum, 1, 2)(3); // 6
curry(sum, 1, 2, 3); // 6

延迟功能评估

// returns a new version of `fn` that returns values as lazy evaluable
const thunkfy =
  (fn) =>
  (...args) =>
  () =>
    fn(...args);

// Example
const heavyComputation = (x) => doStuff(x);
const unnecessarySlow = manyThings
  .map(heavyComputation)
  .find((result) => result.criteria);
const probablyFaster = manyThings
  .map(thunkfy(heavyComputation))
  .find((thunk) => thunk().criteria);

一次执行一个功能

const once = (fn) =>
  (
    (ran = false) =>
    () =>
      ran ? fn : ((ran = !ran), (fn = fn()))
  )();

// Example
let n = 0;
const incOnce = once(() => ++n);
incOnce(); // n = 1
incOnce(); // n = 1
incOnce(); // n = 1

翻转函数的参数

// Reverse the order of arguments
const flip =
  (fn) =>
  (...args) =>
    fn(...args.reverse());

// For binary functions
const flip = (fn) => (b, a) => fn(a, b);

// Or for curried functions
const flip = (fn) => (b) => (a) => fn(a)(b);

// Example
const isParent = (parent, child) => parent.children.includes(child);
const isChild = flip(isParent);

身份功能

const identity = (x) => x;

逻辑异或运算符

// returns `true` if one of the arguments is truthy and the other is falsy

const xor = (a, b) => (a && !b) || (!a && b);

// Or
const xor = (a, b) => !(!a && !b) && !(a && b);

// Or
const xor = (a, b) => Boolean(!a ^ !b);

// Examples
xor(true, true); // false
xor(false, false); // false
xor(true, false); // true
xor(false, true); // true

记忆功能

const memoize = (fn) =>
  (
    (cache = {}) =>
    (arg) =>
      cache[arg] || (cache[arg] = fn(arg))
  )();

// Example
// Calculate Fibonacci numbers
const fibo = memoize((n) => (n <= 2 ? 1 : fibo(n - 1) + fibo(n - 2)));

fibo(1); // 1
fibo(2); // 1
fibo(3); // 2
fibo(4); // 3
fibo(5); // 5
fibo(6); // 8

部分应用功能

const partial =
  (fn, ...a) =>
  (...b) =>
    fn(...a, ...b);

// Example
const sum = (x, y) => x + y;
const inc = partial(sum, 1);
inc(9); // 10

泛函功能

// `fn` is a curried function
// `n` is the depth of parameters
const uncurry =
  (fn, n = 1) =>
  (...args) =>
    (
      (acc) => (args) =>
        args.reduce((x, y) => x(y), acc)
    )(fn)(args.slice(0, n));

// Example
const sum = (a) => (b) => (c) => a + b + c;
uncurry(sum, 1)(1)(2)(3); // 6
uncurry(sum, 2)(1, 2)(3); // 6
uncurry(sum, 3)(1, 2, 3); // 6

MISC

检查代码是否在节点 js 中运行

const isNode =
  typeof process !== "undefined" &&
  process.versions != null &&
  process.versions.node != null;

检查代码是否在浏览器中运行

const isBrowser = typeof window === "object" && typeof document === "object";

将摄氏度转换为华氏度

const celsiusToFahrenheit = (celsius) => (celsius * 9) / 5 + 32;

const fahrenheitToCelsius = (fahrenheit) => ((fahrenheit - 32) * 5) / 9;

// Examples
celsiusToFahrenheit(15); // 59
celsiusToFahrenheit(0); // 32
celsiusToFahrenheit(-20); // -4

fahrenheitToCelsius(59); // 15
fahrenheitToCelsius(32); // 0
const cookies = document.cookie
  .split(";")
  .map((item) => item.split("="))
  .reduce((acc, [k, v]) => (acc[k.trim().replace('"', "")] = v) && acc, {});

将十六进制转换为 RGB

const hexToRgb = (hex) =>
  hex
    .replace(
      /^#?([a-f\d])([a-f\d])([a-f\d])$/i,
      (_, r, g, b) => `#${r}${r}${g}${g}${b}${b}`
    )
    .substring(1)
    .match(/.{2}/g)
    .map((x) => parseInt(x, 16));

// Examples
hexToRgb("#00ffff"); // [0, 255, 255]
hexToRgb("#0ff"); // [0, 255, 255]

将 RGB 颜色转换为十六进制

const rgbToHex = (red, green, blue) =>
  `#${((1 << 24) + (red << 16) + (green << 8) + blue).toString(16).slice(1)}`;

// Or
const rgbToHex = (red, green, blue) =>
  `#${[red, green, blue].map((v) => v.toString(16).padStart(2, "0")).join("")}`;

// Example
rgbToHex(0, 255, 255); // '#00ffff'

解码 jwt 令牌

const decode = (token) =>
  decodeURIComponent(
    atob(token.split(".")[1].replace("-", "+").replace("_", "/"))
      .split("")
      .map((c) => `%${("00" + c.charCodeAt(0).toString(16)).slice(-2)}`)
      .join("")
  );

// Example
decode(`
    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
    eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0I
    joxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
`);

// { "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }

检测暗模式

const isDarkMode =
  window.matchMedia &&
  window.matchMedia("(prefers-color-scheme: dark)").matches;

缓动功能

// Some easing functions
// See https://gist.github.com/gre/1650294 and https://easings.net

const linear = (t) => t;

const easeInQuad = (t) => t * t;
const easeOutQuad = (t) => t * (2 - t);
const easeInOutQuad = (t) => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t);

const easeInCubic = (t) => t * t * t;
const easeOutCubic = (t) => --t * t * t + 1;
const easeInOutCubic = (t) =>
  t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;

const easeInQuart = (t) => t * t * t * t;
const easeOutQuart = (t) => 1 - --t * t * t * t;
const easeInOutQuart = (t) =>
  t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;

const easeInQuint = (t) => t * t * t * t * t;
const easeOutQuint = (t) => 1 + --t * t * t * t * t;
const easeInOutQuint = (t) =>
  t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t;

const easeInSine = (t) => 1 + Math.sin((Math.PI / 2) * t - Math.PI / 2);
const easeOutSine = (t) => Math.sin((Math.PI / 2) * t);
const easeInOutSine = (t) => (1 + Math.sin(Math.PI * t - Math.PI / 2)) / 2;

const easeInElastic = (t) => (0.04 - 0.04 / t) * Math.sin(25 * t) + 1;
const easeOutElastic = (t) => ((0.04 * t) / --t) * Math.sin(25 * t);
const easeInOutElastic = (t) =>
  (t -= 0.5) < 0
    ? (0.02 + 0.01 / t) * Math.sin(50 * t)
    : (0.02 - 0.01 / t) * Math.sin(50 * t) + 1;

模拟掷骰子

const throwdice = () => ~~(Math.random() * 6) + 1;

// Examples
throwdice(); // 4
throwdice(); // 1
throwdice(); // 6

编码网址

// `encodeURIComponent` doesn't encode -_.!~*'()
const encode = (url) =>
  encodeURIComponent(url)
    .replace(/!/g, "%21")
    .replace(/~/g, "%7E")
    .replace(/\*/g, "%2A")
    .replace(/'/g, "%27")
    .replace(/\(/g, "%28")
    .replace(/\)/g, "%29")
    .replace(/%20/g, "+");

获取第一个已定义且非 null 的参数

const coalesce = (...args) =>
  args.find((item) => item !== undefined && item !== null);

// Or
const coalesce = (...args) =>
  args.find((item) => ![undefined, null].includes(item));

// Examples
coalesce(undefined, null, "helloworld", NaN); // 'helloworld'
const cookie = (name) =>
  `; ${document.cookie}`.split(`; ${name}=`).pop().split(";").shift();

// Example
cookie("_ga"); // GA1.2.825309271.1581874719

从网址获取参数值

const getParam = (url, param) =>
  new URLSearchParams(new URL(url).search).get(param);

// Example
getParam("http://domain.com?message=hello", "message"); // 'hello'

将页面重定向到 https(如果位于 http 中)

const redirectHttps = () =>
  location.protocol === "https:"
    ? {}
    : location.replace(`https://${location.href.split("//")[1]}`);

// Or
const redirectHttps = () =>
  location.protocol === "https:" ? {} : (location.protocol = "https:");

依次兑现承诺

// `promises` is an array of `Promise`
const run = (promises) =>
  promises.reduce(
    (p, c) => p.then((rp) => c.then((rc) => [...rp, rc])),
    Promise.resolve([])
  );

// Example
run(promises).then((results) => {
  // `results` is an array of promise results in the same order
});

交换两个变量

[a, b] = [b, a];

// Or
a = [b, (b = a)][0];

// Or
a = ((x) => x)(b, (b = a));

// Or
// (only works with numbers)
a = b + ((b = a), 0);

a = b * ((b = a), 1);

等待一段时间

const wait = async (milliseconds) =>
  new Promise((resolve) => setTimeout(resolve, milliseconds));

数字

在数字后添加序数后缀

// `n` is a position number
const addOrdinal = (n) =>
  `${n}${["st", "nd", "rd"][((((n + 90) % 100) - 10) % 10) - 1] || "th"}`;

// Or
const addOrdinal = (n) => `${n}${[, "st", "nd", "rd"][/1?.$/.exec(n)] || "th"}`;

// Or
const addOrdinal = (n) =>
  `${n}${[, "st", "nd", "rd"][(n % 100 >> 3) ^ 1 && n % 10] || "th"}`;

// Or
const addOrdinal = (n) =>
  `${n}${
    { one: "st", two: "nd", few: "rd", other: "th" }[
      new Intl.PluralRules("en", { type: "ordinal" }).select(n)
    ]
  }`;

// Examples
addOrdinal(1); // '1st'
addOrdinal(2); // '2nd'
addOrdinal(3); // '3rd'
addOrdinal(11); // '11th'
addOrdinal(12); // '13th'
addOrdinal(13); // '13th'

计算斐波那契数

const fibo = (n, memo = {}) =>
  memo[n] || (n <= 2 ? 1 : (memo[n] = fibo(n - 1, memo) + fibo(n - 2, memo)));

// Examples
fibo(1); // 1
fibo(2); // 1
fibo(3); // 2
fibo(4); // 3
fibo(5); // 5
fibo(6); // 8

计算参数的平均值

const average = (...args) => args.reduce((a, b) => a + b) / args.length;

// Example
average(1, 2, 3, 4); // 2.5

技术参数除法

const division = (...args) => args.reduce((a, b) => a / b);

// Example
division(1, 2, 3, 4); // 0.04166666666666666

计算数字的阶乘

const factorial = (n) => (n <= 1 ? 1 : n * factorial(n - 1));

// Examples
factorial(2); // 2
factorial(3); // 6
factorial(4); // 24
factorial(5); // 120
factorial(6); // 720

计算集合索引的 mod

const mod = (a, b) => ((a % b) + b) % b;

// Examples
mod(-1, 5); // 4
mod(3, 5); // 3
mod(6, 5); // 1

计算参数除法的余数

const remainder = (...args) => args.reduce((a, b) => a % b);

// Example
remainder(1, 2, 3, 4); // 1

计算参数之和

const sum = (...args) => args.reduce((a, b) => a + b);

// Example
sum(1, 2, 3, 4); // 10

将数字限制在两个值之间

const clamp = (val, min = 0, max = 1) => Math.max(min, Math.min(max, val));

// Example
clamp(199, 10, 25); // 25

计算两个数字之间的最大公约数

const gcd = (a, b) => (b === 0 ? a : gcd(b, a % b));

// Example
gcd(10, 15); // 5

将数字转换为等效字符

const toChars = (n) =>
  `${n >= 26 ? toChars(Math.floor(n / 26) - 1) : ""}${
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[n % 26]
  }`;

// Examples
toChars(0); // A
toChars(1); // B
toChars(25); // Z

toChars(26); // AA
toChars(27); // AB
toChars(51); // AZ

toChars(701); // ZZ
toChars(702); // AAA
toChars(703); // AAB

将字符串转换为数字

const toNumber = (str) => +str;

// Example
toNumber("42"); // 42

将度转换为弧度

const degsToRads = (deg) => (deg * Math.PI) / 180.0;

const radsToDegs = (rad) => (rad * 180) / Math.PI;

从数字中获取数字数组

const digits = (n) => `${n}`.split("").map((v) => parseInt(v));

// Example
digits(123); // [1, 2, 3]

相乘参数

const mul = (...args) => args.reduce((a, b) => a * b);

// Example
mul(1, 2, 3, 4); // 24

在整数前加上零

const prefixWithZeros = (number, length) =>
  (number / Math.pow(10, length)).toFixed(length).substr(2);

// Or
const prefixWithZeros = (number, length) =>
  `${Array(length).join("0")}${number}`.slice(-length);

// Or
const prefixWithZeros = (number, length) =>
  String(number).padStart(length, "0");

// Example
prefixWithZeros(42, 5); // '00042'

将数字四舍五入到给定的数字

const round = (n, decimals = 0) =>
  Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`);

// Examples
round(1.234567, 3); // 1.235
round(1.234567, 4); // 1.2346

减去参数

const subtract = (...args) => args.reduce((a, b) => a - b);

// Example
subtract(1, 2, 3, 4); // -8

截断十进制数字

const truncate = (n) => ~~n;

// Examples
truncate(25.198726354); // 25
truncate(-25.198726354); // -25

将数字截断为给定的小数位数而不四舍五入

const toFixed = (n, fixed) =>
  `${n}`.match(new RegExp(`^-?\\d+(?:\.\\d{0,${fixed}})?`))[0];

// Or
const toFixed = (n, fixed) => ~~(Math.pow(10, fixed) * n) / Math.pow(10, fixed);

// Examples
toFixed(25.198726354, 1); // 25.1
toFixed(25.198726354, 2); // 25.19
toFixed(25.198726354, 3); // 25.198
toFixed(25.198726354, 4); // 25.1987
toFixed(25.198726354, 5); // 25.19872
toFixed(25.198726354, 6); // 25.198726

目的

检查多个对象是否相等

const isEqual = (...objects) =>
  objects.every((obj) => JSON.stringify(obj) === JSON.stringify(objects[0]));

// Examples
isEqual({ foo: "bar" }, { foo: "bar" }); // true
isEqual({ foo: "bar" }, { bar: "foo" }); // false

创建一个没有属性的空地图

// `map` doesn't have any properties
const map = Object.create(null);

// The following `map` has `__proto__` property
// const map = {};

从键和值对创建对象

const toObj = (arr) => Object.fromEntries(arr);

// Or
const toObj = (arr) => arr.reduce((a, c) => ((a[c[0]] = c[1]), a), {});

// Example
toObj([
  ["a", 1],
  ["b", 2],
  ["c", 3],
]); // { a: 1, b: 2, c: 3 }

从对象数组中提取属性的值

const pluck = (objs, property) => objs.map((obj) => obj[property]);

// Example
pluck(
  [
    { name: "John", age: 20 },
    { name: "Smith", age: 25 },
    { name: "Peter", age: 30 },
  ],
  "name"
); // ['John', 'Smith', 'Peter']

获取对象给定路径的值

const getValue = (path, obj) =>
  path.split(".").reduce((acc, c) => acc && acc[c], obj);

// Example
getValue("a.b", { a: { b: "Hello World" } }); // 'Hello World';

反转对象的键和值

const invert = (obj) =>
  Object.keys(obj).reduce((res, k) => Object.assign(res, { [obj[k]]: k }), {});

// Example
invert({ a: "1", b: "2", c: "3" }); // { 1: 'a', 2: 'b', 3: 'c' }

忽略对象的属性子集

const omit = (obj, keys) =>
  Object.keys(obj)
    .filter((k) => !keys.includes(k))
    .reduce((res, k) => Object.assign(res, { [k]: obj[k] }), {});

// Example
omit({ a: "1", b: "2", c: "3" }, ["a", "b"]); // { c: '3' }

选择一个对象的属性子集

const pick = (obj, keys) =>
  Object.keys(obj)
    .filter((k) => keys.includes(k))
    .reduce((res, k) => Object.assign(res, { [k]: obj[k] }), {});

// Example
pick({ a: "1", b: "2", c: "3" }, ["a", "b"]); // { a: '1', b: '2' }

浅复制对象

const shallowCopy = obj => Object.assign({}, obj);

// or
const shallowCopy = obj => {...obj};

随机

产生一个随机的布尔值

const randomBoolean = () => Math.random() >= 0.5;

生成给定范围内的随机浮点数

const randomFloat = (min, max) => Math.random() * (max - min) + min;

生成随机的十六进制颜色

const randomColor = () =>
  `#${Math.random().toString(16).slice(2, 8).padEnd(6, "0")}`;

// Or
const randomColor = () => `#${(~~(Math.random() * (1 << 24))).toString(16)}`;

生成给定范围内的随机整数

const randomInteger = (min, max) =>
  Math.floor(Math.random() * (max - min + 1)) + min;

生成一个随机 IP 地址

const randomIp = () =>
  Array(4)
    .fill(0)
    .map((_, i) => Math.floor(Math.random() * 255) + (i === 0 ? 1 : 0))
    .join(".");

// Example
randomIp(); // 175.89.174.131

从给定字符生成随机字符串

const generateString = (length, chars) =>
  Array(length)
    .fill("")
    .map((v) => chars[Math.floor(Math.random() * chars.length)])
    .join("");

// Example
generateString(
  10,
  "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
);

使用节点加密模块生成随机字符串

const randomStr = () => require("crypto").randomBytes(32).toString("hex");

生成给定长度的随机字符串

const generateString = (length) =>
  Array(length)
    .fill("")
    .map((v) => Math.random().toString(36).charAt(2))
    .join("");

生成随机的 uuid

const uuid = (a) =>
  a
    ? (a ^ ((Math.random() * 16) >> (a / 4))).toString(16)
    : ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, uuid);

生成给定范围内的随机整数数组

const randomArrayInRange = (min, max, n) =>
  Array.from(
    { length: n },
    () => Math.floor(Math.random() * (max - min + 1)) + min
  );

// Example
randomArrayInRange(1, 100, 10); // [11, 82, 41, 35, 76, 83, 43, 15, 60, 54]

从数组中获取随机项

const randomItem = (arr) => arr[(Math.random() * arr.length) | 0];

字符串

截取最后一个反斜杠后的内容

const interceptAfter = (str) =>
  str.substring(str.lastIndexOf("/") + 1, str.length);

截取最后一个反斜杠前的内容

const interceptBefore = (str) => str.substring(0, str.lastIndexOf("/") + 1);

大写字符串

const capitalize = (str) => `${str.charAt(0).toUpperCase()}${str.slice(1)}`;

// Example
capitalize("hello world"); // 'Hello world'

检查路径是否相对

const isRelative = (path) => !/^([a-z]+:)?[\\/]/i.test(path);

// Examples
isRelative("/foo/bar/baz"); // false
isRelative("C:\\foo\\bar\\baz"); // false
isRelative("foo/bar/baz.txt"); // true
isRelative("foo.md"); // true

检查字符串是否是回文

const isPalindrome = (str) => str === str.split("").reverse().join("");

// Examples
isPalindrome("abc"); // false
isPalindrom("abcba"); // true

检查网址是否为绝对网址

const isAbsoluteUrl = (url) => /^[a-z][a-z0-9+.-]*:/.test(url);

// Example
isAbsoluteUrl("https://1loc.dev"); // true
isAbsoluteUrl("https://1loc.dev/foo/bar"); // true
isAbsoluteUrl("1loc.dev"); // false
isAbsoluteUrl("//1loc.dev"); // false

检查两个字符串是否为字谜

const areAnagram = (str1, str2) =>
  str1.toLowerCase().split("").sort().join("") ===
  str2.toLowerCase().split("").sort().join("");

// Examples
areAnagram("listen", "silent"); // true
areAnagram("they see", "the eyes"); // true
areAnagram("node", "deno"); // true

转换字母以关联表情符号

const letterToEmoji = (c) =>
  String.fromCodePoint(c.toLowerCase().charCodeAt() + 127365);

// Examples
letterToEmoji("a"); // 🇦
letterToEmoji("b"); // 🇧

将字符串转换为驼峰式大小写

const toCamelCase = (str) =>
  str.trim().replace(/[-_\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ""));

// Examples
toCamelCase("background-color"); // backgroundColor
toCamelCase("-webkit-scrollbar-thumb"); // WebkitScrollbarThumb
toCamelCase("_hello_world"); // HelloWorld
toCamelCase("hello_world"); // helloWorld

将字符串转换为 Pascal 大小写

const toPascalCase = (str) =>
  (str.match(/[a-zA-Z0-9]+/g) || [])
    .map((w) => `${w.charAt(0).toUpperCase()}${w.slice(1)}`)
    .join("");

// Examples
toPascalCase("hello world"); // 'HelloWorld'
toPascalCase("hello.world"); // 'HelloWorld'
toPascalCase("foo_bar-baz"); // FooBarBaz

将字符串转换为 url slug

const slugify = (string) =>
  string
    .toLowerCase()
    .replace(/\s+/g, "-")
    .replace(/[^\w-]+/g, "");

// Example
slugify("Chapter One: Once upon a time..."); // 'chapter-one-once-upon-a-time'

将 Windows 文件路径转换为 Unix 路径

const toUnixPath = (path) =>
  path.replace(/[\\/]+/g, "/").replace(/^([a-zA-Z]+:|\.\/)/, "");

// Examples
toUnixPath("./foo/bar/baz"); // foo/bar/baz
toUnixPath("C:\\foo\\bar\\baz"); // /foo/bar/baz

将驼峰命名法转换为 kebab-case 形式, 反之亦然

const kebabToCamel = (str) => str.replace(/-./g, (m) => m.toUpperCase()[1]);

const camelToKebab = (str) =>
  str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();

// Examples
kebabToCamel("background-color"); // 'backgroundColor'
camelToKebab("backgroundColor"); // 'background-color'

将 snake-case 形式转换成驼峰命名形式

const snakeToCamel = (str) =>
  str.toLowerCase().replace(/(_\w)/g, (m) => m.toUpperCase().substr(1));

// Example
snakeToCamel("HELLO_world"); // 'helloWorld'

将 Excel 列名转换成数字

const getIndex = (col) =>
  col.split("").reduce((prev, next) => prev * 26 + parseInt(next, 36) - 9, 0);

// Examples
getIndex("A"); // 1
getIndex("B"); // 2
getIndex("C"); // 3
getIndex("Z"); // 26

getIndex("AA"); // 27
getIndex("AB"); // 28
getIndex("AC"); // 29
getIndex("AZ"); // 52

getIndex("AAA"); // 703
getIndex("AAB"); // 704

转义 HTML 特殊字符

const escape = (str) =>
  str
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/'/g, "&#39;")
    .replace(/"/g, "&quot;");

// Or
const escape = (str) =>
  str.replace(
    /[&<>"']/g,
    (m) =>
      ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" }[
        m
      ])
  );

获取不带任何参数的基本 URL

const baseUrl = (url) =>
  url.indexOf("?") === -1 ? url : url.slice(0, url.indexOf("?"));

// Or
// Note that `includes` isn't supported in IE 11
const baseUrl = (url) =>
  url.includes("?") ? url.slice(0, url.indexOf("?")) : url;

// Example
baseUrl("https://domain.com/path/sub/path?foo=bar&hello=world"); // 'https://domain.com/path/sub/path'

从文件名获取文件扩展名

const ext = (fileName) => fileName.split(".").pop();

从网址获取文件名

const fileName = (url) => url.substring(url.lastIndexOf("/") + 1);

// Example
fileName("http://domain.com/path/to/document.pdf"); // 'document.pdf'

获取字符串的长度(以字节为单位)

const bytes = (str) => new Blob([str]).size;

// Examples
bytes("hello world"); // 11
bytes("🎉"); // 4

获取字符串中的字符数

const characterCount = (str, char) => str.split(char).length - 1;

// Or
const characterCount = (str, char) =>
  str.replace(new RegExp(String.raw`[^${char}]`, "g"), "").length;

// Examples
characterCount("192.168.1.1", "."); // 3
characterCount("star wars", "s"); // 2

使字符串的第一个字符小写

const lowercaseFirst = (str) => `${str.charAt(0).toLowerCase()}${str.slice(1)}`;

// Example
lowercaseFirst("Hello World"); // 'hello World'

标准化文件路径斜杠

const normalizePath = (path) => path.replace(/[\\/]+/g, "/");

// Example
normalizePath("\\foo\\bar\\baz\\"); // /foo/bar/baz/
normalizePath(".//foo//bar///////baz/"); // ./foo/bar/baz/

从字符串中删除空格

const removeSpaces = (str) => str.replace(/\s/g, "");

// Example
removeSpaces("hel lo wor ld"); // 'helloworld'

重复一个字符串

const repeat = (str, numberOfTimes) => str.repeat(numberOfTimes);

// Or
const repeat = (str, numberOfTimes) => Array(numberOfTimes + 1).join(str);

用 br 元素替换所有换行符

const nl2br = (str) => str.replace(new RegExp("\r?\n", "g"), "<br>");

// In React
str.split("\n").map((item, index) => (
  <React.Fragment key={index}>
    {item}
    <br />
  </React.Fragment>
));

用一个空格替换多个空格

// Replace spaces, tabs and new line characters
const replaceSpaces = (str) => str.replace(/\s\s+/g, " ");

// Only replace spaces
const replaceOnlySpaces = (str) => str.replace(/  +/g, " ");

// Example
replaceSpaces("this\n   is     \ta    \rmessage"); // 'this is a message'

将字符串的第一个给定字符数替换为另一个字符

const mask = (str, num, mask) =>
  `${str}`.slice(num).padStart(`${str}`.length, mask);

// Example
mask(1234567890, 3, "*"); // ***4567890

反转字符串

const reverse = (str) => str.split("").reverse().join("");

// Or
const reverse = (str) => [...str].reverse().join("");

// Or
const reverse = (str) =>
  str.split("").reduce((rev, char) => `${char}${rev}`, "");

// Or
const reverse = (str) =>
  str === "" ? "" : `${reverse(str.substr(1))}${str.charAt(0)}`;

// Example
reverse("hello world"); // 'dlrow olleh'

按字母顺序对字符串的字符进行排序

const sort = (str) =>
  str
    .split("")
    .sort((a, b) => a.localeCompare(b))
    .join("");

// Example
sort("hello world"); // dehllloorw

从字符串中删除 ANSI 代码

const stripAnsiCodes = (str) =>
  str.replace(
    /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
    ""
  );

// Example
stripAnsiCodes("\u001B[4mcake\u001B[0m"); // 'cake'
stripAnsiCodes(
  "\u001B[0m\u001B[4m\u001B[42m\u001B[31mfoo\u001B[39m\u001B[49m\u001B[24mfoo\u001B[0m"
); // 'foofoo'

在字符串的开头和结尾处使用斜杠

const trimSlashes = (str) => str.replace(/^\/+|\/+$/g, "");

// Or
const trimSlashes = (str) => str.split("/").filter(Boolean).join("/");

// Example
trimSlashes("//hello/world///"); // hello/world

修剪一些角色

const trim = (str, char) => str.split(char).filter(Boolean).join();

// Examples
trim("/hello world//", "/"); // hello world
trim('"hello world"', '"'); // hello world
trim("   hello world ", " "); // hello world

从文件名修剪文件扩展名

const trimExt = (fileName) =>
  fileName.indexOf(".") === -1
    ? fileName
    : fileName.split(".").slice(0, -1).join(".");

// Examples
trimExt("document"); // document
trimExt("document.pdf"); // document
trimExt("document.2020.pdf"); // document.2020

用完整的单词截断字符串

const truncate = (str, max, suffix) =>
  str.length < max
    ? str
    : `${str.substr(
        0,
        str.substr(0, max - suffix.length).lastIndexOf(" ")
      )}${suffix}`;

// Example
truncate("This is a long message", 20, "..."); // 'This is a long...'

Unescape html 特殊字符

const unescape = (str) =>
  str
    .replace(/&/g, "&")
    .replace(/&lt;/g, "<")
    .replace(/&gt;/g, ">")
    .replace(/&#0*39;/g, "'")
    .replace(/&quot;/g, '"');

将字符串中每个单词的第一个字符大写

const uppercaseWords = (str) =>
  str
    .split(" ")
    .map((w) => `${w.charAt(0).toUpperCase()}${w.slice(1)}`)
    .join(" ");

// Or
const uppercaseWords = (str) =>
  str.replace(/^(.)|\s+(.)/g, (c) => c.toUpperCase());

// Example
uppercaseWords("hello world"); // 'Hello World'

验证器

检查日期是否在两个日期之间

// `min`, `max` and `date` are `Date` instances
const isBetween = (date, min, max) =>
  date.getTime() >= min.getTime() && date.getTime() <= max.getTime();

检查日期是否是今天

// `date` is a Date object
const isToday = (date) =>
  date.toISOString().slice(0, 10) === new Date().toISOString().slice(0, 10);

检查给定的整数是否是质数

const isPrime = (num) =>
  num > 1 &&
  Array(Math.floor(Math.sqrt(num)) - 1)
    .fill(0)
    .map((_, i) => i + 2)
    .every((i) => num % i !== 0);

检查数字是否为 2 的幂

const isPowerOfTwo = (number) => (number & (number - 1)) === 0;

// Examples
isPowerOfTwo(256); // true
isPowerOfTwo(129); // false

检查数字是否为偶数

const isEven = (number) => number % 2 === 0;

// Or
const isEven = (number) => (number & 1) === 0;

// Or
const isEven = (number) => !(number & 1);

// Or
const isEven = (number) => Number.isInteger(number / 2);

// Examples
isEven(1); // false
isEven(2); // true

检查数字是否在给定范围内

const inRange = (num, a, b) => Math.min(a, b) <= num && num < Math.max(a, b);

// Example
inRange(10, 5, 15); // true
inRange(10, 5, 6); // false
inRange(10, 15, 5); // true
inRange(-10, -5, -15); // true

检查数字是否为负

const isNegative = (number) => Math.sign(number) === -1;

// Or
const isNegative = (number) => number < 0;

// Examples
isNegative(-3); // true
isNegative(8); // false

检查数字是否为奇数

const isOdd = (number) => number % 2 !== 0;

// Or
const isOdd = (number) => !!(number & 1);

// Or
const isOdd = (number) => !Number.isInteger(number / 2);

// Examples
isOdd(1); // true
isOdd(2); // false

检查数字是否为正

const isPositive = (number) => Math.sign(number) === 1;

// Examples
isPositive(3); // true
isPositive(-8); // false

检查字符串是否包含小写字符

const containsLowerCase = (str) => str !== str.toUpperCase();

// Examples
containsLowerCase("Hello World"); // true
containsLowerCase("HELLO WORLD"); // false

检查字符串是否仅包含 ASCII 字符

const isAscii = (str) => /^[\x00-\x7F]+$/.test(str);

检查字符串是否仅包含数字

const isNumeric = (str) => !/[^0-9]/.test(str);

// Examples
isNumeric(2); // true
isNumeric("23"); // true
isNumeric("00123"); // true

isNumeric("1.23"); // false
isNumeric("-Infinity"); // false
isNumeric("Infinity"); // false
isNumeric("NaN"); // false

检查字符串是否仅包含字母和数字

const isAlphanumeric = (str) => /^[0-9A-Z]+$/i.test(str);

// Examples
isAlphanumeric("helloworld"); // true
isAlphanumeric("HelloWorld"); // true
isAlphanumeric("hello world"); // false
isAlphanumeric("hello123"); // true
isAlphanumeric("hello 123"); // false

检查字符串是否仅包含字母

const isAlpha = (str) => /^[A-Z]+$/i.test(str);

// Examples
isAlpha("helloworld"); // true
isAlpha("HelloWorld"); // true
isAlpha("hello world"); // false
isAlpha("0123456789"); // false

检查字符串是否包含大写字符

const containsUpperCase = (str) => str !== str.toLowerCase();

// Examples
containsUpperCase("Hello World"); // true
containsUpperCase("hello world"); // false

检查字符串是否包含空格

const containsWhitespace = (str) => (str) => /\s/.test(str);

// Example
containsWhitespace("hello world"); // true

检查字符串是否为十六进制颜色

const isHexColor = (color) =>
  /^#([0-9A-F]{3}|[0-9A-F]{4}|[0-9A-F]{6}|[0-9A-F]{8})$/i.test(color);

// Examples
isHexColor("#012"); // true
isHexColor("#A1B2C3"); // true
isHexColor("012"); // false
isHexColor("#GHIJKL"); // false

检查字符串是否为十六进制数字

const isHexadecimal = (str) => /^[A-F0-9]+$/i.test(str);

// Or
const isHexadecimal = (str) =>
  str.split("").every((c) => "0123456789ABCDEFabcdef".indexOf(c) !== -1);

// Examples
isHexadecimal("123"); // true
isHexadecimal("A1B2C3"); // true
isHexadecimal("#123"); // false

检查字符串是否为小写

const isLowerCase = (str) => str === str.toLowerCase();

检查字符串是否为大写

const isUpperCase = (str) => str === str.toUpperCase();

检查值是否为数字

const isNumber = (value) => !isNaN(parseFloat(value)) && isFinite(value);

检查值是否为普通对象

const isPlainObject = (v) =>
  !!v &&
  typeof v === "object" &&
  (v.__proto__ === null || v.__proto__ === Object.prototype);

// Examples
isPlainObject(null); // false
isPlainObject("hello world"); // false
isPlainObject([]); // false
isPlainObject(Object.create(null)); // false
isPlainObject(function () {}); // false

isPlainObject({}); // true
isPlainObject({ a: "1", b: "2" }); // true

检查值是否为正则表达式

const isRegExp = (value) =>
  Object.prototype.toString.call(value) === "[object RegExp]";

检查值是否为字符串

const isString = (value) =>
  Object.prototype.toString.call(value) === "[object String]";

// Examples
isString("hello world"); // true
isString(new String("hello world")); // true
isString(10); // false

检查值是否为对象

const isObject = (v) => v !== null && typeof v === "object";

// Examples
isObject(null); // false
isObject("hello world"); // false

isObject({}); // true
isObject([]); // true

检查值是否为零

const isNil = (value) => value == null;

检查一年是否为 leap 年

const isLeapYear = (year) =>
  (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;

// Or
// Get the number of days in February
const isLeapYear = (year) => new Date(year, 1, 29).getDate() === 29;

检查所有数组元素是否等于给定值

const isEqual = (arr, value) => arr.every((item) => item === value);

// Or
// Ends earlier for false arrays
const isEqual = (arr, value) => !arr.some((item) => item !== value);

// Examples
isEqual(["foo", "foo"], "foo"); // true
isEqual(["foo", "bar"], "foo"); // false
isEqual(["bar", "bar"], "foo"); // false

检查数组中的所有项目是否相等

const areEqual = (arr) =>
  arr.length > 0 && arr.every((item) => item === arr[0]);

// Or
const areEqual = (arr) => new Set(arr).size === 1;

// Examples
areEqual([1, 2, 3, 4]); // false
areEqual(["hello", "hello", "hello"]); // true

检查数组是否包含与某些条件匹配的值

const contains = (arr, criteria) => arr.some((v) => criteria(v));

// Or
const contains = (arr, criteria) => arr.some(criteria);

// Or
const contains = (arr, criteria) => arr.filter(criteria).length > 0;

// Examples
contains([10, 20, 30], (v) => v > 25); // true
contains([10, 20, 30], (v) => v > 100 || v < 15); // true
contains([10, 20, 30], (v) => v > 100); // false

检查数组是否为空

const isNotEmpty = (arr) => Array.isArray(arr) && Object.keys(arr).length > 0;

// Examples
isNotEmpty([]); // false
isNotEmpty([1, 2, 3]); // true

检查一个数组是否是其他数组的子集

// Check if `b` is subset of `a`
const isSubset = (a, b) => new Set(b).size === new Set(b.concat(a)).size;

// Or
const isSubset = (a, b) => b.join("|").includes(a.join("|"));

// Examples
isSubset([1, 2], [1, 2, 3, 4]); // true
isSubset([1, 2, 5], [1, 2, 3, 4]); // false
isSubset([6], [1, 2, 3, 4]); // false

检查一个对象是否是一个 promise 对象

const isPromise = (obj) =>
  !!obj &&
  (typeof obj === "object" || typeof obj === "function") &&
  typeof obj.then === "function";

检查对象是否为数组

const isArray = (obj) => Array.isArray(obj);

检查对象是否为空

const isEmpty = (obj) =>
  Reflect.ownKeys(obj).length === 0 && obj.constructor === Object;

// Or for enumerable property names only
const isEmpty = (obj) => JSON.stringify(obj) === "{}";

验证公历

// `m`: the month (zero-based index)
// `d`: the day
// `y`: the year
const isValidDate = (m, d, y) =>
  0 <= m &&
  m <= 11 &&
  0 < y &&
  y < 32768 &&
  0 < d &&
  d <= new Date(y, m, 0).getDate();
打赏
给作者赏一杯咖啡吧
您的支持将是我继续更新下去的动力
微信微信
支付宝支付宝