盡管我們對 JavaScript 已經(jīng)相當(dāng)熟悉了,但這門語言中仍存在許多有趣的特性和行為,今天分享 12 個(gè)鮮為人知的 JavaScript 冷知識。
1. 函數(shù)的長度屬性
你可能知道數(shù)組有 length
屬性,但函數(shù)也有!函數(shù)的 length
屬性返回函數(shù)期望的參數(shù)個(gè)數(shù)(形參數(shù)量)。
function foo(a, b, c = 3) { return a + b + c; }
console.log(foo.length); // 2,不包括帶默認(rèn)值的參數(shù)!
function bar(a, b = 2, c) { return a + b + c; }
console.log(bar.length); // 1,從第一個(gè)帶默認(rèn)值的參數(shù)開始后面的都不算
(() => {}).length; // 0
((...args) => {}).length; // 0
這個(gè)特性在編寫高階函數(shù)或函數(shù)式編程時(shí)特別有用,可以用來進(jìn)行函數(shù)的參數(shù)匹配。
2. void 運(yùn)算符不只是不返回值
void
運(yùn)算符不僅可以用來確保表達(dá)式不返回值,還可以用來解決一些特殊問題:
// 1. 防止箭頭函數(shù)返回值
const onClick = () => void doSomething();
// 2. 創(chuàng)建純凈的 undefined
let undefined = 'hello';
console.log(void 0); // undefined
// 3. 立即執(zhí)行 Promise
void Promise.resolve().then(() => {
console.log('異步執(zhí)行');
});
// 4. 阻止默認(rèn)的 href 跳轉(zhuǎn)
<a href="javascript:void(0)">點(diǎn)擊</a>
3. Function.prototype.toString() 的變化
ES2019 之后,Function.prototype.toString()
會保留函數(shù)的原始格式,包括注釋和空格:
function /* 這是注釋 */ foo() {
console.log("Hello"); // 這也是注釋
}
console.log(foo.toString());
// function /* 這是注釋 */ foo() {
// console.log("Hello"); // 這也是注釋
// }
// 甚至適用于內(nèi)置函數(shù)
console.log(Array.prototype.push.toString());
// "function push() { [native code] }"
4. 逗號運(yùn)算符的隱藏用途
逗號運(yùn)算符可以在一些意想不到的地方使用,比如箭頭函數(shù)或三元運(yùn)算符中:
// 在箭頭函數(shù)中執(zhí)行多條語句
const increment = x => (console.log(x), x + 1);
// 在三元運(yùn)算符中執(zhí)行多個(gè)操作
const result = condition
? (func1(), func2(), value1)
: (func3(), func4(), value2);
// 在數(shù)組方法中巧妙運(yùn)用
const arr = [1, 2, 3];
arr.map(x => (x *= 2, x -= 1)); // [1, 3, 5]
5. 可選鏈操作符的隱藏技巧
可選鏈操作符不僅可以用于對象屬性,還可以用于函數(shù)調(diào)用和數(shù)組:
// 函數(shù)調(diào)用
const result = someFunction?.();
// 數(shù)組訪問
const arr = null;
console.log(arr?.[0]); // undefined
// 動態(tài)屬性名
const propName = null;
console.log(obj?.[propName?.toString()]); // undefined
// 與空值合并操作符組合
const value = obj?.prop ?? 'default';
6. Symbol.asyncIterator 的妙用
你可以使用 Symbol.asyncIterator
創(chuàng)建自定義的異步迭代器:
7. 利用 Object.defineProperty 創(chuàng)建常量對象
你可以創(chuàng)建真正的常量對象,其屬性完全不可修改:
8. Label 語句的妙用
JavaScript 中的 label 語句雖然不常見,但在特定場景下非常有用,特別是在嵌套循環(huán)中:
9. 使用 Proxy 實(shí)現(xiàn)私有屬性
在類私有字段還未普及之前,可以使用 Proxy 來模擬私有屬性:
10. 利用 Generator 實(shí)現(xiàn)范圍數(shù)據(jù)類型
JavaScript 沒有原生的范圍類型,但我們可以用 Generator 實(shí)現(xiàn):
11. BigInt 的特殊行為
BigInt 有一些出人意料的行為:
12. Intl API 的強(qiáng)大功能
Intl API 不僅可以用于格式化日期和數(shù)字,還有很多強(qiáng)大的功能:
// 相對時(shí)間格式化
const rtf = new Intl.RelativeTimeFormat('zh', { numeric: 'auto' });
console.log(rtf.format(-1, 'day')); // "昨天"
console.log(rtf.format(7, 'day')); // "7天后"
// 復(fù)數(shù)規(guī)則
const pr = new Intl.PluralRules('en-US');
console.log(pr.select(0)); // "other"
console.log(pr.select(1)); // "one"
console.log(pr.select(2)); // "other"
// 分段器
const segmenter = new Intl.Segmenter('zh', { granularity: 'word' });
const segments = segmenter.segment('你好,世界!');
console.log([...segments].map(s => s.segment)); // ["你好", ",", "世界", "!"]
歡迎補(bǔ)充。
該文章在 2025/1/9 9:21:02 編輯過