JavaScript 可以做很多神奇的事情!
从复杂的框架到处理 API,有太多的东西需要学习。
但是,它也能让你只用一行代码就能做一些了不起的事情。
下面这些 JavaScript 单行代码,会让你看起来像个专家!
1. 通过Math.random随机获取值
随机布尔值 (true/false)
使用 Math.random
将在 0 和 1 之间创建一个随机数,之后我们检查它是否高于或低于 0.5。这意味着得到真或假的几率是 50%/50%。
const randomBoolean = () => Math.random() >= 0.5;
console.log(randomBoolean());
// Result: a 50/50 change on returning true of false
// 生成随机字符串
Math.random().toString(36).slice(2) // fgvwj5eiat
随机指定范围数值
const range = (max, min) => Math.round(Math.random() * (max - min) + min);
range(1, 5); // 随机生成 1~5之间的数据(包括1,5)
数组随机排序
数组排序使用 Array.sort
,此方法返回值为: 小于0
等于0
大于0
,小于0则数值大和数值小的交换,等于0则不交换,大于0则数值小的和数值大的交换,知道这个规则,我们可以实现随机返回正数,负数,或0来实现乱序排序(俗称洗牌)。
const arr = [134, 4, 3, 7, 6, 788, 34, 76, 2];
console.log(arr.sort(() => Math.random() - 0.5)); // [134, 4, 34, 6, 7, 3, 788, 2, 76]
console.log(arr.sort(() => Math.random() - 0.5)); // [788, 76, 3, 2, 6, 34, 4, 7, 134]
console.log(arr.sort(() => Math.random() - 0.5)); // [2, 7, 4, 788, 76, 3, 134, 6, 34]
2. 检查日期是否为工作日
使用这个方法,你就可以检查函数参数是工作日还是周末。
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)
3. 反转字符串
有几种不同的方法来反转一个字符串。以下代码是最简单的方式之一。
const reverse = str => str.split('').reverse().join('');
reverse('hello world');
// Result: 'dlrow olleh'
4.检查当前 Tab 页是否在前台
我们可以通过使用 document.hidden
属性来检查当前标签页是否在前台中。
const isBrowserTabInView = () => document.hidden;
isBrowserTabInView();
// Result: returns true or false depending on if tab is in view / focus
5. 检查数字是否为偶数
最简单的方式是通过使用模数运算符(%)来解决。如果你对它不太熟悉,这里是 Stack Overflow上的一个很好的图解。
const isEven = num => num % 2 === 0;
console.log(isEven(2));
// Result: true
console.log(isEven(3));
// Result: false
6.从日期中获取时间
通过使用 toTimeString()
方法,在正确的位置对字符串进行切片,我们可以从提供的日期中获取时间或者当前时间。
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
7. 保留小数点(非四舍五入)
使用 Math.pow()
方法,我们可以将一个数字截断到某个小数点。
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
8. 检查元素当前是否为聚焦状态
我们可以使用 document.activeElement
属性检查一个元素当前是否处于聚焦状态。
const elementIsInFocus = (el) => (el === document.activeElement);
elementIsInFocus(anyElement)
// Result: will return true if in focus, false if not in focus
9. 检查浏览器是否支持触摸事件
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
10. 检查当前用户是否为苹果设备
我们可以使用 navigator.platform
来检查当前用户是否为苹果设备。
const isAppleDevice = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
console.log(isAppleDevice);
// Result: will return true if user is on an Apple device
11. 滚动到页面顶部
window.scrollTo()
方法会取一个 x 和 y 坐标来进行滚动。如果我们将这些坐标设置为零,就可以滚动到页面的顶部。
注意:IE 不支持 scrollTo()
方法。
const goToTop = () => window.scrollTo(0, 0);
goToTop();
// Result: will scroll the browser to the top of the page
12. 获取所有参数平均值
我们可以使用 reduce
方法来获得函数参数的平均值
const average = (...args) => args.reduce((a, b) => a + b) / args.length;
average(1, 2, 3, 4);
// Result: 2.5
13. 转换华氏度/摄氏度。
处理温度有时会让人感到困惑。这 2 个功能将帮助你将华氏温度转换为摄氏温度,反之亦然。
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
14. 快速取整
const n1 = 3.1245;
console.log(~~n1); // 3
console.log(~~5.9545); // 5
console.log(~~134.166545); // 134
console.log(~~-45.34); // -45
console.log(~~-1.845); // -1
console.log(~~-0.845); // 0
15. 月份日期前面补零
// 假设日期是 2021 年 3 月 6 日 早上 8 点 7 分 9秒
const date = new Date(2021, 2, 6, 8, 7, 9);
// 希望展示格式如果是各位则前面补零
console.log(0${date.getMonth() + 1}.slice(-2)); // 03
console.log(0${date.getHours()}.slice(-2)) // 08
上面看懂了吗?就是 前面补0然后 slice(-2),从后往前截取两位
011.slice(-2) // 11
01.slice(-2) // 01
09.slice(-2) // 09
16. 多状态切换
例如排序状态的切换, asc -> desc -> default -> asc
状态的切换是个闭环,状态由前一个变为下一个,如果到了最后一个状态又变回第一个状态。
我们定义一个数组,用来表示要切换的排序
function nextOrder(order) {
const orders = ['asc', 'desc', 'default'];
return orders[(orders.indexOf(order) + 1) % orders.length];
}
如上我们实现一个排序的切换过程
console.log(nextOrder('asc')); // desc
console.log(nextOrder('desc')); // default
console.log(nextOrder('default')); // asc
console.log(nextOrder('asc')); // desc
17. 测试一个字符由两个字节还是由四个字节组成的最简单方法
function is32Bit(c) {
return c.codePointAt(0) > 0xFFFF;
}
is32Bit("𠮷") // true (注意这个“𠮷”不是吉祥的“吉”)
/*
这里科普一下:
JavaScript 内部,字符以 UTF-16 的格式储存,每个字符固定为2个字节。
对于那些需要4个字节储存的字符(Unicode 码点大于0xFFFF的字符),JavaScript 会认为它们是两个字符。
如上所说
'𠮷'.length // 2, 因为该 Unicode 码点大于 0xFFFF
'吉'.length // 1
*/
is32Bit("a") // false
// 判断用户输入字符串长度
function codePointLength(text) {
var result = text.match(/[\s\S]/gu);
return result ? result.length : 0;
}
var s = '𠮷𠮷';
s.length // 4
codePointLength(s) // 2
18. 浮点数对比时精度丢失解决
ES6 在Number
对象上面,新增一个极小的常量Number.EPSILON
。根据规格,它表示 1 与大于 1 的最小浮点数之间的差。
Number.EPSILON
实际上是 JavaScript 能够表示的最小精度。误差如果小于这个值,就可以认为已经没有意义了,即不存在误差了。
引入一个这么小的量的目的,在于为浮点数计算,设置一个误差范围。我们知道浮点数计算是不精确的。
0.1 + 0.2 === 0.3 // 结果为false
// 因为 0.1 + 0.2 结果为 0.30000000000000004
// 故而出现以下结果
0.1 + 0.2 - 0.3 // 5.551115123125783e-17
// 判断浮点数运算后的结果是否相等
function isEqual(left, right) {
return Math.abs(left - right) < Number.EPSILON * Math.pow(2, 2);
}
isEqual(0.1 + 0.2, 0.3) // true
isEqual(1.1 + 1.3, 2.4) // true
19. 浮点加法运算数精度丢失问题
// 获取小数点的长度
function getDotLength(n) {
const s = String(n).split('.');
return s.length > 1 ? s[1].length : 0;
}
// 浮点数计算器 加法
function floatCalculatorAdd(...args) {
// 获取所有数字小数位的长度
const floatLengths = args.map((cur) => {
cur = Number(cur) || 0; // 转成 number,类型,无法转number类型的默认为0
return getDotLength(cur);
});
// 获取最长的小数点位数
const maxFloatLen = Math.max(...floatLengths);
// 放大bei shubeishu
const scale = Math.pow(10, maxFloatLen);
const res = args
.map(n => (Number(n) || 0) * scale)
.reduce((acc, cur) => acc + cur, 0);
return res / scale;
}
floatCalculatorAdd(0.1, 0.2) // 0.3
floatCalculatorAdd(1, 3.12, '2.456', 'AF', 0, -123.2) // -116.624
20. 组合函数
// 组合函数
const composeFn = (...funcs) => val => funcs.reduce((a, b) => b(a), val);
/*
应用场景:
例如对一个字符串实现去除前后空格,首字母大写,并在结尾加上句号
这个时候我们代码实现方式可能如下
*/
// 去除前后空格函数
const trim = str => str.replace(/(^\s+)|(\s+$)/g, '');
// 首字母转大写函数
const firstLetterUpper = str => str.slice(0, 1).toUpperCase() + str.slice(1);
// 字符串最后添加。符号
const addSuffix = str => str + '。';
var str = " hi, I am Andy ";
// 实现需求
addSuffix(firstLetterUpper(trim(str))); // Hi, I am Andy。
// 利用组合函数,将多个操作组合成一个函数,方便使用。
const formatStr = composeFn(trim, firstLetterUpper, addSuffix);
formatStr(str); // Hi, I am Andy。
21. 查询参数转为对象
Object.fromEntries(new URLSearchParams('foo=bar&baz=qux'))
// { foo: "bar", baz: "qux" }
22. 数组的平铺 flattern 函数
function flattern(array) {
if (!Array.isArray(array)) {
return array;
}
return [].concat(...array.map(flattern));
}
flattern([1, 2, [3, 4, [5, 6, [7, 8]]]]); // [1, 2, 3, 4, 5, 6. 7, 8]
23. 金额格式化展示
const options = {
style: 'currency',
currency: 'CNY',
};
(91249.139).toLocaleString('zh-CN', options); // ¥91,249.14 (小数点后面会进行四舍五入)
(99999.9999).toLocaleString(options); // 100,000
24. 将一串数字转换成从右往左每三位数用逗号分隔
function formatNum(num) {
// (\+|-)? 表示 正负号; (\d+) 表示整数部分; (\.\d+)? 表示小数部分
if (!/^(\+|-)?(\d+)(\.\d+)?$/.test(num)) {
// 不满足规则说明传递来的数据不是一个正常数字的格式
alert("wrong!"); return num;
}
// 上面已经执行了test,所以这里的a、b、c已经是能够获得值的了,分别是正负号、整数部分、小数部分。
var a = RegExp.$1, b = RegExp.$2, c = RegExp.$3;
// 用来匹配出整数部分 首次出现连续四个数字加一个逗号 或者 结尾连续四个数字 的形式;
var re =/(\d)(\d{3})(,|$)/;
// 从左往右匹配 当遇到第一个逗号就停止,或者没有逗号一直到结尾停止。这样拿到逗号(结尾)前四个数字
while (re.test(b)) {
// 将匹配成功的四个数字,替换成一个数字加逗号加三个数字的形式
// $1 表示正则表达式中的第一个子表达式,也就是 (\d) ,它表示匹配到的四个数字中的第一个数字
// $2 也就是 (\d{3}) , 表示匹配到的 后面三个数字
// $3 也就是 (,|$) , 表示匹配到的四个数字后面的 逗号或者空(结尾就是空)
// replace方法是不影响原字符串的,它返回一个替换好的新字符串,所以这里要将替换好的覆盖原来的
b = b.replace(re, "$1,$2$3");
// 由于re不是全局的正则表达式( 没有加参数g ),所以每次循环替换首次匹配成功的一处
// 也就是 每次循环 拿到 整数部分第一个逗号往前数的 四个数字
// 然后 将拿到的四个数字中 在第一个数字与后三个数字之间加上逗号
// 直到整数部分从左往右 匹配不到 连续四个数字加逗号 的形式,循环结束
}
// 拼接原来的正负号、已分隔好的整数部分、原来的小数部分
return a + "" + b + "" + c;
}
formatNum('1123456') // 1,123,456
formatNum('-123456789.1234') // -123,456,789.1234
25. 转义HTML特殊字符
如果你了解 XSS,解决方案之一就是转义 HTML 字符串
escape = str => str.replace(/[&<>"']/g, m => ({
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
}[m]))
escape('<div class="medium">Hi Medium.</div>') // "<div class="medium">Hi Medium.</div>"
26. 将字符串中每个单词的第一个字符大写
此方法用于将字符串中每个单词的第一个字符大写。
const uppercaseWords = str => str.replace(/^(.)|\s+(.)/g, c => c.toUpperCase())
uppercaseWords('hello world') // Hello World
27. 将字符串转换为驼峰命名法
const toCamelCase = str => str.trim().replace(/[-_\s]+(.)?/g, (_, c) => c ? c.toUpperCase() : '')
toCamelCase('background-color'); // backgroundColor
toCamelCase('-webkit-scrollbar-thumb'); // WebkitScrollbarThumb
toCamelCase('_hello_world'); // HelloWorld
toCamelCase('hello_world'); // helloWorld
28. 数组对象根据某个字段去重
/**
* 数组根据某个字段去重
* @param {*} arr 对象数组
* @param {*} field 对象字段
* @returns 去重后的数组
*/
function uniqueArrayByField(arr, field) {
const map = new Map() // 利用 map 特性,可以做到高性能
return arr.filter(item => !map.has(item[field]) && map.set(item[field], 1))
}
// 例如根据 arr 对象的 stuId 字段去重
uniqueArrayByField(arr, 'stuId')
29. 使用位操作
// 取模
if (value % 2) { // 奇数
} else { // 偶数
}
// 位操作
if (value & 1) { // 奇数
} else { // 偶数
}
// 二进制左位移
const a = 1 << 0 // 1
const b = 1 << 1 // 2
const c = 1 << 2 // 4
const d = 1 << 3 // 8
a | b // 3
b | c // 6
c | d // 12
d | d // 8
a | b | c | d // 15
30. 响应式图片
通过 picture 实现
<picture>
<source srcset="banner_w1000.jpg" media="(min-width: 801px)">
<source srcset="banner_w800.jpg" media="(max-width: 800px)">
<img src="banner.jpg" alt="">
</picture>
通过 @media 实现
@media (min-width: 769px) {
.bg {
background-image: url(bg1080.jpg);
}
}
@media (max-width: 768px) {
.bg {
background-image: url(bg768.jpg);
}
}