10 個(gè) JavaScript 棘手技巧
本文適合對(duì)JavaScript小技巧感興趣的小伙伴閱讀。
歡迎關(guān)注 前端早茶 ,與廣東靚仔攜手共同進(jìn)階~
一、前言
你準(zhǔn)備好學(xué)習(xí)很酷的 JavaScript 技巧了嗎?這些技巧將使您的代碼更好、更容易理解、編寫速度更快。在這篇文章中,我們將探索隱藏的功能和快捷方式,幫助您釋放 JavaScript 的全部威力! 本文分為3部分的10個(gè)JavaScript 棘手技巧第一部分
1. 空合并運(yùn)算符 (??)
空合并運(yùn)算符 (??) 是一個(gè)邏輯運(yùn)算符,當(dāng)其左側(cè)操作數(shù)為 null 或未定義時(shí),它返回其右側(cè)操作數(shù),否則返回其左側(cè)操作數(shù)。當(dāng)您想要為可能為 null 或未定義的變量提供默認(rèn)值時(shí),這會(huì)很有用。
這是一個(gè)簡(jiǎn)單的代碼示例:
let value = null;
let defaultValue = "Default Value";
let result = value ?? defaultValue;
console.log(result); // Outputs: "Default Value"
在此示例中,由于 value 為 null,因此 nullish 合并運(yùn)算符返回 defaultValue,因此“默認(rèn)值”會(huì)記錄到控制臺(tái)。
如果 value 不為 null 或未定義,則會(huì)返回該值:
let value = "Not Null Value";
let defaultValue = "Default Value";
let result = value ?? defaultValue;
console.log(result); // Outputs: "Not Null Value"
在本例中,由于 value 既不是 null 也不是未定義的,所以它是由 nullish 合并運(yùn)算符返回的,因此“Not Null Value”會(huì)記錄到控制臺(tái)。
2. 可選鏈接 (?.)
如果引用為空,則可以安全地訪問嵌套對(duì)象屬性,而不會(huì)出現(xiàn)錯(cuò)誤。這 ?。運(yùn)算符的功能與 . 鏈接運(yùn)算符,不同之處在于,如果引用為空(空或未定義),則表達(dá)式會(huì)短路并返回未定義的值,而不是導(dǎo)致錯(cuò)誤。
這是一個(gè)簡(jiǎn)單的代碼示例:
let user = {
name: "John",
address: {
street: "Main",
city: "New York"
}
};
console.log(user.address.street); // Outputs: "Main"
let user2 = {
name: "Jane"
};
console.log(user2.address?.street); // Outputs: undefined
在此示例中,由于 user2 沒有 address 屬性,因此嘗試訪問 user2.address.street 通常會(huì)導(dǎo)致 TypeError。但是,通過使用可選鏈接運(yùn)算符 (?.),JavaScript 只會(huì)返回 undefined 而不是拋出錯(cuò)誤。
3. 短路評(píng)估
JavaScript 中的短路求值是一種求值布爾表達(dá)式的方法。如果表達(dá)式中的第一個(gè)操作數(shù)足以確定最終結(jié)果,則不計(jì)算第二個(gè)操作數(shù)。這通常與 && (AND) 和 || 一起使用。(或)運(yùn)算符。
這是一個(gè)簡(jiǎn)單的代碼示例:
let a = 0;
let b = 1;
// Using && operator
console.log(a && b); // Outputs: 0
在此示例中,使用 && 運(yùn)算符。對(duì)于 AND 運(yùn)算,如果第一個(gè)操作數(shù)為 false(或像 0 這樣的假值),JavaScript 不需要檢查第二個(gè)操作數(shù),因?yàn)闊o論如何結(jié)果都將為 false。這就是為什么它輸出 0 - 它“短路”并且不評(píng)估 b。
let c = 1;
let d = 2;
// Using || operator
console.log(c || d); // Outputs: 1
在第二個(gè)示例中,|| 使用運(yùn)算符。對(duì)于 OR 運(yùn)算,如果第一個(gè)操作數(shù)為 true(或真值),JavaScript 不需要檢查第二個(gè)操作數(shù),因?yàn)闊o論如何結(jié)果都將為 true。這就是為什么它輸出 1 - 它“短路”并且不評(píng)估 d。
4. 使用map、filter和reduce進(jìn)行數(shù)組操作
讓我們分解一下這些方法:
-
map():此方法創(chuàng)建一個(gè)新數(shù)組,其中包含對(duì)數(shù)組中每個(gè)元素調(diào)用提供的函數(shù)的結(jié)果。
let numbers = [1, 2, 3, 4, 5];
let squares = numbers.map(num => num * num);
console.log(squares); // Outputs: [1, 4, 9, 16, 25]
在此示例中,map() 用于對(duì)數(shù)字?jǐn)?shù)組中的每個(gè)數(shù)字求平方。
-
filter():此方法創(chuàng)建一個(gè)新數(shù)組,其中包含通過所提供函數(shù)實(shí)現(xiàn)的測(cè)試的所有元素
let numbers = [1, 2, 3, 4, 5];
let evens = numbers.filter(num => num % 2 === 0);
console.log(evens); // Outputs: [2, 4]
在此示例中,filter() 用于創(chuàng)建一個(gè)僅包含numbers 數(shù)組中的偶數(shù)的新數(shù)組。
-
reduce():此方法對(duì)累加器和數(shù)組中的每個(gè)元素(從左到右)應(yīng)用函數(shù),以將其減少為單個(gè)輸出值。
let numbers = [1, 2, 3, 4, 5];
let sum = numbers.reduce((total, num) => total + num, 0);
console.log(sum); // Outputs: 15
在此示例中,reduce() 用于對(duì)數(shù)字?jǐn)?shù)組中的所有數(shù)字求和。reduce() 的第二個(gè)參數(shù)(在本例中為 0)是累加器的初始值(在本例中為總計(jì))。
這些方法通常組合使用來執(zhí)行復(fù)雜的數(shù)組操作。例如,您可以首先使用filter()僅獲取偶數(shù),然后使用map()對(duì)這些數(shù)字進(jìn)行平方,最后使用reduce()對(duì)平方求和:
let numbers = [1, 2, 3, 4, 5];
let sumOfEvenSquares = numbers
.filter(num => num % 2 === 0)
.map(num => num * num)
.reduce((total, num) => total + num, 0);
console.log(sumOfEvenSquares); // Outputs: 20
在此示例中,輸出為 20,因?yàn)?2*2 + 4*4 = 4 + 16 = 20。
5. 使用!! 轉(zhuǎn)換為布爾值
在 JavaScript 中,!! 運(yùn)算符用于將值轉(zhuǎn)換為布爾值。首先 !否定該值,將其轉(zhuǎn)換為布爾值并將其反轉(zhuǎn),第二個(gè) ! 將其反轉(zhuǎn)回其原始布爾值。
這是一個(gè)簡(jiǎn)單的代碼示例:
let truthyValue = "Hello, World!";
let falseyValue = "";
console.log(!!truthyValue); // Outputs: true
console.log(!!falseyValue); // Outputs: false
在此示例中,truthyValue 是一個(gè)非空字符串,在 JavaScript 中被視為 true 值,因此 !!truthyValue 返回 true。另一方面, falseyValue 是一個(gè)空字符串,在 JavaScript 中被視為 falsey 值,因此 !!falseyValue 返回 false。
6. 短 if-else 的三元運(yùn)算符
三元運(yùn)算符是許多編程語言(包括 JavaScript)中編寫 if-else 語句的簡(jiǎn)寫方式。之所以稱為三元運(yùn)算符,是因?yàn)樗枰齻€(gè)操作數(shù):一個(gè)條件、條件為真時(shí)的結(jié)果以及條件為假時(shí)的結(jié)果。
語法如下:
condition ? valueIfTrue : valueIfFalse
這是一個(gè)簡(jiǎn)單的代碼示例:
let age = 15;
let beverage = (age >= 21) ? "Beer" : "Juice";
console.log(beverage); // Outputs: "Juice"
在此示例中,條件是年齡 >= 21。如果此條件為真,則飲料變量將設(shè)置為“Beer”。如果條件為假,則飲料設(shè)置為“Juice”。由于年齡為 15,不大于或等于 21,因此條件為 false,因此飲料設(shè)置為“Juice”。
7. 默認(rèn)功能參數(shù)
默認(rèn)函數(shù)參數(shù)允許您設(shè)置函數(shù)參數(shù)的默認(rèn)值。這意味著如果調(diào)用函數(shù)時(shí)沒有為形參提供實(shí)參,則將使用默認(rèn)值。JavaScript ES6 及更高版本中提供此功能。
語法如下:
function functionName(param1 = defaultValue1, param2 = defaultValue2, ...) {
// function body
}
這是一個(gè)簡(jiǎn)單的代碼示例:
function greet(name = "Stranger") {
return "Hello, " + name;
}
console.log(greet()); // Outputs: "Hello, Stranger"
console.log(greet("John")); // Outputs: "Hello, John"
在此示例中,函數(shù)greet 有一個(gè)參數(shù)名稱,默認(rèn)值為“Stranger”。如果您不帶任何參數(shù)調(diào)用greet(),則name參數(shù)將采用其默認(rèn)值,并且該函數(shù)將輸出“Hello,Stranger”。如果調(diào)用greet("John"),name參數(shù)將采用值“John”,并且該函數(shù)將輸出“Hello, John”。
8. 動(dòng)態(tài)字符串的模板文字
模板文字是 JavaScript 中的一項(xiàng)功能,允許您以更加動(dòng)態(tài)和可讀的方式創(chuàng)建字符串。它們是使用反引號(hào) ( ) 而不是單引號(hào)或雙引號(hào)來定義的。
在模板文字中,您可以在 ${} 中包含表達(dá)式、變量和其他 JavaScript 代碼。JavaScript 引擎將評(píng)估 ${} 內(nèi)的代碼并將其結(jié)果插入到字符串中。這使得創(chuàng)建復(fù)雜的字符串變得容易,而無需使用 + 運(yùn)算符連接字符串的各個(gè)部分。
這是一個(gè)簡(jiǎn)單的代碼示例:
let name = "John";
let greeting = `Hello, ${name}!`;
console.log(greeting); // Outputs: "Hello, John!"
在此示例中,使用 ${name} 將變量名稱插入到模板文字中。JavaScript 引擎計(jì)算 name,將 ${name} 替換為 name 的值,然后創(chuàng)建最終的字符串。
您還可以在 ${} 內(nèi)使用表達(dá)式。這是一個(gè)例子:
let a = 5;
let b = 10;
let sum = `The sum of ${a} and ${b} is ${a + b}.`;
console.log(sum); // Outputs: "The sum of 5 and 10 is 15."
在此示例中,計(jì)算表達(dá)式 a + b 并將其結(jié)果插入到字符串中。
9. 解構(gòu)賦值
解構(gòu)賦值是 JavaScript 中的一項(xiàng)功能,它允許您將數(shù)組中的值或?qū)ο笾械膶傩越鈮旱讲煌淖兞恐小_@可以使您的代碼更具可讀性和簡(jiǎn)潔性。
這是一個(gè)數(shù)組的示例:
let numbers = [1, 2, 3];
let [a, b, c] = numbers;
console.log(a); // Outputs: 1
console.log(b); // Outputs: 2
console.log(c); // Outputs: 3
在此示例中,變量 a、b 和 c 分別被賦予 number 數(shù)組的第一個(gè)、第二個(gè)和第三個(gè)元素的值。
解構(gòu)也可以用于對(duì)象:
let person = {
name: "John",
age: 30,
city: "New York"
};
let {name, age, city} = person;
console.log(name); // Outputs: "John"
console.log(age); // Outputs: 30
console.log(city); // Outputs: "New York"
在此示例中,變量 name、age 和 city 被分配為 person 對(duì)象中相應(yīng)屬性的值。
10. 用于數(shù)組和對(duì)象克隆的擴(kuò)展運(yùn)算符
JavaScript 中的展開運(yùn)算符 (...) 用于將可迭代對(duì)象(如數(shù)組或?qū)ο螅┑脑卣归_為單獨(dú)的元素。當(dāng)您想要克隆數(shù)組或?qū)ο髸r(shí),這尤其有用。
這是一個(gè)數(shù)組的示例:
let originalArray = [1, 2, 3];
let clonedArray = [...originalArray];
console.log(clonedArray); // Outputs: [1, 2, 3]
在此示例中,cloneArray 是一個(gè)新數(shù)組,其中包含originalArray 的所有元素。對(duì)originalArray 的任何更改都不會(huì)影響clonedArray,反之亦然。
擴(kuò)展運(yùn)算符也可用于克隆對(duì)象:
let originalObject = {
name: "John",
age: 30,
city: "New York"
};
let clonedObject = {...originalObject};
console.log(clonedObject); // Outputs: { name: 'John', age: 30, city: 'New York' }
在此示例中,clonedObject 是一個(gè)新對(duì)象,包含originalObject 的所有屬性。對(duì)originalObject 的任何更改都不會(huì)影響clonedObject,反之亦然。
擴(kuò)展運(yùn)算符還可以用于合并數(shù)組或?qū)ο螅?/span>
let array1 = [1, 2, 3];
let array2 = [4, 5, 6];
let mergedArray = [...array1, ...array2];
console.log(mergedArray); // Outputs: [1, 2, 3, 4, 5, 6]
let object1 = {a: 1, b: 2};
let object2 = {c: 3, d: 4};
let mergedObject = {...object1, ...object2};
console.log(mergedObject); // Outputs: { a: 1, b: 2, c: 3, d: 4 }
在這些示例中, mergedArray 和 mergedObject 分別包含 array1 和 array2 或 object1 和 object2 的元素或?qū)傩浴?/span>
第二部分
1. 標(biāo)記模板文字
標(biāo)記模板文字是 JavaScript 中模板文字的更高級(jí)形式。它們?cè)试S您使用函數(shù)解析模板文字。標(biāo)簽函數(shù)的第一個(gè)參數(shù)包含一個(gè)字符串值數(shù)組。其余參數(shù)與表達(dá)式相關(guān)。
這是一個(gè)簡(jiǎn)單的例子:
function tag(strings, ...values) {
console.log(strings);
console.log(values);
}
let name = "John";
let age = 30;
tag`Hello, my name is ${name} and I am ${age} years old.`;
在這個(gè)例子中,標(biāo)簽函數(shù)是我們的標(biāo)簽?zāi)0濉?span style="background-color:rgb(255,255,255);color:rgb(23,23,23);font-family:'-apple-system', BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';">當(dāng)我們使用模板文字調(diào)用此函數(shù)時(shí),它會(huì)被拆分為字符串和值的數(shù)組。strings 數(shù)組包含模板文字的所有字符串部分(“Hello,我的名字是”,“,我是”,“歲。”),values 數(shù)組包含計(jì)算的表達(dá)式(姓名,年齡)。
該代碼的輸出將是:
[ 'Hello, my name is ', ' and I am ', ' years old.' ]
[ 'John', 30 ]
當(dāng)您想要?jiǎng)?chuàng)建一個(gè)函數(shù)來生成特定類型的文本輸出,并具有如何將值插入字符串的復(fù)雜規(guī)則時(shí),此功能非常有用。
2. 唯一元素的集合對(duì)象
在 JavaScript 中,Set 對(duì)象是一個(gè)內(nèi)置對(duì)象,它存儲(chǔ)任何類型的唯一值,無論是原始值還是對(duì)象引用。Set中的一個(gè)值只能出現(xiàn)一次;它在套裝系列中是獨(dú)一無二的。
以下是如何使用 Set 的簡(jiǎn)單示例:
let mySet = new Set();
mySet.add(1); // Add a number
mySet.add('some text'); // Add a string
mySet.add('some text'); // Try to add the same string again
console.log(mySet);
在此示例中,我們創(chuàng)建一個(gè)新 Set 并向其中添加一個(gè)數(shù)字和一個(gè)字符串。當(dāng)我們嘗試再次添加相同的字符串時(shí),它不會(huì)被添加,因?yàn)樗呀?jīng)在集合中了。console.log 語句的輸出將是:
Set(2) { 1, 'some text' }
這表明該 Set 包含兩個(gè)元素:數(shù)字 1 和字符串“some text”。重復(fù)的字符串未添加到集合中。
您還可以從數(shù)組創(chuàng)建一個(gè) Set,它會(huì)自動(dòng)刪除任何重復(fù)的值:
let array = [1, 2, 3, 4, 4, 5, 5, 5];
let mySet = new Set(array);
console.log(mySet); // Output: Set(5) { 1, 2, 3, 4, 5 }
在此示例中,數(shù)組包含重復(fù)的數(shù)字。當(dāng)我們從此數(shù)組創(chuàng)建 Set 時(shí),它會(huì)自動(dòng)刪除重復(fù)項(xiàng),因此 Set 僅包含數(shù)組中的唯一數(shù)字。
3.使用Object.entries()和Object.fromEntries()
a) 對(duì)象.entries()
Object.entries() 是一種方法,它返回給定對(duì)象自己的可枚舉字符串鍵控屬性 [key, value] 對(duì)的數(shù)組,其順序與 for...in 循環(huán)提供的順序相同。唯一重要的區(qū)別是 for...in 循環(huán)也枚舉原型鏈中的屬性。
這是一個(gè)例子:
let obj = { foo: 'bar', baz: 42 };
console.log(Object.entries(obj)); // Output: [ ['foo', 'bar'], ['baz', 42] ]
在此示例中,Object.entries() 用于將對(duì)象轉(zhuǎn)換為鍵值對(duì)數(shù)組。
b) Object.fromEntries()
Object.fromEntries() 執(zhí)行 Object.entries() 的逆操作。它將鍵值對(duì)列表轉(zhuǎn)換為對(duì)象。
這是一個(gè)例子:
let entries = [ ['foo', 'bar'], ['baz', 42] ];
let obj = Object.fromEntries(entries);
console.log(obj); // Output: { foo: 'bar', baz: 42 }
在此示例中,Object.fromEntries() 用于將鍵值對(duì)數(shù)組轉(zhuǎn)換回對(duì)象。
4. 對(duì)象中的動(dòng)態(tài)屬性名稱
在 JavaScript 中,您可以使用計(jì)算屬性名稱在對(duì)象中創(chuàng)建動(dòng)態(tài)屬性名稱。這是通過將表達(dá)式括在方括號(hào) [] 中來完成的,該表達(dá)式將被計(jì)算為屬性名稱。當(dāng)您需要?jiǎng)討B(tài)創(chuàng)建屬性名稱時(shí),這非常有用。
這是一個(gè)例子:
let dynamicKey = 'name';
let obj = {
[dynamicKey]: 'John Doe'
};
console.log(obj); // Output: { name: 'John Doe' }
在本例中,變量dynamicKey用作對(duì)象obj的屬性名稱。DynamicKey 的值為“name”,因此該對(duì)象最終會(huì)得到一個(gè)名為“name”且值為“John Doe”的屬性。
您還可以使用此功能創(chuàng)建具有更復(fù)雜名稱的屬性:
let prefix = 'prop';
let obj = {
[`${prefix}_name`]: 'John Doe',
[`${prefix}_age`]: 30
};
console.log(obj); // Output: { prop_name: 'John Doe', prop_age: 30 }
在此示例中,屬性名稱是通過將前綴變量與“_name”和“_age”連接起來創(chuàng)建的。生成的對(duì)象具有屬性“prop_name”和“prop_age”。
5. 使用bind()進(jìn)行函數(shù)柯里化
函數(shù)柯里化是 JavaScript 中的一種技術(shù),其中具有多個(gè)參數(shù)的函數(shù)被轉(zhuǎn)換為一系列函數(shù),每個(gè)函數(shù)都具有單個(gè)參數(shù)。這可以使用bind()方法來實(shí)現(xiàn)。
這是一個(gè)例子:
function multiply(a, b) {
return a * b;
}
let multiplyByTwo = multiply.bind(this, 2);
console.log(multiplyByTwo(4)); // Output: 8
此示例中,乘法函數(shù)采用兩個(gè)參數(shù)。我們通過在乘法上調(diào)用bind()來創(chuàng)建一個(gè)新函數(shù)multiplyByTwo。bind() 的第一個(gè)參數(shù)是 this 值,我們不需要更改它,因此我們傳遞 this。第二個(gè)參數(shù)是要進(jìn)行乘法的第一個(gè)參數(shù),我們將其固定為 2。現(xiàn)在,multiplyByTwo 是一個(gè)函數(shù),它接受單個(gè)參數(shù),將其乘以 2,然后返回結(jié)果。
6. 使用 Array.from() 從類數(shù)組對(duì)象創(chuàng)建數(shù)組
在 JavaScript 中,Array.from() 是一種靜態(tài)方法,它從類似數(shù)組或可迭代的對(duì)象創(chuàng)建新的淺復(fù)制數(shù)組實(shí)例。
這是一個(gè)例子:
let arrayLike = { length: 2, 0: 'a', 1: 'b' };
let arr = Array.from(arrayLike);
console.log(arr); // Output: ['a', 'b']
在此示例中,arrayLike 是一個(gè)具有與數(shù)組類似的屬性和長(zhǎng)度的對(duì)象,但它不是數(shù)組。Array.from() 用于將這個(gè)類似數(shù)組的對(duì)象轉(zhuǎn)換為真正的數(shù)組。
當(dāng)您想從字符串創(chuàng)建數(shù)組時(shí),Array.from() 也很有用:
let str = 'hello';
let arr = Array.from(str);
console.log(arr); // Output: ['h', 'e', 'l', 'l', 'o']
在此示例中,Array.from() 用于將字符串轉(zhuǎn)換為單個(gè)字符的數(shù)組。
7. 可迭代對(duì)象的 for...of 循環(huán)
for...of 循環(huán)是一個(gè) JavaScript 語句,允許您迭代可迭代對(duì)象,例如數(shù)組、字符串、映射、集合等。它是傳統(tǒng) for 循環(huán)的更簡(jiǎn)潔、更易讀的替代方案。
下面是一些代碼示例
a) 您可以使用 for...of 循環(huán)來迭代數(shù)組:
let fruits = ['apple', 'banana', 'cherry'];
for (let fruit of fruits) {
console.log(fruit);
}
在此示例中,for...of 循環(huán)迭代fruits 數(shù)組中的每個(gè)元素并將其記錄到控制臺(tái)。輸出將是:
apple
banana
cherry
b) 您還可以使用 for...of 循環(huán)來迭代字符串:
let greeting = 'Hello';
for (let char of greeting) {
console.log(char);
}
在此示例中,for...of 循環(huán)迭代問候語字符串中的每個(gè)字符并將其記錄到控制臺(tái)。輸出將是:
H
e
l
l
o
請(qǐng)記住,for...of 循環(huán)適用于可迭代對(duì)象,這意味著它不適用于常規(guī)對(duì)象,除非它們可迭代。
8. 使用 Promise.all() 實(shí)現(xiàn)并發(fā) Promise
Promise.all() 是 JavaScript 中的一種方法,用于同時(shí)處理多個(gè) Promise。它采用可迭代的 Promise 作為輸入,并返回一個(gè) Promise,當(dāng)所有輸入的 Promise 都已解決時(shí),該 Promise 會(huì)被解析,或者會(huì)因第一個(gè) Promise 被拒絕的原因而被拒絕。
這是一個(gè)例子:
let promise1 = Promise.resolve(3);
let promise2 = 42;
let promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values); // Output: [3, 42, "foo"]
});
示例中,Promise.all() 用于同時(shí)處理三個(gè) Promise。Promise1 是一個(gè) Promise,解析值為 3,promise2 是一個(gè)非 Promise 值 42,promise3 是一個(gè) Promise,在 100 毫秒后解析值為 'foo'。
Promise.all([promise1,promise2,promise3]) 返回一個(gè)新的 Promise,當(dāng)所有輸入的 Promise 都已解析時(shí),該 Promise 才會(huì)解析。解析值是輸入 Promise 解析值的數(shù)組,其順序與輸入 Promise 相同。在本例中,解析的值為 [3, 42, "foo"]。
如果任何輸入的 Promise 被拒絕,則 Promise.all() 返回的 Promise 會(huì)立即拒絕,并給出第一個(gè)被拒絕的 Promise 的原因,而無需等待其他 Promise 解決或拒絕。
9. 函數(shù)參數(shù)的剩余參數(shù)
剩余參數(shù)語法允許我們將不定數(shù)量的參數(shù)表示為數(shù)組。當(dāng)編寫可以接受任意數(shù)量參數(shù)的函數(shù)時(shí),這尤其有用。
這是一個(gè)例子:
function sum(...args) {
let total = 0;
for(let arg of args) {
total += arg;
}
return total;
}
console.log(sum(1, 2, 3, 4)); // Output: 10
console.log(sum(1, 2, 3, 4, 5)); // Output: 15
使用剩余參數(shù)語法 (...args) 將其所有參數(shù)收集到一個(gè)數(shù)組中。然后,它使用 for...of 循環(huán)迭代數(shù)組并將所有數(shù)字相加。可以使用任意數(shù)量的參數(shù)調(diào)用該函數(shù),并且它將返回所有參數(shù)的總和。
10. 用于性能優(yōu)化的記憶
記憶化是一種編程技術(shù),主要用于通過存儲(chǔ)昂貴的函數(shù)調(diào)用的結(jié)果并在相同的輸入再次出現(xiàn)時(shí)重用它們來加速計(jì)算機(jī)程序。該技術(shù)用于一次又一次解決相同子問題的優(yōu)化問題。
以下示例展示了如何在 JavaScript 中使用記憶化來優(yōu)化計(jì)算斐波那契數(shù)的遞歸函數(shù):
let memo = {};
function fib(n) {
if (n <= 1) {
return n;
} else if (memo[n]) {
return memo[n];
} else {
memo[n] = fib(n - 1) + fib(n - 2);
return memo[n];
}
}
console.log(fib(10)); // Output: 55
console.log(fib(20)); // Output: 6765
在此示例中,fib 函數(shù)首先檢查給定輸入 n 的結(jié)果是否已存儲(chǔ)在 memo 對(duì)象中。如果是,該函數(shù)將返回存儲(chǔ)的結(jié)果,從而避免執(zhí)行昂貴的遞歸調(diào)用。如果結(jié)果尚未存儲(chǔ),該函數(shù)將使用斐波那契數(shù)列的遞歸公式計(jì)算結(jié)果,將其存儲(chǔ)在 memo 對(duì)象中,然后返回。這樣,該函數(shù)就可以避免一遍又一遍地重新計(jì)算相同的斐波那契數(shù),從而顯著提高了大輸入的性能。
第三部分
1. 使用 flat() 展平數(shù)組
JavaScript 中的 flat() 方法用于展平數(shù)組。它創(chuàng)建一個(gè)新數(shù)組,其中所有子數(shù)組元素遞歸地連接到指定深度。默認(rèn)情況下,深度為 1。
這是一個(gè)例子:
let arr = [1, 2, [3, 4, [5, 6]]];
console.log(arr.flat());
// Output: [1, 2, 3, 4, [5, 6]]
console.log(arr.flat(2));
// Output: [1, 2, 3, 4, 5, 6]
console.log(arr.flat(Infinity));
// Output: [1, 2, 3, 4, 5, 6]
在第一個(gè) console.log 中,我們?cè)诓粠魏螀?shù)的情況下調(diào)用 flat(),因此它的深度默認(rèn)為 1,并且只有第一層嵌套數(shù)組會(huì)被展平。
在第二個(gè) console.log 中,我們調(diào)用 flat(2),指定深度為 2,因此它會(huì)展平最多兩層嵌套數(shù)組。
在第三個(gè)console.log中,通過傳遞Infinity,它將展平所有嵌套數(shù)組,無論它們有多深。
2. 使用 ^ 交換值
JavaScript 中的插入符號(hào) (^) 用于按位異或運(yùn)算。但是,它也可以用于在兩個(gè)變量之間交換值,而無需使用臨時(shí)變量。它的工作原理如下:
let a = 5; // binary: 101
let b = 3; // binary: 011
a = a ^ b; // binary: 110, decimal: 6
b = a ^ b; // binary: 101, decimal: 5
a = a ^ b; // binary: 011, decimal: 3
經(jīng)過這些操作,a 變?yōu)?3,b 變?yōu)?5,有效地交換了它們的原始值。
解釋如下:
-
a = a ^ b 對(duì) a 和 b 進(jìn)行按位異或運(yùn)算,并將結(jié)果賦給 a。現(xiàn)在 a 保存了 a ^ b 的結(jié)果。
-
b = a ^ b 等價(jià)于 b = (a ^ b) ^ b。由于 XOR 是結(jié)合律,因此等價(jià)于 b = a ^ (b ^ b)。b ^ b 為 0,任何數(shù)字 XOR 0 就是該數(shù)字本身,因此 b 變?yōu)?a。
-
a = a ^ b 等價(jià)于 a = (a ^ b) ^ a。這相當(dāng)于a=b^(a^a)。a ^ a 為 0,因此 a 變?yōu)?b。
因此,a 和 b 的值在不使用臨時(shí)變量的情況下被交換。但是,應(yīng)謹(jǐn)慎使用此方法,因?yàn)槿绻?a 和 b 不是整數(shù)或者它們非常大,則可能會(huì)導(dǎo)致意外結(jié)果。
3. 用一元加法轉(zhuǎn)換為數(shù)字
在 JavaScript 中,一元加號(hào) (+) 運(yùn)算符可用于將字符串或布爾值轉(zhuǎn)換為數(shù)字。這是在 JavaScript 中執(zhí)行類型轉(zhuǎn)換的一種快速且簡(jiǎn)單的方法。它的工作原理如下:
let str = "123";
let num = +str; // num is now the number 123
console.log(typeof str); // "string"
console.log(typeof num); // "number"
let bool = true;
let numFromBool = +bool; // numFromBool is now the number 1
console.log(typeof bool); // "boolean"
console.log(typeof numFromBool); // "number"
在上面的示例中,一元加運(yùn)算符用于將字符串和布爾值轉(zhuǎn)換為數(shù)字。將字符串“123”轉(zhuǎn)換為數(shù)字123,將布爾值true轉(zhuǎn)換為數(shù)字1。使用typeof運(yùn)算符來確認(rèn)轉(zhuǎn)換前后變量的類型。
需要注意的是,如果字符串無法解析為數(shù)字,則結(jié)果將為 NaN(不是數(shù)字):
let str = "abc";
let num = +str; // num is now NaN
console.log(num); // NaN
在這種情況下,字符串“abc”無法解析為數(shù)字,因此一元加運(yùn)算的結(jié)果為NaN。
4. 使用 Object.assign() 合并對(duì)象
在 JavaScript 中,Object.assign() 是一種用于將所有可枚舉自身屬性的值從一個(gè)或多個(gè)源對(duì)象復(fù)制到目標(biāo)對(duì)象的方法。它將返回目標(biāo)對(duì)象。此方法通常用于合并對(duì)象(組合兩個(gè)或多個(gè)對(duì)象的屬性)。
這是一個(gè)例子:
let obj1 = { a: 1, b: 2 };
let obj2 = { b: 3, c: 4 };
let mergedObj = Object.assign({}, obj1, obj2);
console.log(mergedObj); // { a: 1, b: 3, c: 4 }
在此示例中,Object.assign() 采用三個(gè)參數(shù):空對(duì)象 {}、obj1 和 obj2。首先將 obj1 中的所有屬性復(fù)制到空對(duì)象。然后它將所有屬性從 obj2 復(fù)制到目標(biāo)對(duì)象。如果目標(biāo)對(duì)象上已存在某個(gè)屬性(如本例中的 b),則其值將被源對(duì)象 (obj2) 中的值覆蓋。
因此,生成的 mergedObj 包含 obj1 和 obj2 中的所有屬性,其中 obj2 中的值優(yōu)先。
5. 默認(rèn)值短路
在 JavaScript 中,您可以使用邏輯 OR (||) 運(yùn)算符為變量提供默認(rèn)值。這種技術(shù)稱為短路。如果 || 左側(cè)的值 運(yùn)算符為真(即,在布爾上下文中計(jì)算時(shí)被視為 true 的值),它將是結(jié)果。如果它是假的(即,在布爾上下文中計(jì)算時(shí)被視為假的值),則 || 右側(cè)的值 運(yùn)算符將是結(jié)果。
這是一個(gè)例子:
let name = user.name || 'Anonymous';
console.log(name); // If user.name exists and is not an empty string, null, undefined, 0, NaN, or false, it will be logged. Otherwise, 'Anonymous' will be logged.
在此示例中,如果定義了 user.name 并且不是空字符串、null、undefined、0、NaN 或 false,則 name 將被賦予 user.name 的值。如果 user.name 未定義或者是這些虛假值之一,則 name 將被分配字符串“Anonymous”。
這稱為短路,因?yàn)槿绻谝粋€(gè)操作數(shù)為真,JavaScript 甚至不會(huì)查看第二個(gè)操作數(shù) - 它會(huì)“短路”操作并返回第一個(gè)操作數(shù)。
6. 使用括號(hào)表示法動(dòng)態(tài)訪問對(duì)象屬性
在 JavaScript 中,您可以使用括號(hào)表示法動(dòng)態(tài)訪問對(duì)象屬性。當(dāng)您需要訪問名稱存儲(chǔ)在變量中的屬性時(shí),或者當(dāng)屬性名稱不是有效的標(biāo)識(shí)符(例如,它包含空格或特殊字符)時(shí),這特別有用。
這是一個(gè)例子:
let person = {
name: 'John',
age: 30,
'favorite color': 'blue'
};
let property = 'name';
console.log(person[property]); // Outputs: 'John'
property = 'age';
console.log(person[property]); // Outputs: 30
console.log(person['favorite color']); // Outputs: 'blue'
我們首先定義一個(gè)具有名稱、年齡和最喜歡的顏色屬性的對(duì)象 person。然后我們定義一個(gè)變量屬性并將其設(shè)置為“name”。當(dāng)我們使用 person[property] 時(shí),JavaScript 會(huì)查找屬性的值(即“name”),然后從 person 對(duì)象中檢索屬性“name”的值。我們可以將屬性的值更改為“age”并以相同的方式訪問age屬性。我們還可以直接使用括號(hào)中的字符串來訪問名稱不是有效標(biāo)識(shí)符的屬性,例如“最喜歡的顏色”。
7. HTML 片段的模板字符串
模板字符串,也稱為模板文字,是 JavaScript 中的一項(xiàng)功能,允許您創(chuàng)建帶有嵌入表達(dá)式的字符串。它們?cè)趧?chuàng)建 HTML 片段時(shí)特別有用,因?yàn)樗鼈冊(cè)试S您輕松地將變量和表達(dá)式插入到 HTML 中。
這是一個(gè)例子:
let name = 'John';
let age = 30;
let html = `
<div>
<h1>${name}</h1>
<p>Age: ${age}</p>
</div>`
;
console.log(html);
在這個(gè)例子中,我們首先定義兩個(gè)變量name和age。然后我們定義一個(gè)包含 HTML 片段的模板字符串 html。模板字符串用反引號(hào)括起來,變量名稱和年齡使用 ${...} 語法插入到 HTML 中。當(dāng)我們將 html 記錄到控制臺(tái)時(shí),它會(huì)輸出以下 HTML:
<div>
<h1>John</h1>
<p>Age: 30</p>
</div>
TML 時(shí)(例如,根據(jù)服務(wù)器數(shù)據(jù)構(gòu)建網(wǎng)頁時(shí)),此功能非常有用。
8. 使用 Array.includes() 進(jìn)行存在檢查
JavaScript 中的 Array.includes() 方法用于確定數(shù)組的條目中是否包含某個(gè)值。它根據(jù)需要返回 true 或 false。
這是一個(gè)例子:
let array = [1, 2, 3, 4, 5];
console.log(array.includes(2)); // Outputs: true
console.log(array.includes(6)); // Outputs: false
在此示例中,我們有一個(gè)從 1 到 5 的數(shù)字?jǐn)?shù)組。然后,我們使用includes() 方法檢查數(shù)字 2 是否在數(shù)組中(確實(shí)如此),因此返回 true。我們還檢查數(shù)字 6 是否在數(shù)組中,但事實(shí)并非如此,因此返回 false。
9. 防止對(duì)象修改
在 JavaScript 中,有多種方法可以防止對(duì)象被修改。以下是三種方法:
1. Object.preventExtensions(): 該方法阻止向?qū)ο筇砑有聦傩浴?/span>
let obj = { a: 1 };
Object.preventExtensions(obj);
obj.b = 2; // Attempt to add new property
console.log(obj.b); // Outputs: undefined
2. Object.seal(): 該方法防止添加新屬性和刪除現(xiàn)有屬性。但是,它允許修改現(xiàn)有屬性。
let obj = { a: 1 };
Object.seal(obj);
obj.b = 2; // Attempt to add new property
delete obj.a; // Attempt to delete existing property
console.log(obj.b); // Outputs: undefined
console.log(obj.a); // Outputs: 1
3. Object.freeze(): 該方法防止添加新屬性、刪除現(xiàn)有屬性,并防止更改現(xiàn)有屬性的可枚舉性、可配置性或可寫性。本質(zhì)上,它使對(duì)象變?yōu)橹蛔x。
let obj = { a: 1 };
Object.freeze(obj);
obj.b = 2; // Attempt to add new property
obj.a = 3; // Attempt to modify existing property
console.log(obj.b); // Outputs: undefined
console.log(obj.a); // Outputs: 1
在所有這些示例中,嘗試以不允許的方式修改對(duì)象不會(huì)引發(fā)錯(cuò)誤,它根本不會(huì)產(chǎn)生任何效果。然而,在嚴(yán)格模式下('use strict';),這些操作將拋出 TypeError。
10. Function.prototype.bind() 的強(qiáng)大功能
JavaScript 中的 Function.prototype.bind() 方法是一個(gè)強(qiáng)大的工具,它允許您在函數(shù)的上下文中設(shè)置 this 值,并使用特定的 this 值和初始參數(shù)創(chuàng)建一個(gè)新函數(shù)。
這是一個(gè)例子:
let person = {
firstName: "John",
lastName: "Doe",
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
let logName = function(location, country) {
console.log(this.fullName() + " from " + location + ", " + country);
}
// Create a new function with 'this' bound to 'person'
let logPersonName = logName.bind(person);
// Call the new function
logPersonName("New York", "USA"); // Outputs: "John Doe from New York, USA"
有 fullName 方法的 person 對(duì)象。我們還有一個(gè) logName 函數(shù),用于記錄一條消息,其中包括該人的全名和位置。
然后我們使用bind()創(chuàng)建一個(gè)新函數(shù)logPersonName,它被綁定到person對(duì)象。當(dāng)我們調(diào)用 logPersonName 時(shí),它可以訪問 person 對(duì)象的 fullName 方法,因?yàn)樗辉O(shè)置為 person。
當(dāng)您想要從對(duì)象借用方法,或者想要擁有一個(gè)可以與不同 this 值一起使用的函數(shù)時(shí),這特別有用。
原文鏈接:https://dev.to/sayuj/10-javascript-tricky-hacks-part-1-52dl文章轉(zhuǎn)載于:薩尤吉·塞加爾
最后
這些技巧希望對(duì)小伙伴們?nèi)粘i_發(fā)幫忙有所幫助~
關(guān)注我,一起攜手進(jìn)階
歡迎關(guān)注前端早茶,與廣東靚仔攜手共同進(jìn)階~
