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

【自看】2023前端面試上岸手冊——JavaScript

這篇具有很好參考價值的文章主要介紹了【自看】2023前端面試上岸手冊——JavaScript。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  1. typeof
    【自看】2023前端面試上岸手冊——JavaScript

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

  1. instanceof

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

  1. Object.prototype.toString.call()

Object.prototype.toString.call() 使用 Object 對象的原型方法 toString 來判斷數(shù)據(jù)類型:
【自看】2023前端面試上岸手冊——JavaScript

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

null 和undefined 區(qū)別

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

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

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

如何獲取安全的 undefined 值?

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

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

使用雙等號(==)進行相等判斷時,如果兩邊的類型不一致,則會進行強制類型轉(zhuǎn)化后再進行比較。

使用三等號(===)進行相等判斷時,如果兩邊的類型不一致時,不會做強制類型準(zhǔn)換,直接返回 false。

使用 Object.is 來進行相等判斷時,一般情況下和三等號的判斷相同,它處理了一些特殊的情況,比如 -0 和 +0 不再相等,兩個 NaN是相等的。

什么是 JavaScript 中的包裝類型?

在 JavaScript 中,基本類型是沒有屬性和方法的,但是為了便于操作基本類型的值,在調(diào)用基本類型的屬性或方法時 JavaScript 會在后臺隱式地將基本類型的值轉(zhuǎn)換為對象,如:
【自看】2023前端面試上岸手冊——JavaScript

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

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

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

看看如下代碼會打印出什么:

【自看】2023前端面試上岸手冊——JavaScript

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

為什么會有 BigInt 的提案?

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

如何判斷一個對象是空對象

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

【自看】2023前端面試上岸手冊——JavaScript

使用ES6 新增的方法Object.keys()來判斷:
【自看】2023前端面試上岸手冊——JavaScript

const 對象的屬性可以修改嗎

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

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

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

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

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

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

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

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

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

擴展運算符的作用及使用場景

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

【自看】2023前端面試上岸手冊——JavaScript

上述方法實際上等價于:
【自看】2023前端面試上岸手冊——JavaScript

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

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

需要注意:擴展運算符對對象實例的拷貝屬于淺拷貝。

  1. 數(shù)組擴展運算符

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

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

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

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

【自看】2023前端面試上岸手冊——JavaScript

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

【自看】2023前端面試上岸手冊——JavaScript
要記住:擴展運算符(…)用于取出參數(shù)對象中的所有可遍歷屬性,拷貝到當(dāng)前對象之中,這里參數(shù)對象是個數(shù)組,數(shù)組里面的所有對象都是基礎(chǔ)數(shù)據(jù)類型,將所有基礎(chǔ)數(shù)據(jù)類型重新拷貝到新的數(shù)組中。

合并數(shù)組

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

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

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

const [...rest, last] = [1, 2, 3, 4, 5];// 報錯
const [first, ..rest, last]=[1, 2, 3, 4, 5]; // 報錯

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

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

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

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

【自看】2023前端面試上岸手冊——JavaScript

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

使用Math 函數(shù)獲取數(shù)組中特定的值
【自看】2023前端面試上岸手冊——JavaScript

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

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

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

【自看】2023前端面試上岸手冊——JavaScript

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

【自看】2023前端面試上岸手冊——JavaScript

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

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

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

【自看】2023前端面試上岸手冊——JavaScript

對JSON 的理解

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

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

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

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

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

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

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

一般有以下幾種方式:

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

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

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

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

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

什么是 DOM 和 BOM?

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

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

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

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

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

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

對AJAX 的理解,實現(xiàn)一個 AJAX 請求

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

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

創(chuàng)建一個 XMLHttpRequest 對象。

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

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

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

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

