国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

2023前端面試上岸手冊(cè)——JavaScript部分

這篇具有很好參考價(jià)值的文章主要介紹了2023前端面試上岸手冊(cè)——JavaScript部分。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

JavaScript 有哪些數(shù)據(jù)類型,它們的區(qū)別?

JavaScript 共有八種數(shù)據(jù)類型,分別是 Undefined、Null、Boolean、 Number、String、Object、Symbol、BigInt。

其中 Symbol 和 BigInt 是ES6 中新增的數(shù)據(jù)類型:

  • Symbol 代表創(chuàng)建后獨(dú)一無二且不可變的數(shù)據(jù)類型,它主要是為了解決可能出現(xiàn)的全局變量沖突的問題。

  • BigInt 是一種數(shù)字類型的數(shù)據(jù),它可以表示任意精度格式的整數(shù),使用 BigInt 可以安全地存儲(chǔ)和操作大整數(shù),即使這個(gè)數(shù)已經(jīng)超出了 Number 能夠表示的安全整數(shù)范圍。

這些數(shù)據(jù)可以分為原始數(shù)據(jù)類型和引用數(shù)據(jù)類型:

  • 棧:原始數(shù)據(jù)類型(Undefined、Null、Boolean、Number、String)

  • 堆:引用數(shù)據(jù)類型(對(duì)象、數(shù)組和函數(shù))兩種類型的區(qū)別在于存儲(chǔ)位置的不同:

  • 原始數(shù)據(jù)類型直接存儲(chǔ)在棧(stack)中的簡(jiǎn)單數(shù)據(jù)段,占據(jù)空間小、大小固定,屬于被頻繁使用數(shù)據(jù),所以放入棧中存儲(chǔ);

  • 引用數(shù)據(jù)類型存儲(chǔ)在堆(heap)中的對(duì)象,占據(jù)空間大、大小不固定。如果存儲(chǔ)在棧中,將會(huì)影響程序運(yùn)行的性能;引用數(shù)據(jù)類型在棧中存儲(chǔ)了指針,該指針指向堆中該實(shí)體的起始地址。當(dāng)解釋器尋找引用值時(shí),會(huì)首先檢索其在棧中的地址,取得地址后從堆中獲得實(shí)體。堆和棧的概念存在于數(shù)據(jù)結(jié)構(gòu)和操作系統(tǒng)內(nèi)存中,在數(shù)據(jù)結(jié)構(gòu)中:

  • 在數(shù)據(jù)結(jié)構(gòu)中,棧中數(shù)據(jù)的存取方式為先進(jìn)后出。

  • 堆是一個(gè)優(yōu)先隊(duì)列,是按優(yōu)先級(jí)來進(jìn)行排序的,優(yōu)先級(jí)可以按照大小來規(guī)定。

在操作系統(tǒng)中,內(nèi)存被分為棧區(qū)和堆區(qū):

  • 棧區(qū)內(nèi)存由編譯器自動(dòng)分配釋放,存放函數(shù)的參數(shù)值,局部變量的值等。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。

  • 堆區(qū)內(nèi)存一般由開發(fā)著分配釋放,若開發(fā)者不釋放,程序結(jié)束時(shí)可能由垃圾回收機(jī)制回收。

數(shù)據(jù)類型檢測(cè)的方式有哪些

  1. typeof
    2023前端面試上岸手冊(cè)——JavaScript部分

其中數(shù)組、對(duì)象、null 都會(huì)被判斷為object,其他判斷都正確。

  1. instanceof

instanceof 可以正確判斷對(duì)象的類型,其內(nèi)部運(yùn)行機(jī)制是判斷在其原型鏈中能否找到該類型的原型。
2023前端面試上岸手冊(cè)——JavaScript部分
3. constructor
constructor 有兩個(gè)作用,一是判斷數(shù)據(jù)的類型,二是對(duì)象實(shí)例通過 constrcutor 對(duì)象訪問它的構(gòu)造函數(shù)。需要注意,如果創(chuàng)建一個(gè)對(duì)象來改變它的原型,constructor 就不能用來判斷數(shù)據(jù)類型了:

  1. Object.prototype.toString.call()

Object.prototype.toString.call() 使用 Object 對(duì)象的原型方法 toString 來判斷數(shù)據(jù)類型:
2023前端面試上岸手冊(cè)——JavaScript部分

toString 方法(function 類型返回內(nèi)容為函數(shù)體的字符串,Array類型返回元素組成的字符串…),而不會(huì)去調(diào)用 Object 上原型 toString 方法(返回對(duì)象的具體類型),所以采用 obj.toString()不能得到其對(duì)象類型,只能將 obj 轉(zhuǎn)換為字符串類型;因此,在想要得到對(duì)象的具體類型時(shí),應(yīng)該調(diào)用Object 原型上的toString 方法。

null 和undefined 區(qū)別

首先 Undefined 和 Null 都是基本數(shù)據(jù)類型,這兩個(gè)基本數(shù)據(jù)類型分別都只有一個(gè)值,就是 undefined 和 null。

undefined 代表的含義是未定義,null 代表的含義是空對(duì)象。一般變量聲明了但還沒有定義的時(shí)候會(huì)返回 undefined,null 主要用于賦值給一些可能會(huì)返回對(duì)象的變量,作為初始化。

undefined 在 JavaScript 中不是一個(gè)保留字,這意味著可以使用 undefined 來作為一個(gè)變量名,但是這樣的做法是非常危險(xiǎn)的,它會(huì)影響對(duì) undefined 值的判斷。我們可以通過一些方法獲得安全的

如何獲取安全的 undefined 值?

因?yàn)?undefined 是一個(gè)標(biāo)識(shí)符,所以可以被當(dāng)作變量來使用和賦值,但是這樣會(huì)影響 undefined 的正常判斷。表達(dá)式 void 沒有返回值,因此返回結(jié)果是 undefined。void 并不改變表達(dá)式的結(jié)果,只是讓表達(dá)式不返回值。因此可以用 void 0 來獲得 undefined。

Object.is() 與比較操作符 “兩等” 、“三等” 的區(qū)別?

使用雙等號(hào)(==)進(jìn)行相等判斷時(shí),如果兩邊的類型不一致,則會(huì)進(jìn)行強(qiáng)制類型轉(zhuǎn)化后再進(jìn)行比較。

使用三等號(hào)(===)進(jìn)行相等判斷時(shí),如果兩邊的類型不一致時(shí),不會(huì)做強(qiáng)制類型準(zhǔn)換,直接返回 false。

使用 Object.is 來進(jìn)行相等判斷時(shí),一般情況下和三等號(hào)的判斷相同,它處理了一些特殊的情況,比如 -0 和 +0 不再相等,兩個(gè) NaN是相等的。

什么是 JavaScript 中的包裝類型?

在 JavaScript 中,基本類型是沒有屬性和方法的,但是為了便于操作基本類型的值,在調(diào)用基本類型的屬性或方法時(shí) JavaScript 會(huì)在后臺(tái)隱式地將基本類型的值轉(zhuǎn)換為對(duì)象,如:
2023前端面試上岸手冊(cè)——JavaScript部分

在訪問’abc’.length 時(shí), JavaScript 將’abc’ 在后臺(tái)轉(zhuǎn)換成 String(‘a(chǎn)bc’),然后再訪問其length 屬性。

JavaScript 也可以使用Object 函數(shù)顯式地將基本類型轉(zhuǎn)換為包裝類型:
2023前端面試上岸手冊(cè)——JavaScript部分

也可以使用valueOf 方法將包裝類型倒轉(zhuǎn)成基本類型:
2023前端面試上岸手冊(cè)——JavaScript部分

看看如下代碼會(huì)打印出什么:

2023前端面試上岸手冊(cè)——JavaScript部分

答案是什么都不會(huì)打印,因?yàn)殡m然包裹的基本類型是 false,但是 false 被包裹成包裝類型后就成了對(duì)象,所以其非值為 false,所以循環(huán)體中的內(nèi)容不會(huì)運(yùn)行。

為什么會(huì)有 BigInt 的提案?

JavaScript 中 Number.MAX_SAFE_INTEGER 表示最?安全數(shù)字,計(jì)算結(jié)果是 9007199254740991,即在這個(gè)數(shù)范圍內(nèi)不會(huì)出現(xiàn)精度丟失(?數(shù)除外)。但是?旦超過這個(gè)范圍,js 就會(huì)出現(xiàn)計(jì)算不準(zhǔn)確的情況,這在?數(shù)計(jì)算的時(shí)候不得不依靠?些第三?庫(kù)進(jìn)?解決,因此官?提出了BigInt 來解決此問題。

如何判斷一個(gè)對(duì)象是空對(duì)象

使用JSON 自帶的.stringify 方法來判斷:

2023前端面試上岸手冊(cè)——JavaScript部分

使用ES6 新增的方法Object.keys()來判斷:
2023前端面試上岸手冊(cè)——JavaScript部分

