JS核心知識點之箭頭函數(shù)與this詳細解析
一.數(shù)組去重的方式有那些?
數(shù)組去重的核心是篩選出數(shù)組中唯一不重復的元素,推薦優(yōu)先使用ES6,代碼簡潔,性能優(yōu)異
1.Set配合擴展運算符
Set 是 ES6 提供的不允許重復值的集合,配合擴展運算符 /Array.from 可快速去重。

2.利用indexOf/includes 遍歷判斷
遍歷數(shù)組,用 indexOf(返回 - 1 表示不存在)或 includes(返回布爾值)判斷元素是否已存在于新數(shù)組,不存在加入新數(shù)組,存在則不加入

還可以使用forEach+includes實現(xiàn)

3.利用filter + indexOf/Set(篩選式去重)

二.講述一下手寫深拷貝的邏輯
核心就 3 步,抓住本質即可:
- 判斷類型:如果是基本類型 /
null,直接返回(無需拷貝); - 創(chuàng)建容器:區(qū)分數(shù)組和普通對象,創(chuàng)建對應的空新對象 / 新數(shù)組;
- 遞歸拷貝:遍歷原數(shù)據(jù)的屬性 / 元素,遞歸調用深拷貝,賦值給新容器。
滿足絕大多數(shù)簡單場景簡化版手寫代碼

以下是測試

總結:
- 簡化版深拷貝的核心是「類型判斷 + 遞歸拷貝」,3 步即可實現(xiàn)普通場景的深拷貝需求。
- 基礎簡化版足以應對日常大部分簡單場景(基本類型、普通對象、數(shù)組)。
三.this指向的理解
1.this的核心本質:this 是 JavaScript 中的關鍵字,它的指向不是在定義時確定的,而是在函數(shù)調用時確定的(即 “調用時綁定”)。簡單說:this 指向的是「調用函數(shù)的那個對象」,誰調用函數(shù),this 就指向誰。
2.this 的 4 種核心綁定規(guī)則(從常用到特殊):
1.默認綁定(獨立函數(shù)調用)
當函數(shù)獨立調用(沒有明確的調用對象)時,this 指向全局對象
瀏覽器環(huán)境:全局對象是 window。
Node.js 環(huán)境:全局對象是 global。
嚴格模式(use strict):默認綁定的 this 是 undefined

2.隱式綁定
當函數(shù)作為對象的方法被調用時,this 指向這個調用函數(shù)的對象(即 “點前面的對象”)

3. 顯式綁定(手動指定 this)
通過 call、apply、bind 方法,可以手動指定 this 的指向,不受調用方式影響。
call/apply:立即執(zhí)行函數(shù),第一個參數(shù)是 this 指向的對象
bind:返回一個新函數(shù)(不立即執(zhí)行),新函數(shù)的 this 永久綁定為第一個參數(shù)

4.new綁定
當函數(shù)作為構造函數(shù)(用 new 關鍵字調用)時,this 指向新建的實例對象。

5.特殊場景 箭頭函數(shù)
箭頭函數(shù)沒有自己的 this,它的 this 是繼承自外層作用域的 this(定義時確定,而非調用時),不受綁定規(guī)則影響。

