前言
在Javascript通常我們在遍歷一個字符串的時候通常使用的方式是
var str ="abcdefg";
for(let i=0;i<str.length;i++){}
但在最近的學習中,有人建議我最好應該是下面這樣執行。
var str ="abcdefg";
for(let i=0,len= str.length;i<len;i++){}
我有點疑惑,這用一個變量存儲字符串的長度不是多此一舉嗎?為什么還建議我使用以下代碼呢?抱著懷疑的態度我決定進行效率測試。下面是測試代碼。
function test1() {let time1 = Date.now();for (let i = 0; i < str.length; i++) { }let time2 = Date.now();return time2 - time1;
}
function test2() {let time1 = Date.now();for (let i = 0,len = str.length; i < len; i++) { }let time2 = Date.now();return time2 - time1;
}
console.log(test1());
console.log(test2());
當測試集長度為10000長度以下基本沒有區別,但是當長度來到十萬級別百萬的時候,時間消耗確實是有差距的,但都是毫秒級差距。但是雖然效率相差不大,但是到底是什么原因導致的時間上的差距呢?這里就得要先介紹一下JS的基本類了。
JS的原始(基本)數據類型
- 字符串(String) :任何文本信息,用單引號
' '
或雙引號" "
包圍。 - 數字(Number) :整數或浮點數,包括 Infinity 和 NaN。
- 布爾值(Boolean) :只有兩個值,
true
和false
。 - 未定義(Undefined) :表示變量已被聲明但沒有賦值,或被直接初始化為
undefined
。 - Null:表示一個特意設置為空的對象引用,只有一個值
null
。 - Symbol(ES6起):一種唯一且不可變的數據類型,常用于對象的鍵,以避免鍵名沖突。
- Bigint (ECMAScript 2020 (ES2020)):能夠安全地存儲極大或極小的整數值
原始數據類型(也稱作基本數據類型或者primitive data types)在JavaScript中是不具備自己的方法和屬性的。
問題來了,字符串String
是原始數據類型,為什么卻擁有.length屬性呢?而且不只是.length屬性,字符串類型還擁有賊多的方法。。。相信已經有小伙伴疑惑了?這不是自相矛盾嗎?
但是事實確是兩者都是正確的,原始數據類型確實是沒有屬性和方法,JS在對原始數據進行屬性和方法的相關操作的時候會進行包裝,下面引出我們真正的豬腳—包裝類
包裝類
原始值(字符串、數字、布爾值和Symbol等)在JavaScript中通常不具備屬性和方法。然而,包裝類(String、Number、Boolean、Symbol對象)的引入,讓這些基本類型在特定情境下也能穿上“對象”的外衣,短暫擁有方法和屬性。
相信大家都使用過類型強轉類似String()
,Number()
等,這種就是將一個基本類型,先將一個基本類型包裝成一個對象,在返回一個原始數據類型后進行銷毀。如下面這行代碼:
var str ="1231213123123";
console.log(str.length);
這兩行代碼JS將會這樣執行:
- 臨時創建一個String對象,該對象包裝了原始的字符串值
- 然后通過這個對象獲取長度
- 之后這個臨時對象會被銷毀
難道每次使用方法和屬性都要進行對象的創建與銷毀嗎?答案是:是的,每次使用都要進行創建與銷毀。
這下知道為什么在循環中最好先使用一個變量存儲字符串的長度,而不是每次循環都直接使用字符串.length屬性進行判斷了吧。因為每次循環都會進行包裝類的創建和銷毀,雖然在數據集小的情況下效率影響不大但好歹是有點影響不是.
結語
總而言之,JavaScript通過對象、包裝類以及對未定義屬性的處理,展現了其設計哲學的深度與廣度。它既是一門靈活多變的語言,也是開發者手中的利器,允許我們在編碼的旅途中,以最少的約束,創造無限可能。理解這些機制,不僅能夠提升我們的編碼技巧,更能在深層次上領悟JavaScript的設計美學,讓我們的代碼更加優雅、高效。在這條探索之路上,讓我們繼續前行,揭開更多JavaScript的神秘面紗。