const 對(duì)象的屬性可以修改嗎

const 保證的并不是變量的值不能改動(dòng),而是變量指向的那個(gè)內(nèi)存地址不能改動(dòng)。對(duì)于基本類型的數(shù)據(jù)(數(shù)值、字符串、布爾值),其值就保存在變量指向的那個(gè)內(nèi)存地址,因此等同于常量。

但對(duì)于引用類型的數(shù)據(jù)(主要是對(duì)象和數(shù)組)來說,變量指向數(shù)據(jù)的內(nèi)存地址,保存的只是一個(gè)指針,const 只能保證這個(gè)指針是固定不變的,至于它指向的數(shù)據(jù)結(jié)構(gòu)是不是可變的,就完全不能控制了。

如果 new 一個(gè)箭頭函數(shù)的會(huì)怎么樣

箭頭函數(shù)是ES6 中的提出來的,它沒有prototype,也沒有自己的this
指向,更不可以使用arguments 參數(shù),所以不能New 一個(gè)箭頭函數(shù)。 new 操作符的實(shí)現(xiàn)步驟如下:

  1. 創(chuàng)建一個(gè)對(duì)象
  2. 將構(gòu)造函數(shù)的作用域賦給新對(duì)象(也就是將對(duì)象的 proto 屬性指向構(gòu)造函數(shù)的prototype 屬性)
  3. 指向構(gòu)造函數(shù)中的代碼,構(gòu)造函數(shù)中的 this 指向該對(duì)象(也就是為這個(gè)對(duì)象添加屬性和方法)
  4. 返回新的對(duì)象

所以,上面的第二、三步,箭頭函數(shù)都是沒有辦法執(zhí)行的。

箭頭函數(shù)的this 指向哪??

箭頭函數(shù)不同于傳統(tǒng)JavaScript 中的函數(shù),箭頭函數(shù)并沒有屬于??的this,它所謂的this 是捕獲其所在上下?的 this 值,作為??的 this 值,并且由于沒有屬于??的 this,所以是不會(huì)被 new調(diào)?的,這個(gè)所謂的this 也不會(huì)被改變。

可以?Babel 理解?下箭頭函數(shù):
2023前端面試上岸手冊(cè)——JavaScript部分
轉(zhuǎn)化后:
2023前端面試上岸手冊(cè)——JavaScript部分

擴(kuò)展運(yùn)算符的作用及使用場(chǎng)景

  1. 對(duì)象擴(kuò)展運(yùn)算符
    對(duì)象的擴(kuò)展運(yùn)算符(…)用于取出參數(shù)對(duì)象中的所有可遍歷屬性,拷貝到當(dāng)前對(duì)象之中。

2023前端面試上岸手冊(cè)——JavaScript部分

上述方法實(shí)際上等價(jià)于:
2023前端面試上岸手冊(cè)——JavaScript部分

Object.assign 方法用于對(duì)象的合并,將源對(duì)象(source)的所有可枚舉屬性,復(fù)制到目標(biāo)對(duì)象(target)。Object.assign 方法的第一個(gè)參數(shù)是目標(biāo)對(duì)象,后面的參數(shù)都是源對(duì)象。(如果目標(biāo)對(duì)象與源對(duì)象有同名屬性,或多個(gè)源對(duì)象有同名屬性,則后面的屬性會(huì)覆蓋前面的屬性)。
同樣,如果用戶自定義的屬性,放在擴(kuò)展運(yùn)算符后面,則擴(kuò)展運(yùn)算符內(nèi)部的同名屬性會(huì)被覆蓋掉。
2023前端面試上岸手冊(cè)——JavaScript部分

利用上述特性就可以很方便的修改對(duì)象的部分屬性。在 redux 中的 reducer 函數(shù)規(guī)定必須是一個(gè)純函數(shù),reducer 中的 state 對(duì)象要求不能直接修改,可以通過擴(kuò)展運(yùn)算符把修改路徑的對(duì)象都復(fù)制一遍,然后產(chǎn)生一個(gè)新的對(duì)象返回。

需要注意:擴(kuò)展運(yùn)算符對(duì)對(duì)象實(shí)例的拷貝屬于淺拷貝。

  1. 數(shù)組擴(kuò)展運(yùn)算符

數(shù)組的擴(kuò)展運(yùn)算符可以將一個(gè)數(shù)組轉(zhuǎn)為用逗號(hào)分隔的參數(shù)序列,且每次只能展開一層數(shù)組。

console.log(...[1, 2, 3])
// 1 2 3
console.log(...[1, [2, 3, 4], 5])
//1 [2, 3, 4] 5

下面是數(shù)組的擴(kuò)展運(yùn)算符的應(yīng)用:

將數(shù)組轉(zhuǎn)換為參數(shù)序列

2023前端面試上岸手冊(cè)——JavaScript部分

復(fù)制數(shù)組

2023前端面試上岸手冊(cè)——JavaScript部分
要記?。簲U(kuò)展運(yùn)算符(…)用于取出參數(shù)對(duì)象中的所有可遍歷屬性,拷貝到當(dāng)前對(duì)象之中,這里參數(shù)對(duì)象是個(gè)數(shù)組,數(shù)組里面的所有對(duì)象都是基礎(chǔ)數(shù)據(jù)類型,將所有基礎(chǔ)數(shù)據(jù)類型重新拷貝到新的數(shù)組中。

合并數(shù)組

如果想在數(shù)組內(nèi)合并數(shù)組,可以這樣:
2023前端面試上岸手冊(cè)——JavaScript部分
擴(kuò)展運(yùn)算符與解構(gòu)賦值結(jié)合起來,用于生成數(shù)組

const [first,.rest],5];
first // 1
rest // [2, 3, 4, 5]

需要注意:如果將擴(kuò)展運(yùn)算符用于數(shù)組賦值,只能放在參數(shù)的最后一
位,否則會(huì)報(bào)錯(cuò)。

const [...rest, last] = [1, 2, 3, 4, 5];// 報(bào)錯(cuò)
const [first, ..rest, last]=[1, 2, 3, 4, 5]; // 報(bào)錯(cuò)

將字符串轉(zhuǎn)為真正的數(shù)組

[...'hello'] //[ "h", "e", "l", "l", "o" ]

任何 Iterator 接口的對(duì)象,都可以用擴(kuò)展運(yùn)算符轉(zhuǎn)為真正的數(shù)組

比較常見的應(yīng)用是可以將某些數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)為數(shù)組:

2023前端面試上岸手冊(cè)——JavaScript部分

用于替換es5 中的Array.prototype.slice.call(arguments)寫法。

使用Math 函數(shù)獲取數(shù)組中特定的值
2023前端面試上岸手冊(cè)——JavaScript部分

Proxy 可以實(shí)現(xiàn)什么功能?

在 Vue3.0 中通過 Proxy 來替換原本的 Object.defineProperty來實(shí)現(xiàn)數(shù)據(jù)響應(yīng)式。

Proxy 是 ES6 中新增的功能,它可以用來自定義對(duì)象中的操作。

2023前端面試上岸手冊(cè)——JavaScript部分

代表需要添加代理的對(duì)象,handler 用來自定義對(duì)象中的操作,比如可以用來自定義 set 或者 get 函數(shù)。
下面來通過 Proxy 來實(shí)現(xiàn)一個(gè)數(shù)據(jù)響應(yīng)式:

2023前端面試上岸手冊(cè)——JavaScript部分

在上述代碼中,通過自定義 set 和 get 函數(shù)的方式,在原本的邏輯中插入了我們的函數(shù)邏輯,實(shí)現(xiàn)了在對(duì)對(duì)象任何屬性進(jìn)行讀寫時(shí)發(fā)出通知。

當(dāng)然這是簡(jiǎn)單版的響應(yīng)式實(shí)現(xiàn),如果需要實(shí)現(xiàn)一個(gè) Vue 中的響應(yīng)式,需要在 get 中收集依賴,在 set 派發(fā)更新,之所以 Vue3.0 要使用 Proxy 替換原本的 API 原因在于 Proxy 無需一層層遞歸為每個(gè)屬性添加代理,一次即可完成以上操作,性能上更好,并且原本的實(shí)現(xiàn)有一些數(shù)據(jù)更新不能監(jiān)聽到,但是 Proxy 可以完美監(jiān)聽到任何方式的數(shù)據(jù)改變,唯一缺陷就是瀏覽器的兼容性不好。

常用的正則表達(dá)式有哪些?

2023前端面試上岸手冊(cè)——JavaScript部分

對(duì)JSON 的理解

JSON 是一種基于文本的輕量級(jí)的數(shù)據(jù)交換格式。它可以被任何的編程語言讀取和作為數(shù)據(jù)格式來傳遞。

在項(xiàng)目開發(fā)中,使用 JSON 作為前后端數(shù)據(jù)交換的方式。在前端通過將一個(gè)符合 JSON 格式的數(shù)據(jù)結(jié)構(gòu)序列化為JSON 字符串,然后將它傳遞到后端,后端通過 JSON 格式的字符串解析后生成對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu),以此來實(shí)現(xiàn)前后端數(shù)據(jù)的一個(gè)傳遞。

