JavaScript 可以做很多神奇的事情剿吻!
從復(fù)雜的框架到處理 API窍箍,有太多的東西需要學(xué)習(xí)。
但是丽旅,它也能讓你只用一行代碼就能做一些了不起的事情椰棘。
下面這些 JavaScript 單行代碼,會(huì)讓你看起來(lái)像個(gè)專家!
1. 通過(guò)Math.random隨機(jī)獲取值
隨機(jī)布爾值 (true/false)
使用 Math.random
將在 0 和 1 之間創(chuàng)建一個(gè)隨機(jī)數(shù)榄笙,之后我們檢查它是否高于或低于 0.5邪狞。這意味著得到真或假的幾率是 50%/50%。
const randomBoolean = () => Math.random() >= 0.5;
console.log(randomBoolean());
// Result: a 50/50 change on returning true of false
// 生成隨機(jī)字符串
Math.random().toString(36).slice(2) // fgvwj5eiat
隨機(jī)指定范圍數(shù)值
const range = (max, min) => Math.round(Math.random() * (max - min) + min);
range(1, 5); // 隨機(jī)生成 1~5之間的數(shù)據(jù)(包括1茅撞,5)
數(shù)組隨機(jī)排序
數(shù)組排序使用 Array.sort
帆卓,此方法返回值為: 小于0
等于0
大于0
巨朦,小于0則數(shù)值大和數(shù)值小的交換,等于0則不交換鳞疲,大于0則數(shù)值小的和數(shù)值大的交換罪郊,知道這個(gè)規(guī)則,我們可以實(shí)現(xiàn)隨機(jī)返回正數(shù)尚洽,負(fù)數(shù)悔橄,或0來(lái)實(shí)現(xiàn)亂序排序(俗稱洗牌)。
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. 檢查日期是否為工作日
使用這個(gè)方法腺毫,你就可以檢查函數(shù)參數(shù)是工作日還是周末癣疟。
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. 反轉(zhuǎn)字符串
有幾種不同的方法來(lái)反轉(zhuǎn)一個(gè)字符串。以下代碼是最簡(jiǎn)單的方式之一潮酒。
const reverse = str => str.split('').reverse().join('');
reverse('hello world');
// Result: 'dlrow olleh'
4.檢查當(dāng)前 Tab 頁(yè)是否在前臺(tái)
我們可以通過(guò)使用 document.hidden
屬性來(lái)檢查當(dāng)前標(biāo)簽頁(yè)是否在前臺(tái)中睛挚。
const isBrowserTabInView = () => document.hidden;
isBrowserTabInView();
// Result: returns true or false depending on if tab is in view / focus
5. 檢查數(shù)字是否為偶數(shù)
最簡(jiǎn)單的方式是通過(guò)使用模數(shù)運(yùn)算符(%)來(lái)解決。如果你對(duì)它不太熟悉急黎,這里是 Stack Overflow上的一個(gè)很好的圖解扎狱。
const isEven = num => num % 2 === 0;
console.log(isEven(2));
// Result: true
console.log(isEven(3));
// Result: false
6.從日期中獲取時(shí)間
通過(guò)使用 toTimeString()
方法,在正確的位置對(duì)字符串進(jìn)行切片勃教,我們可以從提供的日期中獲取時(shí)間或者當(dāng)前時(shí)間淤击。
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. 保留小數(shù)點(diǎn)(非四舍五入)
使用 Math.pow()
方法,我們可以將一個(gè)數(shù)字截?cái)嗟侥硞€(gè)小數(shù)點(diǎn)故源。
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. 檢查元素當(dāng)前是否為聚焦?fàn)顟B(tài)
我們可以使用 document.activeElement
屬性檢查一個(gè)元素當(dāng)前是否處于聚焦?fàn)顟B(tài)污抬。
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. 檢查當(dāng)前用戶是否為蘋(píng)果設(shè)備
我們可以使用 navigator.platform
來(lái)檢查當(dāng)前用戶是否為蘋(píng)果設(shè)備。
const isAppleDevice = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
console.log(isAppleDevice);
// Result: will return true if user is on an Apple device
11. 滾動(dòng)到頁(yè)面頂部
window.scrollTo()
方法會(huì)取一個(gè) x 和 y 坐標(biāo)來(lái)進(jìn)行滾動(dòng)绳军。如果我們將這些坐標(biāo)設(shè)置為零印机,就可以滾動(dòng)到頁(yè)面的頂部。
注意:IE 不支持 scrollTo()
方法门驾。
const goToTop = () => window.scrollTo(0, 0);
goToTop();
// Result: will scroll the browser to the top of the page
12. 獲取所有參數(shù)平均值
我們可以使用 reduce
方法來(lái)獲得函數(shù)參數(shù)的平均值
const average = (...args) => args.reduce((a, b) => a + b) / args.length;
average(1, 2, 3, 4);
// Result: 2.5
13. 轉(zhuǎn)換華氏度/攝氏度射赛。
處理溫度有時(shí)會(huì)讓人感到困惑。這 2 個(gè)功能將幫助你將華氏溫度轉(zhuǎn)換為攝氏溫度猎唁,反之亦然咒劲。
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. 月份日期前面補(bǔ)零
// 假設(shè)日期是 2021 年 3 月 6 日 早上 8 點(diǎn) 7 分 9秒
const date = new Date(2021, 2, 6, 8, 7, 9);
// 希望展示格式如果是各位則前面補(bǔ)零
console.log(0${date.getMonth() + 1}.slice(-2)); // 03
console.log(0${date.getHours()}.slice(-2)) // 08
上面看懂了嗎?就是 前面補(bǔ)0然后 slice(-2)诫隅,從后往前截取兩位
011.slice(-2) // 11
01.slice(-2) // 01
09.slice(-2) // 09
16. 多狀態(tài)切換
例如排序狀態(tài)的切換腐魂, asc -> desc -> default -> asc
狀態(tài)的切換是個(gè)閉環(huán),狀態(tài)由前一個(gè)變?yōu)橄乱粋€(gè)逐纬,如果到了最后一個(gè)狀態(tài)又變回第一個(gè)狀態(tài)蛔屹。
我們定義一個(gè)數(shù)組,用來(lái)表示要切換的排序
function nextOrder(order) {
const orders = ['asc', 'desc', 'default'];
return orders[(orders.indexOf(order) + 1) % orders.length];
}
如上我們實(shí)現(xiàn)一個(gè)排序的切換過(guò)程
console.log(nextOrder('asc')); // desc
console.log(nextOrder('desc')); // default
console.log(nextOrder('default')); // asc
console.log(nextOrder('asc')); // desc
17. 測(cè)試一個(gè)字符由兩個(gè)字節(jié)還是由四個(gè)字節(jié)組成的最簡(jiǎn)單方法
function is32Bit(c) {
return c.codePointAt(0) > 0xFFFF;
}
is32Bit("??") // true (注意這個(gè)“??”不是吉祥的“吉”)
/*
這里科普一下:
JavaScript 內(nèi)部豁生,字符以 UTF-16 的格式儲(chǔ)存兔毒,每個(gè)字符固定為2個(gè)字節(jié)漫贞。
對(duì)于那些需要4個(gè)字節(jié)儲(chǔ)存的字符(Unicode 碼點(diǎn)大于0xFFFF的字符),JavaScript 會(huì)認(rèn)為它們是兩個(gè)字符育叁。
如上所說(shuō)
'??'.length // 2迅脐, 因?yàn)樵?Unicode 碼點(diǎn)大于 0xFFFF
'吉'.length // 1
*/
is32Bit("a") // false
// 判斷用戶輸入字符串長(zhǎng)度
function codePointLength(text) {
var result = text.match(/[\s\S]/gu);
return result ? result.length : 0;
}
var s = '????';
s.length // 4
codePointLength(s) // 2
18. 浮點(diǎn)數(shù)對(duì)比時(shí)精度丟失解決
ES6 在Number
對(duì)象上面,新增一個(gè)極小的常量Number.EPSILON
豪嗽。根據(jù)規(guī)格谴蔑,它表示 1 與大于 1 的最小浮點(diǎn)數(shù)之間的差。
Number.EPSILON
實(shí)際上是 JavaScript 能夠表示的最小精度龟梦。誤差如果小于這個(gè)值隐锭,就可以認(rèn)為已經(jīng)沒(méi)有意義了,即不存在誤差了计贰。
引入一個(gè)這么小的量的目的钦睡,在于為浮點(diǎn)數(shù)計(jì)算,設(shè)置一個(gè)誤差范圍躁倒。我們知道浮點(diǎn)數(shù)計(jì)算是不精確的荞怒。
0.1 + 0.2 === 0.3 // 結(jié)果為false
// 因?yàn)?0.1 + 0.2 結(jié)果為 0.30000000000000004
// 故而出現(xiàn)以下結(jié)果
0.1 + 0.2 - 0.3 // 5.551115123125783e-17
// 判斷浮點(diǎn)數(shù)運(yùn)算后的結(jié)果是否相等
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. 浮點(diǎn)加法運(yùn)算數(shù)精度丟失問(wèn)題
// 獲取小數(shù)點(diǎn)的長(zhǎng)度
function getDotLength(n) {
const s = String(n).split('.');
return s.length > 1 ? s[1].length : 0;
}
// 浮點(diǎn)數(shù)計(jì)算器 加法
function floatCalculatorAdd(...args) {
// 獲取所有數(shù)字小數(shù)位的長(zhǎng)度
const floatLengths = args.map((cur) => {
cur = Number(cur) || 0; // 轉(zhuǎn)成 number,類型秧秉,無(wú)法轉(zhuǎn)number類型的默認(rèn)為0
return getDotLength(cur);
});
// 獲取最長(zhǎng)的小數(shù)點(diǎn)位數(shù)
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. 組合函數(shù)
// 組合函數(shù)
const composeFn = (...funcs) => val => funcs.reduce((a, b) => b(a), val);
/*
應(yīng)用場(chǎng)景:
例如對(duì)一個(gè)字符串實(shí)現(xiàn)去除前后空格挣输,首字母大寫(xiě),并在結(jié)尾加上句號(hào)
這個(gè)時(shí)候我們代碼實(shí)現(xiàn)方式可能如下
*/
// 去除前后空格函數(shù)
const trim = str => str.replace(/(^\s+)|(\s+$)/g, '');
// 首字母轉(zhuǎn)大寫(xiě)函數(shù)
const firstLetterUpper = str => str.slice(0, 1).toUpperCase() + str.slice(1);
// 字符串最后添加福贞。符號(hào)
const addSuffix = str => str + '。';
var str = " hi, I am Andy ";
// 實(shí)現(xiàn)需求
addSuffix(firstLetterUpper(trim(str))); // Hi, I am Andy停士。
// 利用組合函數(shù)挖帘,將多個(gè)操作組合成一個(gè)函數(shù),方便使用恋技。
const formatStr = composeFn(trim, firstLetterUpper, addSuffix);
formatStr(str); // Hi, I am Andy拇舀。
21. 查詢參數(shù)轉(zhuǎn)為對(duì)象
Object.fromEntries(new URLSearchParams('foo=bar&baz=qux'))
// { foo: "bar", baz: "qux" }
22. 數(shù)組的平鋪 flattern 函數(shù)
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 (小數(shù)點(diǎn)后面會(huì)進(jìn)行四舍五入)
(99999.9999).toLocaleString(options); // 100,000
24. 將一串?dāng)?shù)字轉(zhuǎn)換成從右往左每三位數(shù)用逗號(hào)分隔
function formatNum(num) {
// (\+|-)? 表示 正負(fù)號(hào); (\d+) 表示整數(shù)部分蜻底; (\.\d+)? 表示小數(shù)部分
if (!/^(\+|-)?(\d+)(\.\d+)?$/.test(num)) {
// 不滿足規(guī)則說(shuō)明傳遞來(lái)的數(shù)據(jù)不是一個(gè)正常數(shù)字的格式
alert("wrong!"); return num;
}
// 上面已經(jīng)執(zhí)行了test骄崩,所以這里的a、b薄辅、c已經(jīng)是能夠獲得值的了要拂,分別是正負(fù)號(hào)、整數(shù)部分站楚、小數(shù)部分脱惰。
var a = RegExp.$1, b = RegExp.$2, c = RegExp.$3;
// 用來(lái)匹配出整數(shù)部分 首次出現(xiàn)連續(xù)四個(gè)數(shù)字加一個(gè)逗號(hào) 或者 結(jié)尾連續(xù)四個(gè)數(shù)字 的形式;
var re =/(\d)(\d{3})(,|$)/;
// 從左往右匹配 當(dāng)遇到第一個(gè)逗號(hào)就停止窿春,或者沒(méi)有逗號(hào)一直到結(jié)尾停止拉一。這樣拿到逗號(hào)(結(jié)尾)前四個(gè)數(shù)字
while (re.test(b)) {
// 將匹配成功的四個(gè)數(shù)字采盒,替換成一個(gè)數(shù)字加逗號(hào)加三個(gè)數(shù)字的形式
// $1 表示正則表達(dá)式中的第一個(gè)子表達(dá)式,也就是 (\d) 蔚润,它表示匹配到的四個(gè)數(shù)字中的第一個(gè)數(shù)字
// $2 也就是 (\d{3}) 磅氨, 表示匹配到的 后面三個(gè)數(shù)字
// $3 也就是 (,|$) , 表示匹配到的四個(gè)數(shù)字后面的 逗號(hào)或者空(結(jié)尾就是空)
// replace方法是不影響原字符串的嫡纠,它返回一個(gè)替換好的新字符串烦租,所以這里要將替換好的覆蓋原來(lái)的
b = b.replace(re, "$1,$2$3");
// 由于re不是全局的正則表達(dá)式( 沒(méi)有加參數(shù)g ),所以每次循環(huán)替換首次匹配成功的一處
// 也就是 每次循環(huán) 拿到 整數(shù)部分第一個(gè)逗號(hào)往前數(shù)的 四個(gè)數(shù)字
// 然后 將拿到的四個(gè)數(shù)字中 在第一個(gè)數(shù)字與后三個(gè)數(shù)字之間加上逗號(hào)
// 直到整數(shù)部分從左往右 匹配不到 連續(xù)四個(gè)數(shù)字加逗號(hào) 的形式货徙,循環(huán)結(jié)束
}
// 拼接原來(lái)的正負(fù)號(hào)左权、已分隔好的整數(shù)部分、原來(lái)的小數(shù)部分
return a + "" + b + "" + c;
}
formatNum('1123456') // 1,123,456
formatNum('-123456789.1234') // -123,456,789.1234
25. 轉(zhuǎn)義HTML特殊字符
如果你了解 XSS痴颊,解決方案之一就是轉(zhuǎn)義 HTML 字符串
escape = str => str.replace(/[&<>"']/g, m => ({
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
}[m]))
escape('<div class="medium">Hi Medium.</div>') // "<div class="medium">Hi Medium.</div>"
26. 將字符串中每個(gè)單詞的第一個(gè)字符大寫(xiě)
此方法用于將字符串中每個(gè)單詞的第一個(gè)字符大寫(xiě)赏迟。
const uppercaseWords = str => str.replace(/^(.)|\s+(.)/g, c => c.toUpperCase())
uppercaseWords('hello world') // Hello World
27. 將字符串轉(zhuǎn)換為駝峰命名法
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. 數(shù)組對(duì)象根據(jù)某個(gè)字段去重
/**
* 數(shù)組根據(jù)某個(gè)字段去重
* @param {*} arr 對(duì)象數(shù)組
* @param {*} field 對(duì)象字段
* @returns 去重后的數(shù)組
*/
function uniqueArrayByField(arr, field) {
const map = new Map() // 利用 map 特性,可以做到高性能
return arr.filter(item => !map.has(item[field]) && map.set(item[field], 1))
}
// 例如根據(jù) arr 對(duì)象的 stuId 字段去重
uniqueArrayByField(arr, 'stuId')
29. 使用位操作
// 取模
if (value % 2) { // 奇數(shù)
} else { // 偶數(shù)
}
// 位操作
if (value & 1) { // 奇數(shù)
} else { // 偶數(shù)
}
// 二進(jìn)制左位移
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. 響應(yīng)式圖片
通過(guò) picture 實(shí)現(xiàn)
<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>
通過(guò) @media 實(shí)現(xiàn)
@media (min-width: 769px) {
.bg {
background-image: url(bg1080.jpg);
}
}
@media (max-width: 768px) {
.bg {
background-image: url(bg768.jpg);
}
}