JavaScript 已經存在了相當長的一段時間(大約 26 年),在這段時間裡,該語言已經有了很大的發展。
這種演變大多是有目的,特別是在最新的迭代中,開發者社區已經設法影響了其中的一些變化,使 JavaScript 成為一種非常靈活和好用的語言。
然而,在這些年的演變過程中,可以說仍有一些殘餘的過時功能,這些功能還沒有被拿掉,但確實沒有任何用途(或者更確切地說,在原本的用途方面效率不高)。
以下三個 JavaScript 特性,即使它們在運行時仍然可用,但你應避免去使用它們。
void 操作符
你可能在某一時刻看到過 void 操作符的存在。在過去,每當你點擊一個鏈接,而這個鏈接將觸發一個 JavaScript 函數時,你會添加 href=”javascript:void(0)” 以確保默認行為(即頁面跳轉)不會觸發。
但這究竟是什麼意思呢?
void 操作符是一種在 JavaScript 中生成 undefined 值的方法。沒錯,它能接受任何表達式,並且每次都返回 undefined。
我知道你在想什麼:為什麼不直接使用已經存在的 undefined 關鍵字呢?嗯,正如你看到的,在 ECMAScript 5 之前,undefined 關鍵字並不是一個常量值。是的,你可以定義 undefined,如果你再想一想,這不就是我們曾經想做的事情嗎?
當然,這樣做是沒有意義的,這就是為什麼最終它被重新定義為一個常量值,且不可更改。然而,因為早前你是可以改變它的,所以 void 會允許你訪問 undefined,即使這個常量不再起作用。
事實上,一個很好的方法是通過創建你自己的 IIFEs 來重新定義只屬於你的命名空間的常量,避免與第三方庫的任何問題,其中一個參數確實是 undefined,像這樣:
(function (window, undefined) {
// 你這裡的邏輯,可以把 undefined 當作預期
})(window, void(0))
當然,今天的 void 操作符仍然有它的用途,但它是非必要的。例如,在現在的 JavaScript 中,最好的用例是幫助避免單行箭頭函數的非預期返回。
你可能知道,一個單行箭頭函數將返回該行的結果,即使你沒有顯式使用 return 語句。
const double = x => x * 2; // 返回 X 乘以 2 的結果
const callAfunction = () => myFunction(); // 返回 myFunction 所返回的結果,即使我不想這樣做
這兩個函數都會返回一些東西。顯然,對於 double 函數來說,你希望它返回一個值,但另一個可能不是,你可能只是想用它調用另一個函數(即 myFunction()),但你對其結果值不感興趣。因此你可以這樣做:
const callAfunction = () => void myFunction(); // 返回 myFunction 所返回的結果,即使我不想這樣做
而這將立即覆蓋返回值,並確保你的調用值返回 undefined。
對我來說,這種行為提供了一個最小的好處,使 void 在這個時代的 JavaScript 中毫無用處。
我建議你避免使用它,讓它保持一個廢棄的狀態。
With 語句
這個是 JavaScript 自帶的結構之一,但你可能從未聽說過它,因為它並沒有被真正推廣。事實上,即使是 MDN 官方文檔也不鼓勵你使用它,因為它可能導致非常混亂的代碼。
with 語句允許擴展給定語句的作用域鏈。換句話說,它允許你將一個表達式注入到給定語句的作用域,理想情況下,可以簡化所述語句。
下面是一個示例,這樣你就會明白我想說什麼:
function greet(user) {
with(user) {
console.log(`Hello there ${name}, how are you and your ${kids.length} kids today?`)
}
}
greet({
name: "Fernando",
kids: ["Brian", "Andrew"]
})
注意 greet 函數中 with 語句的魔力。這是一個基本的示例,表明了表達式的 happy path。但是,讓我們看另一個情況,事情變得有點複雜:
function greet(user, message) {
with(user) {
console.log(`Hey ${name}, here is a message for you: ${message}`)
}
}
// happy path
greet({
name: "Fernando"
}, "You got 2 emails")
// kinda sad path
greet({
name: "Fernando",
message: "Unrelated message"
}, "you got email")
你認為這種執行方式的輸出結果會是什麼?
Hey Fernando, here is a message for you: You got 2 emails
Hey Fernando, here is a message for you: Unrelated message
由於你在傳入的對象中添加了一個同名屬性,你無意間覆蓋了函數的第二個參數。我想補充的是,這完全是正常的,因為人們永遠不會期望兩者處於同一個作用域級別。然而,多虧了 with,我們把這兩個作用域都混在了一起,但結果並不理想。
這都是為了說明要避免使用 with,雖然它可能看起來是節省代碼量的好方法,但你的代碼很快會變得非常複雜,這會對別人(或兩周後的你)去理解你的代碼造成心智負擔。
Labels 標籤
如果你學習編程足夠早(像我一樣),你就經歷過其他語言(如 C 語言)中對 go-to 語句的憎恨。那太糟糕了,那是一個在當年很有意義的功能,但最終隨着同一問題的更新的解決方案,這種功能變得如此過時和糟糕,以至於變成了一種反模式。
因此 JavaScript 不得不去實現它。
Go-to 語句是一種方式,讓你在代碼的任何地方放置一個標記,然後從其他地方跳到那裡。你可以跳到一個函數的中間,或者跳到一個 IF 語句裡面,它就像一個神奇的入口,可以跳到你代碼中的任何地方。我相信你可以看到這可能是一個問題,它的力量太大,靈活性太強,我們當然會錯過使用它的機會。
然而,JavaScript 實現了一個類似的,但不完全相同的結構:labels 標籤。
JavaScript 中的標籤語句是一個你放在語句前的標記,然後你可以 break 或 continue。請注意,沒有更多的 go-to,這是一個很好的優勢。
你可以這樣寫:
label1: {
console.log(1)
let condition = true
if(condition) {
break label1
}
console.log(2)
}
console.log("end")
而輸出結果將是:
1
end
當然,這個例子看起來非常像一個 if..else 語句。而且你完全可以說,它看起來並不那麼糟糕。然而,你打破了代碼的正常流程,跳過了語句。如果你就是希望如此,那麼使用 if..else 帶來的心智負擔會小很多。
當我們把標籤與循環和 continue 語句的相互作用包括在內時,labels 標籤的問題就變得更明顯了。
let i, j;
loop1:
for(i = 0; i < 10; i++) {
loop2:
for(j = 0; j < 10; j++) {
if(j == 3 && i == 2) {
continue loop2;
}
console.log({i, j})
if(j % 2 == 0) {
continue loop1;
}
}
}
你能在頭腦中運行上述代碼並告訴我具體的輸出結果嗎?這並非不可能,但要花點時間。上面的腳本會打印:
{ i: 0, j: 0 }
{ i: 1, j: 0 }
{ i: 2, j: 0 }
{ i: 3, j: 0 }
{ i: 4, j: 0 }
{ i: 5, j: 0 }
{ i: 6, j: 0 }
{ i: 7, j: 0 }
{ i: 8, j: 0 }
{ i: 9, j: 0 }
從本質上講,第二個 if 在 0 的時候評估為 true,所以 continue 語句影響了外循環,導致它移動到下一個索引值,這反過來又重置了內循環,導致它回到 0,同樣的事情不斷發生,重複了 10 次。第一個 if,如果你想知道的話,從來沒有評估為 true,因為 j 從來沒有達到 0 以外的任何值。
labels 標籤可能是棘手的小傢伙,即使你能正確地使用它們,並且從解釋器的角度來看,它們也很有意義,但你應該為人類而不是為機器寫代碼。別人會來讀它(甚至是三周後的你),當他們看到標籤的那一刻,他們會永遠恨你。當然,他們會花更多的時間來理解你代碼的基本流程,但這在目前是次要問題。
本文總結
請不要誤會,我喜歡 JavaScript 這門語言,自從 18 年前我開始從事網絡開發工作以來,我一直在以不同的方式與它互動。我見證了這門語言的發展,就像一壇好酒,隨着時間的推移而變得更好。然而,如果我說這門語言中沒有一些我不喜歡的黑暗角落,那是假的。而這三個功能恰好表明了這一點。
好消息是,在我多年的經驗中,我還沒有看到 with 或標籤(Label)被實施並部署到生產中。這並不是說沒有這樣的情況,只是我從未見過,這讓我覺得沒有多少代碼審查會讓它們通過。
你有沒有看到這些功能在現代 JavaScript 中被使用?
原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/230023.html