因?yàn)?JSON 的語法是基于 js 的,因此很容易將 JSON 和 js 中的對(duì)象弄混,但是應(yīng)該注意的是 JSON 和 js 中的對(duì)象不是一回事,JSON中對(duì)象格式更加嚴(yán)格,比如說在 JSON 中屬性值不能為函數(shù),不能出現(xiàn) NaN 這樣的屬性值等,因此大多數(shù)的 js 對(duì)象是不符合 JSON 對(duì)象的格式的。

在 js 中提供了兩個(gè)函數(shù)來實(shí)現(xiàn) js 數(shù)據(jù)結(jié)構(gòu)和 JSON 格式的轉(zhuǎn)換處理,JSON.stringify 函數(shù),通過傳入一個(gè)符合 JSON 格式的數(shù)據(jù)結(jié)構(gòu),將其轉(zhuǎn)換為一個(gè) JSON 字符串。如果傳入的數(shù)據(jù)結(jié)構(gòu)不符合 JSON 格式,那么在序列化的時(shí)候會(huì)對(duì)這些值進(jìn)行對(duì)應(yīng)的特殊處理,使其符合規(guī)范。在前端向后端發(fā)送數(shù)據(jù)時(shí),可以調(diào)用這個(gè)函數(shù)將數(shù)據(jù)對(duì)象轉(zhuǎn)化為 JSON 格式的字符串。

JSON.parse() 函數(shù),這個(gè)函數(shù)用來將 JSON 格式的字符串轉(zhuǎn)換為一個(gè) js 數(shù)據(jù)結(jié)構(gòu),如果傳入的字符串不是標(biāo)準(zhǔn)的 JSON 格式的字符串的話,將會(huì)拋出錯(cuò)誤。當(dāng)從后端接收到 JSON 格式的字符串時(shí),可以通過這個(gè)方法來將其解析為一個(gè) js 數(shù)據(jù)結(jié)構(gòu),以此來進(jìn)行數(shù)據(jù)的訪問。

JavaScript 腳本延遲加載的方式有哪些?

延遲加載就是等頁(yè)面加載完成之后再加載 JavaScript 文件。js 延遲加載有助于提高頁(yè)面加載速度。

一般有以下幾種方式:

defer 屬性:給 js 腳本添加 defer 屬性,這個(gè)屬性會(huì)讓腳本的加載與文檔的解析同步解析,然后在文檔解析完成后再執(zhí)行這個(gè)腳本文件,這樣的話就能使頁(yè)面的渲染不被阻塞。多個(gè)設(shè)置了 defer 屬性的腳本按規(guī)范來說最后是順序執(zhí)行的,但是在一些瀏覽器中可能不是這樣。

async 屬性:給 js 腳本添加 async 屬性,這個(gè)屬性會(huì)使腳本異步加載,不會(huì)阻塞頁(yè)面的解析過程,但是當(dāng)腳本加載完成后立即執(zhí)行 js腳本,這個(gè)時(shí)候如果文檔沒有解析完成的話同樣會(huì)阻塞。多個(gè) async屬性的腳本的執(zhí)行順序是不可預(yù)測(cè)的,一般不會(huì)按照代碼的順序依次執(zhí)行。

動(dòng)態(tài)創(chuàng)建 DOM 方式:動(dòng)態(tài)創(chuàng)建 DOM 標(biāo)簽的方式,可以對(duì)文檔的加載事件進(jìn)行監(jiān)聽,當(dāng)文檔加載完成后再動(dòng)態(tài)的創(chuàng)建 script 標(biāo)簽來引入 js 腳本。

使用 setTimeout 延遲方法:設(shè)置一個(gè)定時(shí)器來延遲加載 js 腳本文件

讓 JS 最后加載:將 js 腳本放在文檔的底部,來使 js 腳本盡可能的在最后來加載執(zhí)行。

什么是 DOM 和 BOM?

DOM 指的是文檔對(duì)象模型,它指的是把文檔當(dāng)做一個(gè)對(duì)象,這個(gè)對(duì)象主要定義了處理網(wǎng)頁(yè)內(nèi)容的方法和接口。

BOM 指的是瀏覽器對(duì)象模型,它指的是把瀏覽器當(dāng)做一個(gè)對(duì)象來對(duì)待,這個(gè)對(duì)象主要定義了與瀏覽器進(jìn)行交互的法和接口。BOM 的核心是 window,而 window 對(duì)象具有雙重角色,它既是通過 js 訪問瀏覽器 窗口的一個(gè)接口,又是一個(gè) Global(全局)對(duì)象。這意味著在網(wǎng)頁(yè) 中定義的任何對(duì)象,變量和函數(shù),都作為全局對(duì)象的一個(gè)屬性或者方 法存在。window 對(duì)象含有 location 對(duì)象、navigator 對(duì)象、screen對(duì)象等子對(duì)象,并且 DOM 的最根本的對(duì)象 document 對(duì)象也是 BOM的 window 對(duì)象的子對(duì)象。

escape、encodeURI、encodeURIComponent 的區(qū)別

encodeURI 是對(duì)整個(gè) URI 進(jìn)行轉(zhuǎn)義,將 URI 中的非法字符轉(zhuǎn)換為合法字符,所以對(duì)于一些在 URI 中有特殊意義的字符不會(huì)進(jìn)行轉(zhuǎn)義。

encodeURIComponent 是對(duì) URI 的組成部分進(jìn)行轉(zhuǎn)義,所以一些特殊字符也會(huì)得到轉(zhuǎn)義。

escape 和 encodeURI 的作用相同,不過它們對(duì)于 unicode 編碼為 0xff 之外字符的時(shí)候會(huì)有區(qū)別,escape 是直接在字符的 unicode編碼前加上 %u,而 encodeURI 首先會(huì)將字符轉(zhuǎn)換為 UTF-8 的格式,再在每個(gè)字節(jié)前加上 %。

對(duì)AJAX 的理解,實(shí)現(xiàn)一個(gè) AJAX 請(qǐng)求

AJAX 是 Asynchronous JavaScript and XML 的縮寫,指的是通過 JavaScript 的 異步通信,從服務(wù)器獲取 XML 文檔從中提取數(shù)據(jù),再更新當(dāng)前網(wǎng)頁(yè)的對(duì)應(yīng)部分,而不用刷新整個(gè)網(wǎng)頁(yè)。

創(chuàng)建AJAX 請(qǐng)求的步驟:

創(chuàng)建一個(gè) XMLHttpRequest 對(duì)象。

在這個(gè)對(duì)象上使用 open 方法創(chuàng)建一個(gè) HTTP 請(qǐng)求,open 方法所需要的參數(shù)是請(qǐng)求的方法、請(qǐng)求的地址、是否異步和用戶的認(rèn)證信息。

在發(fā)起請(qǐng)求前,可以為這個(gè)對(duì)象添加一些信息和監(jiān)聽函數(shù)。比如說可以通過 setRequestHeader 方法來為請(qǐng)求添加頭信息。還可以為這個(gè)對(duì)象添加一個(gè)狀態(tài)監(jiān)聽函數(shù)。一個(gè) XMLHttpRequest 對(duì)象一共有 5個(gè)狀態(tài),當(dāng)它的狀態(tài)變化時(shí)會(huì)觸發(fā)onreadystatechange 事件,可以通過設(shè)置監(jiān)聽函數(shù),來處理請(qǐng)求成功后的結(jié)果。當(dāng)對(duì)象的 readyState 變?yōu)?4 的時(shí)候,代表服務(wù)器返回的數(shù)據(jù)接收完成,這個(gè)時(shí)候可以通 過判斷請(qǐng)求的狀態(tài),如果狀態(tài)是 2xx 或者 304 的話則代表返回正常。這個(gè)時(shí)候就可以通過 response 中的數(shù)據(jù)來對(duì)頁(yè)面進(jìn)行更新了。

當(dāng)對(duì)象的屬性和監(jiān)聽函數(shù)設(shè)置完成后,最后調(diào)用 sent 方法來向服務(wù)器發(fā)起請(qǐng)求,可以傳入?yún)?shù)作為發(fā)送的數(shù)據(jù)體。
2023前端面試上岸手冊(cè)——JavaScript部分
使用Promise 封裝AJAX:
2023前端面試上岸手冊(cè)——JavaScript部分

什么是尾調(diào)用,使用尾調(diào)用有什么好處?

尾調(diào)用指的是函數(shù)的最后一步調(diào)用另一個(gè)函數(shù)。代碼執(zhí)行是基于執(zhí)行棧的,所以當(dāng)在一個(gè)函數(shù)里調(diào)用另一個(gè)函數(shù)時(shí),會(huì)保留當(dāng)前的執(zhí)行上下文,然后再新建另外一個(gè)執(zhí)行上下文加入棧中。使用尾調(diào)用的話,因?yàn)橐呀?jīng)是函數(shù)的最后一步,所以這時(shí)可以不必再保留當(dāng)前的執(zhí)行上下文,從而節(jié)省了內(nèi)存,這就是尾調(diào)用優(yōu)化。但是 ES6 的尾調(diào)用優(yōu)化只在嚴(yán)格模式下開啟,正常模式是無效的。

