2023.05.04 - 2023.05.06 更新前端面試問題總結(12道題)
獲取更多面試相關問題可以訪問
github 地址: https://github.com/pro-collection/interview-question/issues gitee 地址: https://gitee.com/yanleweb/interview-question/issues
目錄:
-
初級開發者相關問題【共計 1 道題】
- 340.值類型和引用類型 的區別?【熱度: 1,625】【JavaScript】
-
中級開發者相關問題【共計 7 道題】
- 329.常見圖片懶加載方式有哪些?【熱度: 1,001】【web應用場景】
- 330.cookie 構成部分有哪些【熱度: 598】【瀏覽器、web應用場景】
- 331.掃碼登錄實現方式【熱度: 734】【web應用場景】
- 332.DNS 協議了解多少【熱度: 712】【網絡、web應用場景】【出題公司: 騰訊】
- 335.HTTP 304 狀態碼表達的請求過程是什么【熱度: 459】【網絡】【出題公司: 阿里巴巴】
- 336.[React] 事件綁定原理【熱度: 1,097】【web框架】【出題公司: 小米】
- 337.函數式編程了解多少?【熱度: 1,789】【web應用場景】【出題公司: 百度】
-
高級開發者相關問題【共計 4 道題】
- 328.script 預加載方式有哪些, 這些加載方式有何區別?【熱度: 420】【瀏覽器、web應用場景】
- 333.TCP/IP 如何保證數據包傳輸的有序可靠【熱度: 336】【網絡】【出題公司: 騰訊】
- 338.JavaScript 對象的底層數據結構是什么【熱度: 517】【JavaScript】
- 339.JavaScript 中的變量在內存中的具體存儲形式是什么【熱度: 183】【JavaScript】
初級開發者相關問題【共計 1 道題】
340.值類型和引用類型 的區別?【熱度: 1,625】【JavaScript】
關鍵詞:值類型和引用類型區別
在JavaScript中,值類型和引用類型是兩種不同的數據類型,它們之間的區別在于數據存儲和傳遞的方式不同。
值類型(也稱為“原始類型”)包括 undefined、null、boolean、number和string。這些數據類型的值是可以直接存儲在變量中的,這意味著如果我們將一個值類型的變量賦給另一個變量時,實際上是將值復制到新變量的內存空間中。在JavaScript中,值類型的變量是直接存儲在棧中的。因此,值類型的變量永遠不會出現“引用計數”錯誤,因為每個變量都可以被簡單地復制和賦值。
引用類型包括對象、數組和函數等復雜數據類型。和值類型不同,引用類型的值是存儲在堆中的,棧中存儲的是變量的引用地址。當我們把一個引用類型的變量賦給另一個變量時,實際上是將變量的引用地址復制到了新變量的內存空間中。這意味著這兩個變量引用同一個對象。如果我們修改一個變量,那么另一個變量也會被修改;因為它們引用同一個對象。如果我們在堆中創建多個對象,則會有多個變量引用它們。這一點需要非常小心,因為它可以導致一些問題,如“引用計數”錯誤。
總之,JavaScript中的值類型和引用類型之間的區別在于它們如何存儲和傳遞。理解這兩種不同的數據類型的工作原理,可以幫助我們更好地理解JavaScript的內部工作原理,從而更好地編寫代碼。
舉例說明
下面是一個簡單的例子,來說明值類型和引用類型在操作時的區別:
// 值類型
var x = 1;
var y = x;
x = 2;
console.log(x); // 輸出2
console.log(y); // 輸出1
// 引用類型
var a = {name: 'Tom', age: 20};
var b = a;
a.age = 30;
console.log(a.age); // 輸出30
console.log(b.age); // 輸出30,原因是 a 和 b 指向同一個對象
在這個例子中,我們首先創建一個值類型變量 x,并將其值設置為 1。接著我們將 x 的值賦給 y 變量。然后我們將 x 的值修改為 2,這不會影響變量 y,因為 x 和 y 之間的賦值使用的是值復制。這是值類型的典型特性。
接下來,我們創建了一個包含 name 和 age 屬性的對象 a,并將其賦給變量 b。然后我們修改了 a 的 age 屬性的值。此時,由于 a 和 b 引用同一個對象,因此 b.age 的值也隨之改變,這才是引用類型的典型特性。
在代碼中我們看到,值類型的變量在賦值時是通過復制整個值本身的副本,在內存中分配了新的空間來存儲。而引用類型的變量賦值時是將指針復制到新變量中,用來指向堆(heap)中存儲對象的內存空間。
中級開發者相關問題【共計 7 道題】
329.常見圖片懶加載方式有哪些?【熱度: 1,001】【web應用場景】
關鍵詞:圖片懶加載、Intersection Observer API
圖片懶加載可以延遲圖片的加載,只有當圖片即將進入視口范圍時才進行加載。這可以大大減輕頁面的加載時間,并降低帶寬消耗,提高了用戶的體驗。以下是一些常見的實現方法:
- Intersection Observer API
Intersection Observer API
是一種用于異步檢查文檔中元素與視口疊加程度的API??梢詫⑵溆糜跈z測圖片是否已經進入視口,并根據需要進行相應的處理。
let observer = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
const lazyImage = entry.target;
lazyImage.src = lazyImage.dataset.src;
observer.unobserve(lazyImage);
}
});
});
const lazyImages = [...document.querySelectorAll(".lazy")];
lazyImages.forEach(function (image) {
observer.observe(image);
});
- 自定義監聽器
或者,可以通過自定義監聽器來實現懶加載。其中,應該避免在滾動事件處理程序中頻繁進行圖片加載,因為這可能會影響性能。相反,使用自定義監聽器只會在滾動停止時進行圖片加載。
function lazyLoad() {
const images = document.querySelectorAll(".lazy");
const scrollTop = window.pageYOffset;
images.forEach((img) => {
if (img.offsetTop < window.innerHeight + scrollTop) {
img.src = img.dataset.src;
img.classList.remove("lazy");
}
});
}
let lazyLoadThrottleTimeout;
document.addEventListener("scroll", function () {
if (lazyLoadThrottleTimeout) {
clearTimeout(lazyLoadThrottleTimeout);
}
lazyLoadThrottleTimeout = setTimeout(lazyLoad, 20);
});
在這個例子中,我們使用了 setTimeout()
函數來延遲圖片的加載,以避免在滾動事件的頻繁觸發中對性能的影響。
無論使用哪種方法,都需要為需要懶加載的圖片設置占位符,并將未加載的圖片路徑保存在 data
屬性中,以便在需要時進行加載。這些占位符可以是簡單的 div 或樣式類,用于預留圖片的空間,避免頁面布局的混亂。
<!-- 占位符示例 -->
<div class="lazy-placeholder" style="background-color: #ddd;height: 500px;"></div>
<!-- 圖片示例 -->
<img class="lazy" data-src="path/to/image.jpg" alt="預覽圖" />
總體來說,圖片懶加載是一種這很簡單,但非常實用的優化技術,能夠顯著提高網頁的性能和用戶體驗。
330.cookie 構成部分有哪些【熱度: 598】【瀏覽器、web應用場景】
關鍵詞:cookie 構成部分、cookie 作用路徑、cookie 作用域
在 HTTP 協議中,cookie 是一種包含在請求和響應報文頭中的數據,用于在客戶端存儲和讀取信息。cookie 是由服務器發送的,客戶端可以使用瀏覽器 API 將 cookie 存儲在本地進行后續使用。
一個 cookie 通常由以下幾個部分組成:
- 名稱:cookie 的名稱(鍵),通常是一個字符串。
- 值:cookie 的值,通常也是一個字符串。
- 失效時間:cookie 失效的時間,過期時間通常存儲在一個
expires
屬性中,以便瀏覽器自動清除失效的 cookie。 - 作用路徑:cookie 的作用路徑,只有在指定路徑下的請求才會攜帶該 cookie。
- 作用域:cookie 的作用域,指定了該 cookie 綁定的域名,可以使用
domain
屬性來設置。
例如,以下是一個設置了名稱為 “user”、值為 “john”、失效時間為 2022 年 1 月 1 日,并且作用于全站的 cookie:
Set-Cookie: user=john; expires=Sat, 01 Jan 2022 00:00:00 GMT; path=/; domain=example.com
其中,Set-Cookie
是響應報文頭,用于設置 cookie。在該響應報文中,將 cookie 數據設置為 “user=john”,失效時間為 “2022年1月1日”,作用路徑為全站,作用域為 “example.com” 的域名。這個 cookie 就會被存儲在客戶端,以便在以后的請求中發送給服務器。
331.掃碼登錄實現方式【熱度: 734】【web應用場景】
關鍵詞:掃碼登錄
掃碼登錄的實現原理核心是基于一個中轉站,該中轉站通常由應用提供商提供,用于維護手機和PC之間的會話狀態。
整個掃碼登錄的流程如下:
-
用戶在PC端訪問應用,并選擇使用掃碼登錄方式。此時,應用生成一個隨機的認證碼,并將該認證碼通過二維碼的形式顯示在PC端的頁面上。
-
用戶打開手機上的應用,并選擇使用掃碼登錄方式。此時,應用會打開手機端的相機,用戶可以對著PC端的二維碼進行掃描。
-
一旦用戶掃描了二維碼,手機上的應用會向應用提供商的中轉站發送一個請求,請求包含之前生成的隨機認證碼和手機端的一個會話ID。
-
中轉站驗證認證碼和會話ID是否匹配,如果匹配成功,則該中轉站將用戶的身份信息發送給應用,并創建一個PC端和手機端之間的會話狀態。
-
應用使用收到的身份信息對用戶進行認證,并創建一個與該用戶關聯的會話狀態。同時,應用返回一個通過認證的響應給中轉站。
-
中轉站將該響應返回給手機端的應用,并攜帶一個用于表示該會話的令牌,此時手機和PC之間的認證流程就完成了。
-
當用戶在PC端進行其他操作時,應用將會話令牌附加在請求中,并通過中轉站向手機端的應用發起請求。手機端的應用使用會話令牌(也就是之前生成的令牌)來識別并驗證會話狀態,從而允許用戶在PC端進行需要登錄的操作。
332.DNS 協議了解多少【熱度: 712】【網絡、web應用場景】【出題公司: 騰訊】
關鍵詞:DNS協議、DNS加速
DNS 基本概念
DNS(Domain Name System,域名系統)是因特網上用于將主機名轉換為 IP 地址的協議。它是一個分布式數據庫系統,通過將主機名映射到 IP 地址來實現主機名解析,并使用戶能夠通過更容易識別的主機名來訪問互聯網上的資源。
在使用 DNS 協議進行主機名解析時,系統首先查詢本地 DNS 緩存。如果緩存中不存在結果,系統將向本地 DNS 服務器發出請求,并逐級向上查找,直到找到權威 DNS 服務器并獲得解析結果。在域名解析的過程中,DNS 協議采用了分級命名空間的結構,不同的域名可以通過點分隔符分為多個級別,例如 www.example.com
可以分為三個級別:www
、example
和 com
。
除了將域名映射到 IP 地址之外,DNS 協議還支持多種其他功能:
- 逆向映射:將 IP 地址解析為域名。
- 郵件服務器設置:支持郵件服務器的自動發現和設置。
- 負載均衡:DNS 還可以實現簡單的負載均衡,通過將相同 IP 地址的主機名映射到不同的 IP 地址來分散負載。
- 安全:DNSSEC(DNS Security Extensions,DNS 安全擴展)可以提供對域名解析的認證和完整性。
如何加快 DNS 的解析?
有以下幾種方法可以加快 DNS 的解析:
-
使用高速 DNS 服務器:默認情況下,網絡服務提供商(ISP)為其用戶提供 DNS 服務器。但是,這些服務器不一定是最快的,有時會出現瓶頸。如果您想加快 DNS 解析,請嘗試使用其他高速 DNS 服務器,例如 Google 的公共 DNS 服務器或 OpenDNS。
-
緩存 DNS 記錄:在本地計算機上緩存 DNS 記錄可以大大加快應用程序的響應。當您訪問特定的網站時,計算機會自動緩存該網站的 DNS 記錄。如果您再次訪問該網站,則計算機將使用緩存的 DNS 記錄。
-
減少 DNS 查找:當您訪問一個網站時,您的計算機將會查找該域名的 IP 地址。如果網站有很多域名,則查找過程可能會變得非常緩慢。因此,盡可能使用較少的域名可以減少 DNS 查找的數量,并提高響應速度。
-
使用 CDN:CDN(內容分發網絡)是一種將內容存儲在全球多個位置的系統。這些位置通常都有專用的 DNS 服務器,可以大大加快站點的加載速度。
-
使用 DNS 緩存工具:一些輔助工具可以幫助您優化與 DNS 相關的設置,例如免費的 DNS Jumper 軟件和 Namebench 工具,它們可以測試您的 DNS 響應時間并為您推薦最佳配置。
通過使用高速 DNS 服務器、緩存 DNS 記錄、減少 DNS 查找、使用 CDN 和 DNS 緩存工具等方法,可以顯著提高 DNS 解析速度,從而加快應用程序響應時間。
335.HTTP 304 狀態碼表達的請求過程是什么【熱度: 459】【網絡】【出題公司: 阿里巴巴】
關鍵詞:304狀態碼、304請求過程、304過程、304請求
HTTP 304 狀態碼是表示所請求的資源未修改,可以直接使用客戶端緩存的版本。當客戶端發送 GET 請求時,服務器會檢查該資源的 ETag(實體標簽)或 Last-Modified(最后修改時間)等信息,與客戶端緩存中的相應信息進行比較。如果這些信息相同,則表示資源未發生更改,服務器返回 304 狀態碼,告訴客戶端直接使用本地緩存的資源即可,無需重新下載,這樣可以大大節省網絡帶寬和服務器資源消耗。
下面是 HTTP 304 的具體過程:
-
客戶端首先給服務器發送一個請求,該請求包含了一個 If-Modified-Since 或者 If-None-Match 字段,用來在服務器端判斷訪問的資源是否已經被修改過。
-
如果服務器端檢查發現訪問的資源沒有發生改變,服務器就不會發送資源內容,而是返回 304 的狀態碼給客戶端。
-
客戶端接收到 304 的狀態碼后,會從本地緩存中加載相應的資源。
-
如果服務器端發現訪問的資源已經發生過改變,服務器會發送新的資源內容給客戶端,并且返回 200 的狀態碼。
需要注意的是,客戶端緩存中的資源不一定完全等同于服務器端的資源,可能由于緩存失效等原因導致客戶端緩存中的資源與服務器端不完全一致,因此在實際應用中,需要謹慎使用 304 緩存機制,尤其對于那些變化頻繁的資源,建議設置較短的緩存時間,以避免出現緩存失效等問題。
336.[React] 事件綁定原理【熱度: 1,097】【web框架】【出題公司: 小米】
關鍵詞:react事件綁定、react合成事件、react事件監聽
綁定原理與過程
在 React 中,事件綁定不同于傳統的直接在 HTML 元素添加事件監聽器的方式。React 的事件綁定是建立在自定義組件上的,因此需要對 React 組件的生命周期進行理解。
React 事件綁定的原理可以概括為三個步驟:
- 創建 React 元素
在 React 中,事件的綁定是通過在 JSX 中創建元素時給元素添加一個事件屬性實現的。例如:
<button onClick={this.handleClick}>點我</button>
這里使用 onClick 屬性將組件的 handleClick 方法傳遞給一個按鈕組件,這個按鈕組件在點擊之后會調用 handleClick 方法。
- 掛載事件處理函數
當 React 元素插入文檔中之后,React 會在元素宿主節點上掛載事件處理函數。這個過程是在 React 元素生成之后、組件掛載之前完成的。React 在執行組件掛載生命周期函數之前,會將所有元素上聲明的事件處理函數統一掛載到 DOM 上。
- 移除事件處理函數
當 React 元素被移除文檔時,React 會自動移除對應的事件處理函數。這個過程是在組件卸載之后、元素從 DOM 中移除之前執行的。
React 的事件綁定表現為組件的方法,所以在事件處理函數中,可以通過 this 關鍵字來訪問組件的狀態和屬性。
需要注意的是,React 組件中不能使用原生事件綁定方式,比如使用 element.addEventListener('click', function(){})
,因為這樣做會導致 React 無法正確地跟蹤組件狀態的變化,從而可能導致一些潛在問題。
React 組件中為何不能使用原生事件綁定方式
React 組件中不能使用原生事件綁定方式是因為,React 使用的是 Virtual DOM 技術,而不是直接操作 DOM。React 的 Virtual DOM 能夠自動監測組件(即數據)狀態的變化和更新,從而根據更新后的狀態重新渲染視圖,并在必要的時候更新真實 DOM。
如果使用原生事件綁定方式,比如使用 element.addEventListener('click', function(){})
,那么這些綁定的事件處理函數是直接綁定在真實的 DOM 元素上的,并不參與 Virtual DOM 中的數據流程,這樣就會導致以下兩個問題:
-
事件綁定后,如果組件狀態變化并且重新渲染,那么重新渲染后的組件實例會重新創建一個新的 DOM 元素,而舊的 DOM 元素會被銷毀,導致原來的事件處理函數被綁定在了一個不存在的元素上,導致事件失效。
-
使用原生事件綁定方式,無法在事件處理函數中直接訪問組件實例的狀態和屬性。例如,在事件處理函數中想要訪問一個組件的狀態或者屬性,就必須使用組件實例的引用(即 this 指針),但是這個 this 指針指向的并不是組件實例本身,而是真實的 DOM 元素,這樣就無法直接訪問組件狀態和屬性。
因此,在 React 中,我們必須使用 onClick
等鉤子函數來綁定事件處理函數,這樣 React 就能夠在其 Virtual DOM 中正確地跟蹤組件狀態變化,并保證事件處理函數的正確性。當然,在一些極端的情況下,React 也提供了訪問真實 DOM 元素的機制,比如 ref
屬性,這個可以在某些場景下使用。
337.函數式編程了解多少?【熱度: 1,789】【web應用場景】【出題公司: 百度】
關鍵詞:函數式編程
函數式編程的核心概念
函數式編程是一種編程范式,它將程序看做是一系列函數的組合,函數是應用的基礎單位。函數式編程主要有以下核心概念:
-
純函數:函數的輸出只取決于輸入,沒有任何副作用,不會修改外部變量或狀態,所以對于同樣的輸入,永遠返回同樣的輸出值。因此,純函數可以有效地避免副作用和競態條件等問題,使得代碼更加可靠、易于調試和測試。
-
不可變性:在函數式編程中,數據通常是不可變的,即不允許在內部進行修改。這樣可以避免副作用的發生,提高代碼可靠性。
-
函數組合:函數可以組合成復雜的函數,從而減少重復代碼的產生。
-
高階函數:高階函數是指可以接收其他函數作為參數,也可以返回函數的函數。例如,函數柯里化和函數的組合就是高階函數的應用場景。
-
惰性計算:指在必要的時候才計算(執行)函數,而不是在每個可能的執行路徑上都執行,從而提高性能。
函數式編程的核心概念是將函數作為基本構建塊來組合構建程序,通過純函數、不可變性、函數組合、高階函數和惰性計算等概念來實現代碼的簡潔性、可讀性和可維護性,以及高效的性能運行。
函數式編程的優勢
函數式編程有以下優勢:
-
易于理解和維護:函數式編程強調數據不變性和純函數概念,可以提高代碼的可讀性和可維護性,因為它避免了按照順序對變量進行修改,并強調函數行為的確定性。
-
更少的 bug:由于函數式編程強調純函數的概念,它可以消除由于副作用引起的bug。因為純函數不會修改外部狀態或數據結構,只是將輸入轉換為輸出。這么做有助于保持代碼更加可靠。
-
更好的可測試性:由于純函數不具有副作用,它更容易測試,因為測試數據是預測性的。
-
更少的重構:函數式編程使用函數組合和柯里化等方法來簡化代碼。它將大型問題分解為微小問題,從而減少了代碼重構的需要。
-
避免并發問題:由于函數式編程強調不變性和純函數的概念,這使得并發問題變得更簡單。純函數允許并行運行,因此,當程序在不同的線程上執行時,它更容易保持同步。
-
代碼復用:由于函數是基本構建塊,并且可以組合成更高級別的功能塊,使用函數式編程可以更大程度上推崇代碼復用,減少代碼冗余。
函數式編程通過強調純函數、不可變數據結構和函數組合等概念,可以提高代碼可讀性和可維護性,降低程序bug出現的風險,更容易測試,并且更容易將問題分解為更容易處理的小部分,更好地應對并發和可擴展性。
高級開發者相關問題【共計 4 道題】
328.script 預加載方式有哪些, 這些加載方式有何區別?【熱度: 420】【瀏覽器、web應用場景】
關鍵詞:script 預加載
在瀏覽器中,可以通過預加載 JavaScript 腳本來提高性能和用戶體驗。預加載是指在瀏覽器解析完當前頁面之前,提前加載并解析相關資源(例如 JavaScript 文件、CSS 文件等)。這樣可以在用戶請求訪問其他頁面時,減少資源加載的時間和延遲,從而提高頁面加載速度和用戶體驗。
以下是兩種預加載 JavaScript 腳本的方法:
- defer 屬性
<script>
標簽的 defer
屬性可以告訴瀏覽器,讓 JavaScript 文件在頁面文檔解析完成之后再執行。這種方式可以保證頁面不會因為腳本加載和執行而被阻塞,同時又能夠保證腳本能夠按照正確的順序執行(即按照在 HTML 中出現的順序,因為 defer
屬性會按照這個順序依次加載和執行)。
<!DOCTYPE html>
<html>
<head>
<title>My Page</title>
<script src="script1.js" defer></script>
<script src="script2.js" defer></script>
</head>
<body>
...
</body>
</html>
- prefetch 和 preload
預加載的另一種方法是使用 Link
標簽的 prefetch
或 preload
屬性。這種方法可以在不影響當前頁面加載的情況下,預先加載需要后續頁面需要的 JavaScript 文件和其他資源。
其中,prefetch
屬性指示瀏覽器預先加載并緩存 JavaScript 文件,但不會立即執行文件。而 preload
屬性則會在瀏覽器空閑時立即加載文件,并且可以指定文件的類型、優先級等屬性。
<head>
<title>My Page</title>
<link rel="prefetch" href="script1.js" />
<link rel="preload" href="script2.js" as="script" />
</head>
需要注意的是,使用 prefetch
和 preload
屬性時,應該避免將其用于太多的資源文件,否則可能會引發網絡瓶頸和性能問題。可以在需要優化的資源文件上使用這些屬性,并通過測試和性能分析來調整其預加載的優先級和時機,以達到最優化的預加載效果。
333.TCP/IP 如何保證數據包傳輸的有序可靠【熱度: 336】【網絡】【出題公司: 騰訊】
關鍵詞:TCP/IP 可靠性、TCP/IP 序列號、TCP/IP 超時
TCP/IP 采用以下幾種機制來保證數據包傳輸的有序可靠:
-
確認和重傳:每當 TCP/IP 協議收到一個數據包時,將向發送方回送一個確認信息。如果接收方未收到數據包,則發送方將重傳該數據包。這種確認和重傳的機制可以確保數據包能夠可靠地傳輸,即使在網絡故障或擁塞的情況下也能保證數據包的可靠性。
-
滑動窗口:滑動窗口是 TCP/IP 協議用來控制發送方和接收方之間數據流的一種機制。發送方會將窗口大小告知接收方,接收方在收到數據包時,會回送一個告知發送方可以繼續發送數據的指令?;瑒哟翱跈C制可以通過有效地控制數據包的發送與接收,實現有序的數據傳輸。
-
序列號:每個數據包都會附帶一個序列號,接收方通過序列號對數據包進行排序,從而實現傳輸的有序性。
-
超時重傳時間:TCP/IP 建立了一個計時器,如果在指定時間內沒有收到確認信息,則會重新發送未確認的數據包。這種機制可以幫助保證數據包傳輸的可靠性,確保數據包能夠及時被送達。
總之,TCP/IP 協議通過確認和重傳、滑動窗口、序列號以及超時重傳時間等機制,保證了數據包傳輸的有序可靠性。這些機制可以確保數據包能夠被及時送達,有效地防止了數據包丟失、重復和亂序等問題,從而提供了高效可靠的傳輸服務。
338.JavaScript 對象的底層數據結構是什么【熱度: 517】【JavaScript】
關鍵詞:JavaScript 對象數據結構
在JavaScript中,對象是一種無序的鍵值對集合,可以保存和傳遞信息。對象是一種非常重要的數據類型,在JavaScript中,幾乎所有東西都是對象。
在底層,JavaScript對象的數據結構是哈希表(Hash Table),也可以稱為散列表。哈希表是一種使用哈希函數將鍵值映射到數據中的位置的數據結構。它允許效率高且快速地插入、查找和刪除數據,這些操作在算法的平均情況下都需要常數時間。哈希表的主要思想是將鍵值對轉換為索引的方式在常數時間內獲取值,因此哈希表非常適合用于大量的鍵值對數據存儲。
在JavaScript中,對象的鍵值對存儲使用了類似哈希表的技術。JavaScript引擎使用一個稱為哈希表種子的隨機數字來計算鍵的哈希值,然后使用頭插法(鏈表或樹)將鍵和值存儲在桶中,以實現高效的插入和查詢操作。因此,JavaScript對象在實現上使用了哈希表來存儲和訪問鍵值對,從而提供了非常高效的數據存儲和查找操作,使之成為了編寫JavaScript代碼的強大工具。
339.JavaScript 中的變量在內存中的具體存儲形式是什么【熱度: 183】【JavaScript】
關鍵詞:JavaScript 變量存儲形式
在JavaScript中,變量的存儲方式是基于所存儲值的數據類型。JavaScript有7種內置數據類型:undefined、null、boolean、number、string、symbol和object。
對于基礎數據類型(除了object),變量值會直接存儲在內存中。具體來說,這些數據類型的變量在內存中的存儲形式如下:
- undefined和null:這兩個數據類型都只有一個值,每個值有一個特殊的內存地址。存儲它們的變量會被賦予對應的內存地址。
- boolean:這個數據類型的值只需要存儲一個比特位(0或1),它們通常被存儲在棧中,而不是堆中。
- number:根據規范,數字類型在內存中占用8個字節的空間(64位),它們通常被存儲在棧中,而不是堆中。
- string:字符串實際上是一組字符數組,它們通常被存儲在堆中,并通過引用地址存儲在棧中。
- symbol:每個symbol對應于唯一的標識符。它們通常被存儲在堆中,并通過引用地址存儲在棧中。
而對于對象類型(包括對象、數組等),變量存儲了一個指向存儲對象的內存地址的指針。JavaScript采用引用計數內存管理,因此它會對每個對象進行引用計數,當一個對象不再被引用時,JavaScript會自動回收這個對象的內存空間。
總的來說,在JavaScript中,變量的存儲方式基于值類型的數據類型,對于對象型變量,存儲指向對象的內存地址的指針以及對象的值,而對于基礎類型的變量,直接存儲變量的值。