總結:
this指向是「調用時確定」的,核心原則是 “誰調用,指向誰”(箭頭函數(shù)除外)。- 核心綁定規(guī)則:默認綁定(全局 /undefined)、隱式綁定(對象方法)、顯式綁定(call/apply/bind)、new 綁定(構造函數(shù)實例)。
- 箭頭函數(shù)無自身
this,繼承外層作用域的this(定義時確定)。 - 綁定優(yōu)先級:
new 綁定 > 顯式綁定 > 隱式綁定 > 默認綁定。
四. 如何使用promise封裝原生ajax?
封裝思路
- 創(chuàng)建 Promise 實例:用 Promise 包裹 AJAX 邏輯,成功時調用
resolve,失敗時調用reject。 - 創(chuàng)建 XHR 對象:通過
new XMLHttpRequest()生成 AJAX 核心對象。 - 配置請求:調用
open()方法設置請求方式、URL、是否異步。 - 處理響應:監(jiān)聽
onload事件(請求完成),判斷響應狀態(tài)碼,成功則傳遞響應數(shù)據(jù),失敗則傳遞錯誤信息。 - 處理網絡錯誤:監(jiān)聽
onerror事件(網絡異常),觸發(fā)reject。 - 發(fā)送請求:調用
send()方法,攜帶請求體(POST 請求時使用)。 - 可選配置:設置請求頭(如 POST 請求的
Content-Type)。
注意事項
- 跨域問題:原生 AJAX 受同源策略限制,跨域需后端配置 CORS 或使用 JSONP(本封裝不支持 JSONP)。
- 請求體格式:如果需要提交表單數(shù)據(jù)(
application/x-www-form-urlencoded),需將data轉為key=value格式,并對應設置請求頭。 - 兼容性:
XMLHttpRequest支持 IE7 及以上瀏覽器,如需兼容更低版本,需使用ActiveXObject(極少場景需要)。
總結
- 核心是用 Promise 包裹原生 AJAX 流程,成功調用
resolve、失敗調用reject,實現(xiàn)異步流程的優(yōu)雅管理。 - 封裝關鍵步驟:創(chuàng)建 XHR 對象 → 配置請求 → 設置請求頭 → 處理響應 / 錯誤 → 發(fā)送請求。
- 使用時通過
then接收成功數(shù)據(jù)、catch捕獲錯誤,支持 GET/POST 等常見請求方式,可靈活配置參數(shù)。 - 該封裝支持 JSON 格式請求 / 響應,自動拼接 GET 參數(shù),具備默認配置,可直接用于日常簡單接口請求。
五. 箭頭函數(shù)和普通函數(shù)的區(qū)別?
箭頭函數(shù)是ES6新增的函數(shù)語法,與普通函數(shù)(ES5函數(shù))相比,核心區(qū)別體現(xiàn)在6個方面,具體如下:
this指向不同(核心區(qū)別):普通函數(shù)的this指向動態(tài)變化,取決于調用方式(全局調用指向window/global,對象方法調用指向該對象,構造函數(shù)調用指向實例,call/apply/bind可手動改變this);箭頭函數(shù)沒有自己的this,其this繼承自外層作用域的this,且一旦確定無法改變(call/apply/bind對其this無效,僅能傳遞參數(shù))。
構造函數(shù)特性:普通函數(shù)可作為構造函數(shù)使用new關鍵字創(chuàng)建實例(此時this指向實例);箭頭函數(shù)不能作為構造函數(shù),使用new調用會拋出TypeError錯誤(因箭頭函數(shù)沒有prototype屬性)。
arguments對象:普通函數(shù)內部有arguments對象,用于存儲實參列表(類數(shù)組,可通過Array.from轉換為數(shù)組);箭頭函數(shù)沒有arguments對象,若需獲取實參,可使用剩余參數(shù)(...args)。
prototype屬性:普通函數(shù)有prototype屬性,其原型上的方法可被實例繼承;箭頭函數(shù)沒有prototype屬性。
函數(shù)體簡化:箭頭函數(shù)支持簡潔語法,若函數(shù)體只有一條return語句,可省略大括號和return關鍵字(如(a,b) => a+b);若返回對象,需用小括號包裹(如(a,b) => ({name: a, age: b}));普通函數(shù)無此簡化語法。
不能用作Generator函數(shù):箭頭函數(shù)不能使用yield關鍵字,無法作為Generator函數(shù);普通函數(shù)可以。
六. 瀏覽器環(huán)境中事件循環(huán)的理解?
瀏覽器環(huán)境的事件循環(huán)(Event Loop)是JavaScript解決單線程執(zhí)行阻塞問題的核心機制,其本質是協(xié)調調用棧、宏任務隊列(Macro Task Queue)和微任務隊列(Micro Task Queue)的執(zhí)行順序,確保異步任務有序執(zhí)行,具體邏輯和流程如下:
核心前提:JavaScript是單線程語言,同一時間只能執(zhí)行一個任務,若直接執(zhí)行異步任務(如定時器、網絡請求、DOM事件)會導致阻塞,因此需要事件循環(huán)機制區(qū)分同步/異步任務的執(zhí)行時機。
關鍵組件:
調用棧:用于執(zhí)行同步任務的棧結構,遵循“先進后出”原則,函數(shù)調用時入棧,執(zhí)行完畢后出棧;
宏任務隊列:存儲宏任務(異步任務的一種),常見類型有:script(整體代碼)、setTimeout/setInterval、I/O操作(如文件讀?。?、UI渲染、requestAnimationFrame;
微任務隊列:存儲微任務(異步任務的一種),常見類型有:Promise.then/catch/finally、MutationObserver、process.nextTick(Node環(huán)境特有,瀏覽器無)、queueMicrotask。
執(zhí)行流程(核心規(guī)則):
1. 先執(zhí)行調用棧中的同步任務,直到調用棧為空;
2. 執(zhí)行微任務隊列中的所有微任務(按隊列順序依次執(zhí)行),直到微任務隊列為空;
3. 執(zhí)行一次宏任務隊列中的第一個宏任務,將其推入調用棧執(zhí)行,執(zhí)行完畢后調用棧為空;
4. 重復步驟2-3,形成循環(huán)(即“事件循環(huán)”)。
注意點:
整體script代碼屬于宏任務,優(yōu)先執(zhí)行;
微任務的執(zhí)行優(yōu)先級高于宏任務,每次執(zhí)行完一個宏任務后,必須清空所有微任務再執(zhí)行下一個宏任務;
UI渲染任務在微任務隊列清空后、下一個宏任務執(zhí)行前進行(不同瀏覽器可能有細微差異,但核心邏輯一致)。
七. === 和 Object.is() 的區(qū)別?
===(嚴格相等運算符)和Object.is()都是JavaScript中用于判斷兩個值是否“嚴格相等”的方式,但二者在處理特殊值(如NaN、0和-0)時存在差異,核心區(qū)別如下:
核心一致點:均不進行類型轉換,直接比較值的類型和具體值,若類型不同則直接返回false(這一點區(qū)別于==,==會先進行類型轉換再比較值)。
關鍵差異點(特殊值處理):
處理NaN:===認為NaN !== NaN(這是JavaScript的設計缺陷,NaN與任何值都不相等,包括自身);而Object.is(NaN, NaN)返回true(修復了NaN的比較問題)。
處理0和-0:===認為+0 === -0(因為二者在數(shù)值上等價);而Object.is(+0, -0)返回false(因為+0和-0在底層存儲和某些運算場景中存在差異,如1/+0=+Infinity,1/-0=-Infinity)。
普通值比較一致性:對于除NaN、+0、-0之外的普通值,二者結果完全一致。例如:
5 === 5 → true;Object.is(5,5) → true;
'5' === 5 → false;Object.is('5',5) → false;
null === undefined → false;Object.is(null, undefined) → false。
總結:Object.is()可以理解為“更嚴格的===”,它修正了===在NaN和+0/-0比較上的不合理之處,更符合直覺上的“值相等”判斷。
八. promise的理解?
Promise是ES6引入的異步編程解決方案,用于解決傳統(tǒng)回調函數(shù)(回調地獄)的問題,其本質是一個狀態(tài)容器,存儲著異步操作的結果(未完成/已完成/已失敗),并提供統(tǒng)一的API供開發(fā)者處理異步結果,核心特性和用法如下:
核心定義:Promise是一個構造函數(shù),可通過new Promise((resolve, reject) => { ... })創(chuàng)建實例,接收一個“執(zhí)行器函數(shù)”作為參數(shù),執(zhí)行器函數(shù)立即執(zhí)行,內部包含異步操作邏輯。
三個狀態(tài)(不可逆):注意:狀態(tài)一旦從pending轉為fulfilled或rejected,就無法再改變。
pending(等待態(tài)):初始狀態(tài),異步操作未完成;
fulfilled(成功態(tài)):異步操作完成,調用resolve()后從pending轉為fulfilled,狀態(tài)固定;
rejected(失敗態(tài)):異步操作失敗,調用reject()后從pending轉為rejected,狀態(tài)固定。
核心方法(原型方法):
then():接收兩個可選參數(shù)(成功回調、失敗回調),用于處理fulfilled和rejected狀態(tài)的結果;then()方法返回一個新的Promise實例,因此支持鏈式調用(解決回調地獄的核心);
catch():專門處理rejected狀態(tài)的結果,等價于then(null, 失敗回調);通常用于鏈式調用的末尾,統(tǒng)一捕獲前面所有異步操作的錯誤;
finally():無論Promise狀態(tài)是fulfilled還是rejected,都會執(zhí)行的回調;finally()返回一個新的Promise,且回調函數(shù)不接收任何參數(shù)(無法獲取異步結果),主要用于執(zhí)行清理操作(如關閉加載動畫)。
靜態(tài)方法(工具方法):
Promise.resolve(value):快速創(chuàng)建一個fulfilled狀態(tài)的Promise,value為成功結果;若value本身是Promise,則直接返回該Promise;
Promise.reject(reason):快速創(chuàng)建一個rejected狀態(tài)的Promise,reason為失敗原因;
Promise.all(iterable):接收一個可迭代對象(如數(shù)組),包含多個Promise;只有所有Promise都變?yōu)閒ulfilled,才返回fulfilled狀態(tài)的Promise(結果為所有Promise成功結果的數(shù)組);只要有一個Promise變?yōu)閞ejected,立即返回rejected狀態(tài)的Promise(結果為第一個失敗的原因);
Promise.race(iterable):接收可迭代對象,返回一個新Promise;只要有一個Promise狀態(tài)改變(fulfilled或rejected),就立即返回該狀態(tài)的結果(“競速”機制);
Promise.allSettled(iterable):接收可迭代對象,等待所有Promise都完成(無論成功或失敗)后,返回fulfilled狀態(tài)的Promise,結果為每個Promise的狀態(tài)和結果組成的數(shù)組(解決了Promise.all()一個失敗就整體失敗的問題);
Promise.any(iterable):接收可迭代對象,只要有一個Promise變?yōu)閒ulfilled,就返回fulfilled狀態(tài)的結果;只有所有Promise都變?yōu)閞ejected,才返回rejected狀態(tài)的Promise(與Promise.all()相反)。
核心優(yōu)勢:解決回調地獄(回調嵌套過深導致的代碼可讀性差、維護困難),通過鏈式調用將異步操作線性化;統(tǒng)一異步操作的錯誤處理機制(catch()統(tǒng)一捕獲)。
注意點:Promise一旦創(chuàng)建,執(zhí)行器函數(shù)立即執(zhí)行,無法中途取消;若未添加catch()捕獲錯誤,失敗狀態(tài)的Promise會拋出未捕獲錯誤,影響程序執(zhí)行。
九. 遞歸函數(shù)的理解?
遞歸函數(shù)是指在函數(shù)內部直接或間接調用自身的函數(shù),是一種常用的編程思想,核心用于將復雜的大問題拆解為與原問題結構相似的小問題,通過解決小問題最終解決大問題,其核心要素和注意事項如下:
核心組成(兩個必要條件):
遞歸終止條件(基線條件):函數(shù)必須有一個明確的終止條件,當滿足該條件時停止調用自身,否則會導致無限遞歸(棧溢出錯誤,如Maximum call stack size exceeded);
遞歸遞推條件(遞歸步驟):函數(shù)在內部調用自身時,必須將問題規(guī)模縮?。磦鬟f的參數(shù)更接近終止條件),確保最終能觸發(fā)終止條件。
執(zhí)行原理:遞歸函數(shù)的執(zhí)行依賴調用棧,每次調用自身時,會將當前函數(shù)的執(zhí)行上下文(參數(shù)、局部變量、執(zhí)行位置)壓入調用棧;當觸發(fā)終止條件后,函數(shù)開始逐步返回,同時從調用棧中彈出執(zhí)行上下文,依次執(zhí)行剩余邏輯。
典型應用場景:
數(shù)學問題:計算階乘(n! = n × (n-1) × ... × 1)、斐波那契數(shù)列、冪運算等;
數(shù)據(jù)結構操作:遍歷樹(二叉樹前序/中序/后序遍歷)、圖的深度優(yōu)先搜索(DFS)、鏈表反轉等;
復雜邏輯拆解:如文件目錄遍歷(多層嵌套目錄的讀?。?/p>
示例(計算n的階乘):
// 遞歸函數(shù):計算n的階乘 function factorial(n) { // 終止條件:n=1時返回1 (1! = 1) if (n === 1) return 1; // 遞推條件:n! = n × (n-1)!,縮小問題規(guī)模 (n-1) return n * factorial(n - 1); } factorial(5); // 結果:120(5×4×3×2×1) }優(yōu)缺點:
優(yōu)點:代碼簡潔、邏輯清晰,能直觀體現(xiàn)問題的遞歸結構;
缺點:遞歸調用會占用額外的??臻g,若遞歸深度過深易導致棧溢出;重復計算問題(如斐波那契數(shù)列的簡單遞歸實現(xiàn),會重復計算大量相同子問題),效率較低。
優(yōu)化方案:
尾遞歸優(yōu)化:將遞歸調用放在函數(shù)的最后一步(尾調用),部分語言(如ES6規(guī)范中的JavaScript)支持尾遞歸優(yōu)化,可避免棧溢出(但實際瀏覽器支持度有限);
記憶化緩存:將已計算的子問題結果緩存起來,避免重復計算(如用對象存儲斐波那契數(shù)列的已計算值);
迭代改寫:將遞歸邏輯改為循環(huán)迭代(如用for循環(huán)計算階乘),完全避免遞歸調用的棧空間占用。
十. 快速排序的邏輯是什么?
快速排序是一種高效的排序算法,基于分治思想,核心邏輯是通過“選基準、分區(qū)、遞歸排序”三步,將無序數(shù)組逐步拆解為有序子數(shù)組,最終合并為完整的有序數(shù)組,其時間復雜度平均為O(n log n),最壞為O(n²)(可通過合理選基準優(yōu)化),具體邏輯步驟如下:
步驟1:選擇基準元素(pivot):從待排序數(shù)組中選擇一個元素作為“基準”,基準的選擇直接影響排序效率,常見選擇方式有:
選數(shù)組第一個元素或最后一個元素(簡單但易導致最壞情況,如有序數(shù)組);
選數(shù)組中間元素(折中方案);
隨機選擇元素(推薦,可降低最壞情況概率)。
步驟2:分區(qū)操作(partition):以基準元素為標準,將待排序數(shù)組劃分為兩個子數(shù)組: 分區(qū)實現(xiàn)邏輯(雙指針法):
左子數(shù)組:所有元素都小于基準元素;
右子數(shù)組:所有元素都大于或等于基準元素;
基準元素最終會落在其“正確的排序位置”(即最終有序數(shù)組中該元素的位置)。
初始化左指針(left)指向數(shù)組起始位置,右指針(right)指向數(shù)組末尾;
右指針向左移動,找到第一個小于基準的元素,停止移動;
左指針向右移動,找到第一個大于或等于基準的元素,停止移動;
交換左、右指針指向的元素;
重復步驟2-4,直到左指針 >= 右指針;
交換基準元素與左指針(或右指針)指向的元素,完成分區(qū),此時基準元素位于正確位置。
步驟3:遞歸排序子數(shù)組:對分區(qū)后的左子數(shù)組和右子數(shù)組,分別重復步驟1-2(選基準、分區(qū)),直到子數(shù)組的長度為0或1(此時子數(shù)組已天然有序,無需繼續(xù)排序)。
步驟4:合并結果:由于左子數(shù)組、基準元素、右子數(shù)組已分別有序,將三者直接拼接即可得到完整的有序數(shù)組(遞歸過程中無需額外合并操作,分區(qū)后自然有序)。
示例(以數(shù)組[5,2,9,3,7,6,1]為例):
選基準:假設選中間元素3;
分區(qū):通過雙指針交換,最終得到左子數(shù)組[2,1]、基準3、右子數(shù)組[5,9,7,6];
遞歸排序左子數(shù)組[2,1]:選基準2,分區(qū)得到[1]、2、空數(shù)組,左子數(shù)組排序完成;
遞歸排序右子數(shù)組[5,9,7,6]:選基準7,分區(qū)得到[5,6]、7、[9];再遞歸排序[5,6],得到[5,6];
拼接結果:[1,2] + [3] + [5,6,7,9] → 最終有序數(shù)組[1,2,3,5,6,7,9]。
核心特點:
原地排序:不需要額外的大量存儲空間(僅遞歸調用占用??臻g),空間復雜度為O(log n)(遞歸深度);
不穩(wěn)定排序:相等元素的相對位置可能在排序過程中改變(如數(shù)組[3,2,3,1],排序后兩個3的位置可能顛倒);
高效性:平均時間復雜度O(n log n),是實際開發(fā)中最常用的排序算法之一(如V8引擎的Array.sort()在數(shù)組長度大于22時使用快速排序的變體)。
總結
到此這篇關于JS核心知識點之箭頭函數(shù)與this詳細解析的文章就介紹到這了,更多相關JS箭頭函數(shù)與this內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Javascript remove 自定義數(shù)組刪除方法
Javascript自定義數(shù)組刪除方法remove(),需要的朋友可以參考下。2009-10-10
TypeScript類型系統(tǒng)自定義數(shù)據(jù)類型教程示例
這篇文章主要為大家介紹了TypeScript類型系統(tǒng)自定義數(shù)據(jù)類型教程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11
JavaScript統(tǒng)計字符出現(xiàn)次數(shù)
這篇文章主要為大家詳細介紹了JavaScript字符統(tǒng)計出現(xiàn)次數(shù),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-03-03