ES6 模塊與 CommonJS 模塊有什么異同?

ES6 Module 和CommonJS 模塊的區(qū)別:

CommonJS 是對(duì)模塊的淺拷?,ES6 Module 是對(duì)模塊的引?,即 ES6 Module 只存只讀,不能改變其值,也就是指針指向不能變,類似 const;

import 的接?是 read-only(只讀狀態(tài)),不能修改其變量值。 即不能修改其變量的指針指向,但可以改變變量?jī)?nèi)部指針指向,可以對(duì) commonJS 對(duì)重新賦值(改變指針指向),但是對(duì)ES6 Module 賦值會(huì)編譯報(bào)錯(cuò)。

ES6 Module 和CommonJS 模塊的共同點(diǎn):
CommonJS 和ES6 Module 都可以對(duì)引?的對(duì)象進(jìn)?賦值,即對(duì)對(duì)象內(nèi)部屬性的值進(jìn)?改變。

for…in 和for…of 的區(qū)別

for…of 是 ES6 新增的遍歷方式,允許遍歷一個(gè)含有 iterator 接口
的數(shù)據(jù)結(jié)構(gòu)(數(shù)組、對(duì)象等)并且返回各項(xiàng)的值,和ES3 中的for… in 的區(qū)別如下
for…of 遍歷獲取的是對(duì)象的鍵值,for…in 獲取的是對(duì)象的鍵名;
for… in 會(huì)遍歷對(duì)象的整個(gè)原型鏈,性能非常差不推薦使用,而 for … of 只遍歷當(dāng)前對(duì)象不會(huì)遍歷原型鏈;

對(duì)于數(shù)組的遍歷,for…in 會(huì)返回?cái)?shù)組中所有可枚舉的屬性(包括原型鏈上可枚舉的屬性),for…of 只返回?cái)?shù)組的下標(biāo)對(duì)應(yīng)的屬性值;

總結(jié):for...in 循環(huán)主要是為了遍歷對(duì)象而生,不適用于遍歷數(shù)組; for...of 循環(huán)可以用來遍歷數(shù)組、類數(shù)組對(duì)象,字符串、Set、Map 以及 Generator 對(duì)象。

ajax、axios、fetch 的區(qū)別

AJAX

Ajax 即“AsynchronousJavascriptAndXML”(異步 JavaScript 和 XML),是指一種創(chuàng)建交互式網(wǎng)頁(yè)應(yīng)用的網(wǎng)頁(yè)開發(fā)技術(shù)。它是一種在無需重新加載整個(gè)網(wǎng)頁(yè)的情況下,能夠更新部分網(wǎng)頁(yè)的技術(shù)。通過在后臺(tái)與服務(wù)器進(jìn)行少量數(shù)據(jù)交換,Ajax 可以使網(wǎng)頁(yè)實(shí)現(xiàn)異步更新。這意味著可以在不重新加載整個(gè)網(wǎng)頁(yè)的情況下,對(duì)網(wǎng)頁(yè)的某部分進(jìn)行更新。傳統(tǒng)的網(wǎng)頁(yè)(不使用 Ajax)如果需要更新內(nèi)容,必須重載整個(gè)網(wǎng)頁(yè)頁(yè)面。其缺點(diǎn)如下:

  • 本身是針對(duì)MVC 編程,不符合前端MVVM 的浪潮
  • 基于原生XHR 開發(fā),XHR 本身的架構(gòu)不清晰
  • 不符合關(guān)注分離(Separation of Concerns)的原則
  • 配置和調(diào)用方式非?;靵y,而且基于事件的異步模型不友好。

Fetch

fetch 號(hào)稱是 AJAX 的替代品,是在 ES6 出現(xiàn)的,使用了 ES6 中的 promise 對(duì)象。Fetch 是基于 promise 設(shè)計(jì)的。Fetch 的代碼結(jié)構(gòu)比起ajax 簡(jiǎn)單多。fetch 不是ajax 的進(jìn)一步封裝,而是原生 js,沒有使用XMLHttpRequest 對(duì)象。

fetch 的優(yōu)點(diǎn):

  • 語法簡(jiǎn)潔,更加語義化

  • 基于標(biāo)準(zhǔn) Promise 實(shí)現(xiàn),支持 async/await

  • 更加底層,提供的API 豐富(request, response)

  • 脫離了XHR,是ES 規(guī)范里新的實(shí)現(xiàn)方式

fetch 的缺點(diǎn):

  • fetch 只對(duì)網(wǎng)絡(luò)請(qǐng)求報(bào)錯(cuò),對(duì) 400,500 都當(dāng)做成功的請(qǐng)求,服務(wù)器返回 400,500 錯(cuò)誤碼時(shí)并不會(huì) reject,只有網(wǎng)絡(luò)錯(cuò)誤這些導(dǎo)致請(qǐng)求不能完成時(shí),fetch 才會(huì)被 reject。

  • fetch 默認(rèn)不會(huì)帶 cookie , 需要添加配置項(xiàng): fetch(url,{credentials: ‘include’})

  • fetch 不支持 abort , 不支持超時(shí)控制, 使用 setTimeout 及 Promise.reject 的實(shí)現(xiàn)的超時(shí)控制并不能阻止請(qǐng)求過程繼續(xù)在后臺(tái)運(yùn)行,造成了流量的浪費(fèi)
    fetch 沒有辦法原生監(jiān)測(cè)請(qǐng)求的進(jìn)度,而XHR 可以

Axios

Axios 是一種基于Promise 封裝的HTTP 客戶端,其特點(diǎn)如下:

  • 瀏覽器端發(fā)起XMLHttpRequests 請(qǐng)求

  • node 端發(fā)起 http 請(qǐng)求

  • 支持Promise API

  • 監(jiān)聽請(qǐng)求和返回

  • 對(duì)請(qǐng)求和返回進(jìn)行轉(zhuǎn)化

  • 取消請(qǐng)求

  • 自動(dòng)轉(zhuǎn)換json 數(shù)據(jù)

  • 客戶端支持抵御XSRF 攻擊

對(duì)原型、原型鏈的理解

在JavaScript 中是使用構(gòu)造函數(shù)來新建一個(gè)對(duì)象的,每一個(gè)構(gòu)造函數(shù)的內(nèi)部都有一個(gè) prototype 屬性,它的屬性值是一個(gè)對(duì)象,這個(gè)對(duì)象包含了可以由該構(gòu)造函數(shù)的所有實(shí)例共享的屬性和方法。當(dāng)使用構(gòu)造函數(shù)新建一個(gè)對(duì)象后,在這個(gè)對(duì)象的內(nèi)部將包含一個(gè)指針,這個(gè)指針指向構(gòu)造函數(shù)的 prototype 屬性對(duì)應(yīng)的值,在 ES5 中這個(gè)指針被稱為對(duì)象的原型。一般來說不應(yīng)該能夠獲取到這個(gè)值的,但是現(xiàn)在瀏覽器中都實(shí)現(xiàn)了_proto_ 屬性來訪問這個(gè)屬性,但是最好不要使用這個(gè)屬性, 因?yàn)樗皇且?guī)范中規(guī)定的。ES5 中新增了一個(gè) Object.getPrototypeOf() 方法,可以通過這個(gè)方法來獲取對(duì)象的原型。

當(dāng)訪問一個(gè)對(duì)象的屬性時(shí),如果這個(gè)對(duì)象內(nèi)部不存在這個(gè)屬性,那么它就會(huì)去它的原型對(duì)象里找這個(gè)屬性,這個(gè)原型對(duì)象又會(huì)有自己的原型,于是就這樣一直找下去,也就是原型鏈的概念。原型鏈的盡頭一般來說都是 Object.prototype 所以這就是新建的對(duì)象為什么能夠使用 toString() 等方法的原因。

特點(diǎn):JavaScript 對(duì)象是通過引用來傳遞的,創(chuàng)建的每個(gè)新對(duì)象實(shí)體中并沒有一份屬于自己的原型副本。當(dāng)修改原型時(shí),與之相關(guān)的對(duì)象也會(huì)繼承這一改變。

由于Object 是構(gòu)造函數(shù),原型鏈終點(diǎn) Object.prototype. proto ,而Object.prototype. proto === null // true,所以,原型鏈的終點(diǎn)是null。原型鏈上的所有原型都是對(duì)象,所有的對(duì)象最終都 是由Object 構(gòu)造的,而Object.prototype 的下一級(jí)是 Object.prototype. proto 。

2023前端面試上岸手冊(cè)——JavaScript部分

對(duì)作用域、作用域鏈的理解

  1. 全局作用域和函數(shù)作用域