尾調(diào)用指的是函數(shù)的最后一步調(diào)用另一個函數(shù)。代碼執(zhí)行是基于執(zhí)行棧的,所以當(dāng)在一個函數(shù)里調(diào)用另一個函數(shù)時,會保留當(dāng)前的執(zhí)行上下文,然后再新建另外一個執(zhí)行上下文加入棧中。使用尾調(diào)用的話,因為已經(jīng)是函數(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 是對模塊的淺拷?,ES6 Module 是對模塊的引?,即 ES6 Module 只存只讀,不能改變其值,也就是指針指向不能變,類似 const;

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

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

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

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

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

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

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

AJAX

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

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

Fetch

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

fetch 的優(yōu)點:

  • 語法簡潔,更加語義化

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

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

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

fetch 的缺點:

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

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

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

Axios

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

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

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

  • 支持Promise API

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

  • 對請求和返回進行轉(zhuǎn)化

  • 取消請求

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

  • 客戶端支持抵御XSRF 攻擊

對原型、原型鏈的理解

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

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

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

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

【自看】2023前端面試上岸手冊——JavaScript

對作用域、作用域鏈的理解

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

全局作用域

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

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

  • 所有window 對象的屬性擁有全局作用域

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

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

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

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

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

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

作用域鏈:

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

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

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

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

對this 對象的理解

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

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

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

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

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

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

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

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

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

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

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

JavaScript 中的異步機制可以分為以下幾種:

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

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

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

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

對Promise 的理解

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

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

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

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

  1. Promise 的實例有兩個過程:

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

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

Promise 的特點:

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

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

Promise 的缺點:

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

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

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

總結(jié):

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

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

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

Promise 解決了什么問題

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

上面的代碼有如下缺點:

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

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

Promise 出現(xiàn)之后,代碼變成這樣:
【自看】2023前端面試上岸手冊——JavaScript

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

對async/await 的理解

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

【自看】2023前端面試上岸手冊——JavaScript
【自看】2023前端面試上岸手冊——JavaScript

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

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

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

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

async/await 的優(yōu)勢

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

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

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

【自看】2023前端面試上岸手冊——JavaScript

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

對象繼承的方式有哪些?

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

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

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

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

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

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

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

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

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

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

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

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

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

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

到了這里,關(guān)于【自看】2023前端面試上岸手冊——JavaScript的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

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

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

相關(guān)文章

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

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

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

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

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

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

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

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

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

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

    2023最新版Java 面試突擊手冊開源(涵蓋 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ù)。 閉包需要滿足三個條件: 訪問所在作用域; 函數(shù)嵌套; 在所在作用域外被調(diào)用 。 優(yōu)點: 可以重復(fù)使用變量,并且不會造成變量污染 。 缺點: 會引起內(nèi)存泄漏 使用閉包的注意點: 由于閉包會使得函數(shù)中的變量都被保存在內(nèi)

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

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

    2024年02月15日
    瀏覽(34)
  • 前端面試題---->JavaScript

    前端面試題---->JavaScript

    原因: 當(dāng)使用const聲明一個對象或數(shù)組時,實際上是保證了對象或數(shù)組的引用不會被修改,但對象或數(shù)組本身的屬性或元素是可以被修改的。這是因為const只能保證指向的內(nèi)存地址不變,但并不保證內(nèi)存地址指向的內(nèi)容不變,而基本類型的變量在內(nèi)存中存儲的是值本身,而不

    2024年03月27日
    瀏覽(32)
  • 前端JavaScript面試100問(上)

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

    2024年02月15日
    瀏覽(40)
  • web前端Javascript—7道關(guān)于前端的面試題

    本文主要是web前端Javascript—的面試題,附上相關(guān)問題以及解決答案,希望對大家web前端Javascript閉包的學(xué)習(xí)有所幫助。 每個JavaScript 程序員都必須知道閉包是什么。在 JavaScript 面試中,你很可能會被問到的問題 以下是 7 個有關(guān) JavaScript的面試題,比較有挑戰(zhàn)性。不要查看答案

    2024年02月03日
    瀏覽(98)
  • 【直接收藏】前端JavaScript面試100問(中)

    1、https協(xié)議需要到ca申請證書,一般免費證書較少,因而需要一定費用。 2、http是超文本傳輸協(xié)議,信息是明文傳輸,https則是具有安全性的ssl加密傳輸協(xié)議。 3、http和https使用的是完全不同的連接方式,用的端口也不一樣,前者是80,后者是443。 4、http的連接很簡單,是無狀

    2024年02月08日
    瀏覽(22)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包