全局作用域

  • 最外層函數(shù)和最外層函數(shù)外面定義的變量擁有全局作用域

  • 所有未定義直接賦值的變量自動(dòng)聲明為全局作用域

  • 所有window 對(duì)象的屬性擁有全局作用域

  • 全局作用域有很大的弊端,過多的全局作用域變量會(huì)污染全局命名空間,容易引起命名沖突。
    函數(shù)作用域

  • 函數(shù)作用域聲明在函數(shù)內(nèi)部的變零,一般只有固定的代碼片段可以訪問到

  • 作用域是分層的,內(nèi)層作用域可以訪問外層作用域,反之不行
    塊級(jí)作用域

使用ES6 中新增的let 和const 指令可以聲明塊級(jí)作用域,塊級(jí)作用域可以在函數(shù)中創(chuàng)建也可以在一個(gè)代碼塊中的創(chuàng)建(由{ }包裹的代碼片段)

let 和const 聲明的變量不會(huì)有變量提升,也不可以重復(fù)聲明

在循環(huán)中比較適合綁定塊級(jí)作用域,這樣就可以把聲明的計(jì)數(shù)器變量限制在循環(huán)內(nèi)部。

作用域鏈:

在當(dāng)前作用域中查找所需變量,但是該作用域沒有這個(gè)變量,那這個(gè)變量就是自由變量。如果在自己作用域找不到該變量就去父級(jí)作用域查找,依次向上級(jí)作用域查找,直到訪問到 window 對(duì)象就被終止,這一層層的關(guān)系就是作用域鏈。

作用域鏈的作用是保證對(duì)執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的有序訪問,通過作用域鏈,可以訪問到外層環(huán)境的變量和函數(shù)。

作用域鏈的本質(zhì)上是一個(gè)指向變量對(duì)象的指針列表。變量對(duì)象是一個(gè)包含了執(zhí)行環(huán)境中所有變量和函數(shù)的對(duì)象。作用域鏈的前端始終都是當(dāng)前執(zhí)行上下文的變量對(duì)象。全局執(zhí)行上下文的變量對(duì)象(也就是全局對(duì)象)始終是作用域鏈的最后一個(gè)對(duì)象。

當(dāng)查找一個(gè)變量時(shí),如果當(dāng)前執(zhí)行環(huán)境中沒有找到,可以沿著作用域鏈向后查找。

對(duì)this 對(duì)象的理解

this 是執(zhí)行上下文中的一個(gè)屬性,它指向最后一次調(diào)用這個(gè)方法的對(duì)象。在實(shí)際開發(fā)中,this 的指向可以通過四種調(diào)用模式來判斷。

第一種是函數(shù)調(diào)用模式,當(dāng)一個(gè)函數(shù)不是一個(gè)對(duì)象的屬性時(shí),直接作為函數(shù)來調(diào)用時(shí),this 指向全局對(duì)象。

第二種是方法調(diào)用模式,如果一個(gè)函數(shù)作為一個(gè)對(duì)象的方法來調(diào)用時(shí), this 指向這個(gè)對(duì)象。

第三種是構(gòu)造器調(diào)用模式,如果一個(gè)函數(shù)用 new 調(diào)用時(shí),函數(shù)執(zhí)行前會(huì)新創(chuàng)建一個(gè)對(duì)象,this 指向這個(gè)新創(chuàng)建的對(duì)象。

第四種是 apply 、 call 和 bind 調(diào)用模式,這三個(gè)方法都可以顯 示的指定調(diào)用函數(shù)的 this 指向。其中 apply 方法接收兩個(gè)參數(shù): 一個(gè)是 this 綁定的對(duì)象,一個(gè)是參數(shù)數(shù)組。call 方法接收的參數(shù),第一個(gè)是 this 綁定的對(duì)象,后面的其余參數(shù)是傳入函數(shù)執(zhí)行的參數(shù)。也就是說,在使用 call() 方法時(shí),傳遞給函數(shù)的參數(shù)必須逐個(gè)列舉 出來。bind 方法通過傳入一個(gè)對(duì)象,返回一個(gè) this 綁定了傳入對(duì) 象的新函數(shù)。這個(gè)函數(shù)的 this 指向除了使用 new 時(shí)會(huì)被改變,其 他情況下都不會(huì)改變。

這四種方式,使用構(gòu)造器調(diào)用模式的優(yōu)先級(jí)最高,然后是 apply、call和 bind 調(diào)用模式,然后是方法調(diào)用模式,然后是函數(shù)調(diào)用模式。

call() 和 apply() 的區(qū)別?

它們的作用一模一樣,區(qū)別僅在于傳入?yún)?shù)的形式的不同。

apply 接受兩個(gè)參數(shù),第一個(gè)參數(shù)指定了函數(shù)體內(nèi) this 對(duì)象的指向,第二個(gè)參數(shù)為一個(gè)帶下標(biāo)的集合,這個(gè)集合可以為數(shù)組,也可以為類 數(shù)組,apply 方法把這個(gè)集合中的元素作為參數(shù)傳遞給被調(diào)用的函數(shù)。

call 傳入的參數(shù)數(shù)量不固定,跟 apply 相同的是,第一個(gè)參數(shù)也是代表函數(shù)體內(nèi)的 this 指向,從第二個(gè)參數(shù)開始往后,每個(gè)參數(shù)被依次傳入函數(shù)。

異步編程的實(shí)現(xiàn)方式?

JavaScript 中的異步機(jī)制可以分為以下幾種:

回調(diào)函數(shù) 的方式,使用回調(diào)函數(shù)的方式有一個(gè)缺點(diǎn)是,多個(gè)回調(diào)函數(shù)嵌套的時(shí)候會(huì)造成回調(diào)函數(shù)地獄,上下兩層的回調(diào)函數(shù)間的代碼耦合度太高,不利于代碼的可維護(hù)。

Promise 的方式,使用 Promise 的方式可以將嵌套的回調(diào)函數(shù)作為鏈?zhǔn)秸{(diào)用。但是使用這種方法,有時(shí)會(huì)造成多個(gè) then 的鏈?zhǔn)秸{(diào)用,可能會(huì)造成代碼的語義不夠明確。

generator 的方式,它可以在函數(shù)的執(zhí)行過程中,將函數(shù)的執(zhí)行權(quán)轉(zhuǎn)移出去,在函數(shù)外部還可以將執(zhí)行權(quán)轉(zhuǎn)移回來。當(dāng)遇到異步函數(shù)執(zhí)行的時(shí)候,將函數(shù)執(zhí)行權(quán)轉(zhuǎn)移出去,當(dāng)異步函數(shù)執(zhí)行完畢時(shí)再將執(zhí)行權(quán)給轉(zhuǎn)移回來。因此在 generator 內(nèi)部對(duì)于異步操作的方式,可以以同步的順序來書寫。使用這種方式需要考慮的問題是何時(shí)將函數(shù)的控制權(quán)轉(zhuǎn)移回來,因此需要有一個(gè)自動(dòng)執(zhí)行 generator 的機(jī)制,比如說 co 模塊等方式來實(shí)現(xiàn) generator 的自動(dòng)執(zhí)行。

async 函數(shù) 的方式,async 函數(shù)是 generator 和 promise 實(shí)現(xiàn)的一個(gè)自動(dòng)執(zhí)行的語法糖,它內(nèi)部自帶執(zhí)行器,當(dāng)函數(shù)內(nèi)部執(zhí)行到一個(gè) await 語句的時(shí)候,如果語句返回一個(gè) promise 對(duì)象,那么函數(shù)將會(huì)等待 promise 對(duì)象的狀態(tài)變?yōu)?resolve 后再繼續(xù)向下執(zhí)行。因此可以將異步邏輯,轉(zhuǎn)化為同步的順序來書寫,并且這個(gè)函數(shù)可以自動(dòng)執(zhí)行。

對(duì)Promise 的理解

Promise 是異步編程的一種解決方案,它是一個(gè)對(duì)象,可以獲取異步操作的消息,他的出現(xiàn)大大改善了異步編程的困境,避免了地獄回調(diào),它比傳統(tǒng)的解決方案回調(diào)函數(shù)和事件更合理和更強(qiáng)大。

所謂Promise,簡(jiǎn)單說就是一個(gè)容器,里面保存著某個(gè)未來才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果。從語法上說,Promise 是一個(gè)對(duì)象,從它可以獲取異步操作的消息。Promise 提供統(tǒng)一的 API,各種異步操作都可以用同樣的方法進(jìn)行處理。

  1. Promise 的實(shí)例有三個(gè)狀態(tài):
  • Pending(進(jìn)行中)
  • Resolved(已完成)
  • Rejected(已拒絕)

當(dāng)把一件事情交給promise 時(shí),它的狀態(tài)就是Pending,任務(wù)完成了狀態(tài)就變成了Resolved、沒有完成失敗了就變成了Rejected。

  1. Promise 的實(shí)例有兩個(gè)過程:

pending -> fulfilled : Resolved(已完成)
pending -> rejected:Rejected(已拒絕)

注意:一旦從進(jìn)行狀態(tài)變成為其他狀態(tài)就永遠(yuǎn)不能更改狀態(tài)了。

Promise 的特點(diǎn):

對(duì)象的狀態(tài)不受外界影響。promise 對(duì)象代表一個(gè)異步操作,有三種狀態(tài),pending(進(jìn)行中)、fulfilled(已成功)、rejected(已失?。?。只有異步操作的結(jié)果,可以決定當(dāng)前是哪一種狀態(tài),任何其他操作都無法改變這個(gè)狀態(tài),這也是 promise 這個(gè)名字的由來——“期約”;

一旦狀態(tài)改變就不會(huì)再變,任何時(shí)候都可以得到這個(gè)結(jié)果。promise對(duì)象的狀態(tài)改變,只有兩種可能:從 pending 變?yōu)?fulfilled,從 pending 變?yōu)?rejected。這時(shí)就稱為 resolved(已定型)。如果改變已經(jīng)發(fā)生了,你再對(duì) promise 對(duì)象添加回調(diào)函數(shù),也會(huì)立即得到這個(gè)結(jié)果。這與事件(event)完全不同,事件的特點(diǎn)是:如果你錯(cuò)過了它,再去監(jiān)聽是得不到結(jié)果的。

Promise 的缺點(diǎn):

無法取消Promise,一旦新建它就會(huì)立即執(zhí)行,無法中途取消。

如果不設(shè)置回調(diào)函數(shù),Promise 內(nèi)部拋出的錯(cuò)誤,不會(huì)反應(yīng)到外部。

當(dāng)處于pending 狀態(tài)時(shí),無法得知目前進(jìn)展到哪一個(gè)階段(剛剛開始還是即將完成)。

總結(jié):

Promise 對(duì)象是異步編程的一種解決方案,最早由社區(qū)提出。Promise是一個(gè)構(gòu)造函數(shù),接收一個(gè)函數(shù)作為參數(shù),返回一個(gè) Promise 實(shí)例。一個(gè) Promise 實(shí)例有三種狀態(tài), 分別是 pending、resolved 和 rejected,分別代表了進(jìn)行中、已成功和已失敗。實(shí)例的狀態(tài)只能由 pending 轉(zhuǎn)變 resolved 或者rejected 狀態(tài),并且狀態(tài)一經(jīng)改變,就凝固了,無法再被改變了。

狀態(tài)的改變是通過 resolve() 和 reject() 函數(shù)來實(shí)現(xiàn)的,可以在異步操作結(jié)束后調(diào)用這兩個(gè)函數(shù)改變 Promise 實(shí)例的狀態(tài),它的原型上定義了一個(gè) then 方法,使用這個(gè) then 方法可以為兩個(gè)狀態(tài)的改變注冊(cè)回調(diào)函數(shù)。這個(gè)回調(diào)函數(shù)屬于微任務(wù),會(huì)在本輪事件循環(huán)的末尾執(zhí)行。

注意:在構(gòu)造 Promise 的時(shí)候,構(gòu)造函數(shù)內(nèi)部的代碼是立即執(zhí)行的

Promise 解決了什么問題

在工作中經(jīng)常會(huì)碰到這樣一個(gè)需求,比如我使用ajax 發(fā)一個(gè)A 請(qǐng)求后,成功后拿到數(shù)據(jù),需要把數(shù)據(jù)傳給 B 請(qǐng)求;那么需要如下編寫代碼:
2023前端面試上岸手冊(cè)——JavaScript部分

上面的代碼有如下缺點(diǎn):

后一個(gè)請(qǐng)求需要依賴于前一個(gè)請(qǐng)求成功后,將數(shù)據(jù)往下傳遞,會(huì)導(dǎo)致多個(gè)ajax 請(qǐng)求嵌套的情況,代碼不夠直觀。

如果前后兩個(gè)請(qǐng)求不需要傳遞參數(shù)的情況下,那么后一個(gè)請(qǐng)求也需要前一個(gè)請(qǐng)求成功后再執(zhí)行下一步操作,這種情況下,那么也需要如上編寫代碼,導(dǎo)致代碼不夠直觀。

Promise 出現(xiàn)之后,代碼變成這樣:
2023前端面試上岸手冊(cè)——JavaScript部分

這樣代碼看起了就簡(jiǎn)潔了很多,解決了地獄回調(diào)的問題。

對(duì)async/await 的理解

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-X3jHJs2R-1682168150270)(media/image8.png)]async/await 其實(shí)是 Generator 的語法糖,它能實(shí)現(xiàn)的效果都能用 then 鏈來實(shí)現(xiàn),它是為優(yōu)化then 鏈而開發(fā)出來的。從字面上來看, async 是“異步”的簡(jiǎn)寫,await 則為等待,所以很好理解async 用于申明一個(gè) function 是異步的,而 await 用于等待一個(gè)異步方法執(zhí)行完成。當(dāng)然語法上強(qiáng)制規(guī)定 await 只能出現(xiàn)在asnyc 函數(shù)中,先來看看async 函數(shù)返回了什么:

2023前端面試上岸手冊(cè)——JavaScript部分
2023前端面試上岸手冊(cè)——JavaScript部分

所以,async 函數(shù)返回的是一個(gè) Promise 對(duì)象。async 函數(shù)(包含函數(shù)語句、函數(shù)表達(dá)式、Lambda 表達(dá)式)會(huì)返回一個(gè) Promise 對(duì)象,如果在函數(shù)中 return 一個(gè)直接量,async 會(huì)把這個(gè)直接量通過 Promise.resolve() 封裝成 Promise 對(duì)象。
async 函數(shù)返回的是一個(gè) Promise 對(duì)象,所以在最外層不能用 await 獲取其返回值的情況下,當(dāng)然應(yīng)該用原來的方式:then() 鏈來處理這個(gè) Promise 對(duì)象,就像這樣:
2023前端面試上岸手冊(cè)——JavaScript部分

那如果 async 函數(shù)沒有返回值,又該如何?很容易想到,它會(huì)返回 Promise.resolve(undefined)。

聯(lián)想一下 Promise 的特點(diǎn)——無等待,所以在沒有 await 的情況下執(zhí)行 async 函數(shù),它會(huì)立即執(zhí)行,返回一個(gè) Promise 對(duì)象,并且,絕不會(huì)阻塞后面的語句。這和普通返回 Promise 對(duì)象的函數(shù)并無二致。

注意:Promise.resolve(x) 可以看作是 new Promise(resolve => resolve(x)) 的簡(jiǎn)寫,可以用于快速封裝字面量對(duì)象或其他對(duì)象,將其封裝成 Promise 實(shí)例。

async/await 的優(yōu)勢(shì)

單一的 Promise 鏈并不能發(fā)現(xiàn) async/await 的優(yōu)勢(shì),但是,如果需要處理由多個(gè) Promise 組成的 then 鏈的時(shí)候,優(yōu)勢(shì)就能體現(xiàn)出來了(很有意思,Promise 通過 then 鏈來解決多層回調(diào)的問題,現(xiàn)在又用 async/await 來進(jìn)一步優(yōu)化它)。

假設(shè)一個(gè)業(yè)務(wù),分多個(gè)步驟完成,每個(gè)步驟都是異步的,而且依賴于上一個(gè)步驟的結(jié)果。仍然用 setTimeout 來模擬異步操作:
2023前端面試上岸手冊(cè)——JavaScript部分

現(xiàn)在用 Promise 方式來實(shí)現(xiàn)這三個(gè)步驟的處理:

2023前端面試上岸手冊(cè)——JavaScript部分

輸出結(jié)果 result 是 step3() 的參數(shù) 700 + 200 = 900。doIt() 順序執(zhí)行了三個(gè)步驟,一共用了 300 + 500 + 700 = 1500 毫秒,和 console.time()/console.timeEnd() 計(jì)算的結(jié)果一致。
如果用 async/await 來實(shí)現(xiàn)呢,會(huì)是這樣:
2023前端面試上岸手冊(cè)——JavaScript部分

結(jié)果和之前的 Promise 實(shí)現(xiàn)是一樣的,但是這個(gè)代碼看起來是不是清晰得多,幾乎跟同步代碼一樣

async/await 對(duì)比 Promise 的優(yōu)勢(shì)

  • 代碼讀起來更加同步,Promise 雖然擺脫了回調(diào)地獄,但是 then 的鏈?zhǔn)秸{(diào)?也會(huì)帶來額外的閱讀負(fù)擔(dān)

  • Promise 傳遞中間值?常麻煩,?async/await?乎是同步的寫法,?常優(yōu)雅

  • 錯(cuò)誤處理友好,async/await 可以?成熟的 try/catch,Promise 的錯(cuò)誤捕獲?常冗余

  • 調(diào)試友好,Promise 的調(diào)試很差,由于沒有代碼塊,你不能在?個(gè)返回表達(dá)式的箭頭函數(shù)中設(shè)置斷點(diǎn),如果你在?個(gè).then 代碼塊中使?調(diào)試器的步進(jìn)(step-over)功能,調(diào)試器并不會(huì)進(jìn)?后續(xù)的.then 代碼塊,因?yàn)檎{(diào)試器只能跟蹤同步代碼的每?步。

對(duì)象創(chuàng)建的方式有哪些?

一般使用字面量的形式直接創(chuàng)建對(duì)象,但是這種創(chuàng)建方式對(duì)于創(chuàng)建大量相似對(duì)象的時(shí)候,會(huì)產(chǎn)生大量的重復(fù)代碼。但 js 和一般的面向?qū)ο蟮恼Z言不同,在 ES6 之前它沒有類的概念。但是可以使用函數(shù)來進(jìn)行模擬,從而產(chǎn)生出可復(fù)用的對(duì)象創(chuàng)建方式,常見的有以下幾種:

  1. 第一種是工廠模式,工廠模式的主要工作原理是用函數(shù)來封裝創(chuàng)建對(duì)象的細(xì)節(jié),從而通過調(diào)用函數(shù)來達(dá)到復(fù)用的目的。但是它有一個(gè)很大的問題就是創(chuàng)建出來的對(duì)象無法和某個(gè)類型聯(lián)系起來,它只是簡(jiǎn)單的封裝了復(fù)用代碼,而沒有建立起對(duì)象和類型間的關(guān)系。

  2. 第二種是構(gòu)造函數(shù)模式。js 中每一個(gè)函數(shù)都可以作為構(gòu)造函數(shù),只要一個(gè)函數(shù)是通過 new 來調(diào)用的,那么就可以把它稱為構(gòu)造函數(shù)。執(zhí)行構(gòu)造函數(shù)首先會(huì)創(chuàng)建一個(gè)對(duì)象,然后將對(duì)象的原型指向構(gòu)造函數(shù)的 prototype 屬性,然后將執(zhí)行上下文中的 this 指向這個(gè)對(duì)象,最后再執(zhí)行整個(gè)函數(shù),如果返回值不是對(duì)象,則返回新建的對(duì)象。因?yàn)?this 的值指向了新建的對(duì)象,因此可以使用 this 給對(duì)象賦值。構(gòu)造函數(shù)模式相對(duì)于工廠模式的優(yōu)點(diǎn)是,所創(chuàng)建的對(duì)象和構(gòu)造函數(shù)建立起了聯(lián)系,因此可以通過原型來識(shí)別對(duì)象的類型。但是構(gòu)造函數(shù)存在一個(gè)缺點(diǎn)就是,造成了不必要的函數(shù)對(duì)象的創(chuàng)建,因?yàn)樵?js 中函數(shù)也是一個(gè)對(duì)象,因此如果對(duì)象屬性中如果包含函數(shù)的話,那么每次都會(huì)新建一個(gè)函數(shù)對(duì)象,浪費(fèi)了不必要的內(nèi)存空間,因?yàn)楹瘮?shù)是所有的實(shí)例都可以通用的。

  3. 第三種模式是原型模式,因?yàn)槊恳粋€(gè)函數(shù)都有一個(gè) prototype屬性,這個(gè)屬性是一個(gè)對(duì)象,它包含了通過構(gòu)造函數(shù)創(chuàng)建的所有實(shí)例都能共享的屬性和方法。因此可以使用原型對(duì)象來添加公用屬性和方法,從而實(shí)現(xiàn)代碼的復(fù)用。這種方式相對(duì)于構(gòu)造函數(shù)模式來說,解決了函數(shù)對(duì)象的復(fù)用問題。但是這種模式也存在一些問題,一個(gè)是沒有辦法通過傳入?yún)?shù)來初始化值,另一個(gè)是如果存在一個(gè)引用類型如 Array 這樣的值,那么所有的實(shí)例將共享一個(gè)對(duì)象,一個(gè)實(shí)例對(duì)引用類型值的改變會(huì)影響所有的實(shí)例。

  4. 第四種模式是組合使用構(gòu)造函數(shù)模式和原型模式,這是創(chuàng)建自定義類型的最常見方式。因?yàn)闃?gòu)造函數(shù)模式和原型模式分開使用都存在一些問題,因此可以組合使用這兩種模式,通過構(gòu)造函數(shù)來初始化對(duì)象的屬性,通過原型對(duì)象來實(shí)現(xiàn)函數(shù)方法的復(fù)用。這種方法很好的解決了兩種模式單獨(dú)使用時(shí)的缺點(diǎn),但是有一點(diǎn)不足的就是,因?yàn)槭褂昧藘煞N不同的模式,所以對(duì)于代碼的封裝性不夠好。

  5. 第五種模式是動(dòng)態(tài)原型模式,這一種模式將原型方法賦值的創(chuàng)建過程移動(dòng)到了構(gòu)造函數(shù)的內(nèi)部,通過對(duì)屬性是否存在的判斷,可以實(shí)現(xiàn)僅在第一次調(diào)用函數(shù)時(shí)對(duì)原型對(duì)象賦值一次的效果。這一種方式很好地對(duì)上面的混合模式進(jìn)行了封裝。

  6. 第六種模式是寄生構(gòu)造函數(shù)模式,這一種模式和工廠模式的實(shí)現(xiàn)基本相同,我對(duì)這個(gè)模式的理解是,它主要是基于一個(gè)已有的類型,在實(shí)例化時(shí)對(duì)實(shí)例化的對(duì)象進(jìn)行擴(kuò)展。這樣既不用修改原來的構(gòu)造函數(shù),也達(dá)到了擴(kuò)展對(duì)象的目的。它的一個(gè)缺點(diǎn)和工廠模式一樣,無法實(shí)現(xiàn)對(duì)象的識(shí)別。

對(duì)象繼承的方式有哪些?

  1. 第一種是以原型鏈的方式來實(shí)現(xiàn)繼承,但是這種實(shí)現(xiàn)方式存在的缺點(diǎn)是,在包含有引用類型的數(shù)據(jù)時(shí),會(huì)被所有的實(shí)例對(duì)象所共享,容易造成修改的混亂。還有就是在創(chuàng)建子類型的時(shí)候不能向超類型傳遞參數(shù)。

  2. 第二種方式是使用借用構(gòu)造函數(shù)的方式,這種方式是通過在子 類型的函數(shù)中調(diào)用超類型的構(gòu)造函數(shù)來實(shí)現(xiàn)的,這一種方法解決了不 能向超類型傳遞參數(shù)的缺點(diǎn),但是它存在的一個(gè)問題就是無法實(shí)現(xiàn)函 數(shù)方法的復(fù)用,并且超類型原型定義的方法子類型也沒有辦法訪問到。

  3. 第三種方式是組合繼承,組合繼承是將原型鏈和借用構(gòu)造函數(shù)組合起來使用的一種方式。通過借用構(gòu)造函數(shù)的方式來實(shí)現(xiàn)類型的屬性的繼承,通過將子類型的原型設(shè)置為超類型的實(shí)例來實(shí)現(xiàn)方法的繼承。這種方式解決了上面的兩種模式單獨(dú)使用時(shí)的問題,但是由于我們是以超類型的實(shí)例來作為子類型的原型,所以調(diào)用了兩次超類的構(gòu)造函數(shù),造成了子類型的原型中多了很多不必要的屬性。

  4. 第四種方式是原型式繼承,原型式繼承的主要思路就是基于已有的對(duì)象來創(chuàng)建新的對(duì)象,實(shí)現(xiàn)的原理是,向函數(shù)中傳入一個(gè)對(duì)象,然后返回一個(gè)以這個(gè)對(duì)象為原型的對(duì)象。這種繼承的思路主要不是為了實(shí)現(xiàn)創(chuàng)造一種新的類型,只是對(duì)某個(gè)對(duì)象實(shí)現(xiàn)一種簡(jiǎn)單繼承,ES5中定義的 Object.create() 方法就是原型式繼承的實(shí)現(xiàn)。缺點(diǎn)與原型鏈方式相同。

  5. 第五種方式是寄生式繼承,寄生式繼承的思路是創(chuàng)建一個(gè)用于封裝繼承過程的函數(shù),通過傳入一個(gè)對(duì)象,然后復(fù)制一個(gè)對(duì)象的副本,然后對(duì)象進(jìn)行擴(kuò)展,最后返回這個(gè)對(duì)象。這個(gè)擴(kuò)展的過程就可以理解是一種繼承。這種繼承的優(yōu)點(diǎn)就是對(duì)一個(gè)簡(jiǎn)單對(duì)象實(shí)現(xiàn)繼承,如果這個(gè)對(duì)象不是自定義類型時(shí)。缺點(diǎn)是沒有辦法實(shí)現(xiàn)函數(shù)的復(fù)用。

  6. 第六種方式是寄生式組合繼承,組合繼承的缺點(diǎn)就是使用超類型的實(shí)例做為子類型的原型,導(dǎo)致添加了不必要的原型屬性。寄生式組合繼承的方式是使用超類型的原型的副本來作為子類型的原型,這樣就避免了創(chuàng)建不必要的屬性。

哪些情況會(huì)導(dǎo)致內(nèi)存泄漏

以下四種情況會(huì)造成內(nèi)存的泄漏:

  1. 意外的全局變量:由于使用未聲明的變量,而意外的創(chuàng)建了一個(gè)全局變量,而使這個(gè)變量一直留在內(nèi)存中無法被回收。

  2. 被遺忘的計(jì)時(shí)器或回調(diào)函數(shù):設(shè)置了 setInterval 定時(shí)器,而忘記取消它,如果循環(huán)函數(shù)有對(duì)外部變量的引用的話,那么這個(gè)變量會(huì)被一直留在內(nèi)存中,而無法被回收。

  3. 脫離 DOM 的引用:獲取一個(gè) DOM 元素的引用,而后面這個(gè)元素被刪除,由于一直保留了對(duì)這個(gè)元素的引用,所以它也無法被回收。

  4. 閉包:不合理的使用閉包,從而導(dǎo)致某些變量一直被留在內(nèi)存當(dāng)中。

一天時(shí)間系列文章是博主精心整理的面試熱點(diǎn)問題和難點(diǎn)問題,吸收了大量的技術(shù)博客與面試文章,總結(jié)多年的面試經(jīng)歷,帶你快速并高效地審視前端面試知識(shí)。直擊技術(shù)痛點(diǎn),主動(dòng)出擊,精密打擊,這才是面試拿到高薪的秘訣!文章來源地址http://www.zghlxwxcb.cn/news/detail-431292.html

  • 本系列訂閱 一天時(shí)間迅速準(zhǔn)備前端面試(高薪精品)–歡迎訂閱

到了這里,關(guān)于2023前端面試上岸手冊(cè)——JavaScript部分的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Java基礎(chǔ)部分面試題(2023最新)

    Java基礎(chǔ)部分面試題(2023最新)

    1. 談?wù)勀銓?duì) Java 平臺(tái)的理解? ① 平臺(tái)無關(guān)性 (一次編譯到處運(yùn)行) ② GC (垃圾自動(dòng)回收機(jī)制,不像C++那樣需要手動(dòng)去釋放堆內(nèi)存) ③ 語言特性 (泛型、反射、Lambda 表達(dá)式) ④ 面向?qū)ο?(封裝、繼承、多態(tài)) ⑤ 類庫(kù) (集合、并發(fā)庫(kù)、網(wǎng)絡(luò)庫(kù)等、IO、NIO) ⑥ 異常處理

    2024年02月01日
    瀏覽(22)
  • 阿里巴巴 2023 版(Java 崗)面試突擊手冊(cè),Github 已標(biāo)星42K

    阿里巴巴 2023 版(Java 崗)面試突擊手冊(cè),Github 已標(biāo)星42K

    程序員作為一個(gè)自帶“高薪多金”標(biāo)簽的職業(yè),收入要高于市場(chǎng)的平均薪資,即便是在 2023 年,程序員的薪資依然保持居高不下。 據(jù)拉勾發(fā)布的《2022 程序員群體職場(chǎng)洞察報(bào)告》顯示計(jì)算機(jī)專業(yè)的應(yīng)屆本科生起薪普遍高于其他職業(yè)的平均薪資水平。77%的本科畢業(yè)生起薪超過 1

    2024年02月09日
    瀏覽(15)
  • 全面上新!阿里 2023 版(Java 崗)面試突擊手冊(cè),Github 已標(biāo)星 37K

    全面上新!阿里 2023 版(Java 崗)面試突擊手冊(cè),Github 已標(biāo)星 37K

    程序員面試背八股,幾乎已經(jīng)是互聯(lián)網(wǎng)不可逆的一個(gè)形式了。自從面試**八股文火了之后,網(wǎng)上出現(xiàn)了不少 Java 相關(guān)的面試題,很多朋友盲目收集背誦,**但網(wǎng)上大部分的面試題,大多存在這幾個(gè)問題: 第一,未必系統(tǒng)全面;第二,光有題沒有答案解析;第三雖然資料不錯(cuò),

    2023年04月11日
    瀏覽(22)
  • 這套【阿里-服務(wù)端開發(fā)與面試知識(shí)手冊(cè)】2023年了不會(huì)還有人沒看過吧

    這套【阿里-服務(wù)端開發(fā)與面試知識(shí)手冊(cè)】2023年了不會(huì)還有人沒看過吧

    整篇 128362字 ,300+頁(yè)的筆記涵蓋**【Java體系】和【架構(gòu)能力】 兩大部分 包含 網(wǎng)絡(luò)和操作系統(tǒng)基礎(chǔ)、JVM、多線程、Spring、Netty主流框架 等重點(diǎn)知識(shí),以及 結(jié)合實(shí)踐給出各類難點(diǎn)問題和解決方案**等,不管你是正在學(xué)習(xí)Java還是已經(jīng)工作了都是對(duì)你的技術(shù)提升有非常大的好處,不

    2024年02月05日
    瀏覽(25)
  • 前端面試的性能優(yōu)化部分(3)每篇10題

    優(yōu)化移動(dòng)端網(wǎng)頁(yè)的性能是提升用戶體驗(yàn)、降低用戶流失的關(guān)鍵。以下是一些優(yōu)化移動(dòng)端網(wǎng)頁(yè)性能的常見方法: 壓縮和合并資源: 壓縮 CSS、JavaScript 和圖片等靜態(tài)資源,減少文件大小,同時(shí)合并多個(gè)文件,減少請(qǐng)求次數(shù),加快頁(yè)面加載速度。 使用響應(yīng)式圖片: 使用不同尺寸的

    2024年02月14日
    瀏覽(21)
  • 前端面試的性能優(yōu)化部分(1)每篇10題

    懶加載(Lazy Loading)是一種優(yōu)化技術(shù),它用于延遲加載頁(yè)面資源,只在需要時(shí)才加載特定的內(nèi)容,而不是在頁(yè)面初始加載時(shí)一次性加載所有資源。懶加載的目的是提高頁(yè)面加載速度和性能,尤其對(duì)于單頁(yè)應(yīng)用(SPA)或包含大量圖片和其他資源的網(wǎng)頁(yè)來說尤為重要。 懶加載可以

    2024年02月14日
    瀏覽(23)
  • 前端面試的性能優(yōu)化部分(2)每篇10題

    常見的圖片格式有 JPEG、PNG、GIF、WebP 和 SVG,它們各有適用的使用場(chǎng)景: JPEG (Joint Photographic Experts Group): 使用場(chǎng)景:適用于照片和真實(shí)場(chǎng)景的圖片,特別是色彩豐富和漸變豐富的圖像。 優(yōu)點(diǎn):壓縮率高,圖片文件較小,保持較高的圖像質(zhì)量。 缺點(diǎn):不支持透明度。 PNG (Por

    2024年02月15日
    瀏覽(30)
  • 2023最新版Java 面試突擊手冊(cè)開源(涵蓋 p5-p8 技術(shù)棧)

    2023最新版Java 面試突擊手冊(cè)開源(涵蓋 p5-p8 技術(shù)棧)

    前言: 本文收集整理了各大廠常見面試題N道,你想要的這里都有內(nèi)容涵蓋:Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、Redis、MySQL、Spring、Spring Boot、Spring Cloud、RabbitMQ、Kafka、Linux 等技術(shù)棧,希望大家都能找到適合自己的公司,開開心心的擼代碼。 目錄: 看面試題可以是

    2024年02月08日
    瀏覽(35)
  • JavaScript最新面試題合集(2023年)

    閉包:就是能夠讀取外層函數(shù)內(nèi)部變量的函數(shù)。 閉包需要滿足三個(gè)條件: 訪問所在作用域; 函數(shù)嵌套; 在所在作用域外被調(diào)用 。 優(yōu)點(diǎn): 可以重復(fù)使用變量,并且不會(huì)造成變量污染 。 缺點(diǎn): 會(huì)引起內(nèi)存泄漏 使用閉包的注意點(diǎn): 由于閉包會(huì)使得函數(shù)中的變量都被保存在內(nèi)

    2024年02月07日
    瀏覽(24)
  • 前端面試問題-JavaScript

    1 閉包 閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù) 閉包是指有權(quán)訪問另?個(gè)函數(shù)作?域中變量的函數(shù),創(chuàng)建閉包的最常?的?式就是在?個(gè)函數(shù)內(nèi)創(chuàng)建另?個(gè)函數(shù),通過另?個(gè)函數(shù)訪問這個(gè)函數(shù)的局部變量,利?閉包可以突破作?鏈域 閉包的特性: 函數(shù)內(nèi)再嵌套函數(shù) 內(nèi)部函

    2024年02月15日
    瀏覽(34)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包