前端JavaScript面試100問(上)
1、解釋一下什么是閉包 ? ?
閉包:就是能夠讀取外層函數(shù)內(nèi)部變量的函數(shù)。
閉包需要滿足三個條件:
訪問所在作用域;
函數(shù)嵌套;
在所在作用域外被調(diào)用 。
優(yōu)點:可以重復使用變量,并且不會造成變量污染 。
缺點:會引起內(nèi)存泄漏
使用閉包的注意點:
由于閉包會使得函數(shù)中的變量都被保存在內(nèi)存中,內(nèi)存消耗很大,所以不能濫用閉包,否則會造成網(wǎng)頁的性能問題,在IE中可能導致內(nèi)存泄露。解決方法是,在退出函數(shù)之前,將不使用的局部變量全部刪除。
閉包會在父函數(shù)外部,改變父函數(shù)內(nèi)部變量的值。所以,如果你把父函數(shù)當作對象(object)使用,把閉包當作它的公用方法(Public Method),把內(nèi)部變量當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數(shù)內(nèi)部變量的值。
2、解釋一下原型和原型鏈 ? ?
原型
原型就是一個為對象實例定義了一些公共屬性和公共方法的對象模板。
原型鏈
對象之間的繼承關(guān)系通過構(gòu)造函數(shù)的prototype指向父類對象,直到指向Object對象為止形成的指向鏈條。
通俗講:原型鏈是原型對象創(chuàng)建過程的歷史記錄。
注:在javascript中,所有的對象都擁有一個__proto__屬性指向該對象的原型(prototype) 。
3、說一下 ES6 中你熟悉的一些內(nèi)容 ? ?
class 類的繼承ES6中不再像ES5一樣使用原型鏈實現(xiàn)繼承,而是引入Class這個概念
async、await使用 async/await, 搭配promise,可以通過編寫形似同步的代碼來處理異步流程, 提高代碼的簡潔性和可讀性async 用于申明一個 function 是異步的,而 await 用于等待一個異步方法執(zhí)行完成
Promise是異步編程的一種解決方案,比傳統(tǒng)的解決方案(回調(diào)函數(shù)和事件)更合理、強大
Symbol是一種基本類型。Symbol 通過調(diào)用symbol函數(shù)產(chǎn)生,它接收一個可選的名字參數(shù),該函數(shù)返回的symbol是唯一的
Proxy代理使用代理(Proxy)監(jiān)聽對象的操作,然后可以做一些相應事情
Set是類似于數(shù)組的數(shù)據(jù)集合,無序,插入刪除速度快,元素不重復,查找速度快。
Map是一個類似對象的數(shù)據(jù)結(jié)構(gòu),和對象不同的在于它的key可以是任意類型,但是對象只能使用string和symbol類型,Map的存儲關(guān)聯(lián)性更強
生成器函數(shù)可以進行阻斷函數(shù)執(zhí)行的過程,通過傳參可以傳入新的值進入函數(shù)繼續(xù)執(zhí)行,可以用于將異步變?yōu)樽枞酵?/p>
4、數(shù)組排序的方式 ? ?
冒泡排序:
選擇排序:
快速排序:
5、什么是事件輪詢(EventLoop) ? ?
一個用來等待和發(fā)送消息和事件的程序結(jié)構(gòu)。
1、所有任務都在主線程上執(zhí)行,形成一個執(zhí)行棧。
2、主線程發(fā)現(xiàn)有異步任務,如果是微任務就把他放到微任務的消息隊列里,如果是宏任務就把他放到宏任務的消息隊列里。
3、執(zhí)行棧所有同步任務執(zhí)行完畢。
4、執(zhí)行微任務隊列,之后再執(zhí)行宏任務隊列。
5、輪詢第4步。
6、數(shù)組的一些API, 哪些能夠改變原數(shù)組, 那些不能 ? ?
改變原數(shù)組的方法:
shift()
unshift()
pop()
push()
reverse()
sort()
splice()
不改變原數(shù)組的方法:
concat()
every()
filter()
forEach()
indexOf()
join()
lastIndexOf()
map()
some()
every()
slice()
reduce()
reduceRight()
flat()
flatMap()
find()
7、for 循環(huán)與 forEach 的區(qū)別 ? ?
1.for循環(huán)可以使用break跳出循環(huán),但forEach不能。
2.for循環(huán)可以控制循環(huán)起點(i初始化的數(shù)字決定循環(huán)的起點),forEach只能默認從索引0開始。
3.for循環(huán)過程中支持修改索引(修改 i),但forEach做不到(底層控制index自增,無法左右它)。
8、深淺拷貝 ? ?
深拷貝:
淺拷貝:
9、url 的組成 ?
http:/https: ? 協(xié)議
www.baidu.com 域名
:8080 端口
/sf/vsearch 路徑
?wd=百度熱搜 ? 查詢(可有可無)
#a=1&b=2 哈希值(可有可無) ? ? ? ? ? ? ? ? ? ? ? ?
10、常見的跨域方式 ? ?
JSONP:JSONP是利用外鏈腳本,沒有跨源限制的特點,來實現(xiàn)跨源請求的一種技術(shù)。
CORS:cors:跨域資源共享,是一種實現(xiàn)跨源請求數(shù)據(jù)的技術(shù)。這就是跨源問題的解決方案之一。也是廣泛的解決方案。
正向代理先搭建一個屬于自己的代理服務器
1、用戶發(fā)送請求到自己的代理服務器
2、自己的代理服務器發(fā)送請求到服務器
3、服務器將數(shù)據(jù)返回到自己的代理服務器
4、自己的代理服務器再將數(shù)據(jù)返回給用戶
反向代理
1、用戶發(fā)送請求到服務器(訪問的其實是反向代理服務器,但用戶不知道)
2、反向代理服務器發(fā)送請求到真正的服務器
3、真正的服務器將數(shù)據(jù)返回給反向代理服務器
4、反向代理服務器再將數(shù)據(jù)返回給用戶
通過postMassage,
11、Promise 的使用場景 ? ?
場景1:獲取文件信息。
場景2:配合AJAX獲取信息
場景3:解決回調(diào)地獄,實現(xiàn)串行任務隊列。
場景4: node中進行本地操作的異步過程
12、let, const, var 的區(qū)別 ?

13、對 this 的理解, 三種改變 this 的方式 ?
1.任何情況下直接在script中寫入的this都是window。
2.函數(shù)中的this ?非嚴格模式:this指向window, ?嚴格模式時:this指向undefined。
3.箭頭函數(shù)的thisthis都指向箭頭函數(shù)外上下文環(huán)境的this指向
4.對象中this對象屬性的this 指向?qū)ο笸馍舷挛沫h(huán)境的this對象方法(普通函數(shù))中的this,指向當前對象(誰執(zhí)行該方法,this就指向誰)
5.回調(diào)函數(shù)的this指向
1)、 setTimeout,setInterval回調(diào)函數(shù)不管是否是嚴格模式都會指向window。?
2)、通過在函數(shù)內(nèi)執(zhí)行當前回調(diào)函數(shù) ? 非嚴格模式:this指向window, ? 嚴格模式時:this指向undefined。
3)遞歸函數(shù)中的this ? 非嚴格模式:this指向window, ? 嚴格模式時:this指向undefined。
4) ? 使用arguments0執(zhí)行函數(shù)時 ? ? this指向arguments。
5)事件中的回調(diào)函數(shù),this指向事件偵聽的對象(e.currentTarget);
6、call,apply,bind方法執(zhí)行時this的指向
如果call,apply,bind傳參時,第一個參數(shù)傳入的不是null或者undefined,傳入什么this指向什么
如果第一個參數(shù)傳入的是null或者undefined ,非嚴格模式下指向window ?
7、在ES6的類中this的指向
構(gòu)造函數(shù)中的this指向?qū)嵗斍邦愃a(chǎn)生的新的實例對象 ? ? ?
類中實例化方法中this指向誰執(zhí)行該方法,this指向誰 ? ? ?
類中靜態(tài)方法中this執(zhí)行該類或者該類的構(gòu)造函數(shù) ? ? ?
類中實例化箭頭方法,this仍然指向當前類實例化的實例對象
8、ES5的原型對象中this的指向
函數(shù)名.call(this,....)this寫誰就指誰。
函數(shù)名.apply(this,[參數(shù)1,參數(shù)2,...]) this寫誰就指誰。
函數(shù)名. bind (this,1,2,3) this寫誰就指誰。
在原型的方法中,this指向?qū)嵗斍皹?gòu)造函數(shù)的實例化對象(誰執(zhí)行該方法,this指向誰);
三種改變this指向的方式 ?
14、cookie, localStorage,sessionStorage 的區(qū)別 ?
存儲方式 作用與特性 存儲數(shù)量及大小
cookie
存儲方式
存儲用戶信息,獲取數(shù)據(jù)需要與服務器建立連接。
以路徑存儲,上層路徑不能訪問下層的路徑cookie,下層的路徑cookie可以訪問上層的路徑cookie
作用與特性
可存儲的數(shù)據(jù)有限,且依賴于服務器,無需請求服務器的數(shù)據(jù)盡量不要存放在cookie 中,以免影響頁面性能。
可設(shè)置過期時間。
存儲數(shù)量及大小 將cookie控制在4095B以內(nèi),超出的數(shù)據(jù)會被忽略。
IE6或更低版本 最多存20個cookie;
IE7及以上
版本 多可以有50個;
Firefox多?50個;
chrome和Safari沒有做硬性限制。
cookie最大特征就是可以在頁面與服務器間互相傳遞,當發(fā)送或者接受數(shù)據(jù)時自動傳遞
localStorage
存儲客戶端信息,無需請求服務器。
數(shù)據(jù)永久保存,除非用戶手動清理客戶端緩存。
開發(fā)者可自行封裝一個方法,設(shè)置失效時間。5M左右,各瀏覽器的存儲空間有差異。
任何地方都可以存都可以取
操作簡單
sessionStorage
存儲客戶端信息,無需請求服務器。
數(shù)據(jù)保存在當前會話,刷新頁面數(shù)據(jù)不會被清除,結(jié)束會話(關(guān)閉瀏覽器、關(guān)閉頁面、跳轉(zhuǎn)頁面)數(shù)據(jù)失效。
5M左右,各瀏覽器的存儲空間有差異。
同頁面不同窗口中數(shù)據(jù)不會共享
15、輸入 url 到打開頁面 都做了什么事情 ?
輸入URL
訪問hosts解析,如果沒有解析訪問DNS解析
TCP握手
HTTP請求
HTTP響應返回數(shù)據(jù)
瀏覽器解析并渲染頁面
16、原生 ajax 的流程 ?
17、如何實現(xiàn)繼承 ?
對于 JavaScript 來說,繼承有兩個要點:
復用父構(gòu)造函數(shù)中的代碼
復用父原型中的代碼第一種實現(xiàn)復用父構(gòu)造函數(shù)中的代碼,我們可以考慮調(diào)用父構(gòu)造函數(shù)并將 this 綁定到子構(gòu)造函數(shù)。
第一種方法:復用父原型中的代碼,我們只需改變原型鏈即可。將子構(gòu)造函數(shù)的原型對象的 proto 屬性指向父構(gòu)造函數(shù)的原型對象。
第二種實現(xiàn)使用 new 操作符來替代直接使用 proto 屬性來改變原型鏈。
第三種實現(xiàn)使用一個空構(gòu)造函數(shù)來作為中介函數(shù),這樣就不會將構(gòu)造函數(shù)中的屬性混到 prototype 中
第四種實現(xiàn)es6類的繼承extends。
18、null 和 undefined 的區(qū)別 ? ?
null是一個表示"無"的對象(空對象指針),轉(zhuǎn)為數(shù)值時為0;
undefined是一個表示"無"的原始值,轉(zhuǎn)為數(shù)值時為NaN。拓展:
null表示"沒有對象",即該處不應該有值。典型用法是:
作為函數(shù)的參數(shù),表示該函數(shù)的參數(shù)不是對象。
作為對象原型鏈的終點。
undefined表示"缺少值",就是此處應該有一個值,但是還沒有定義。典型用法是:
變量被聲明了,但沒有賦值時,就等于undefined。
調(diào)用函數(shù)時,應該提供的參數(shù)沒有提供,該參數(shù)等于undefined。
對象沒有賦值的屬性,該屬性的值為undefined。
函數(shù)沒有返回值時,默認返回undefined。
19、函數(shù)的節(jié)流和防抖 ? ?
節(jié)流
節(jié)流是指當一個事件觸發(fā)的時候,為防止事件的連續(xù)頻繁觸發(fā),設(shè)置定時器,達到一種一段事件內(nèi)只觸發(fā)一次的效果,在當前事件內(nèi)不會再次觸發(fā),當前事件結(jié)束以后,再次觸發(fā)才有效.
防抖
防抖是指當一個事件觸發(fā)的時候, 為防止頻繁觸發(fā)事件, 設(shè)置定時器,以達到一種 頻繁觸發(fā)期間不處理, 只有當最后一次連續(xù)觸發(fā)結(jié)束以后才處理
20、什么是 Promise ?
Promise 是異步編程的一種解決方案:從語法上講,promise是一個對象,從它可以獲取異步操作的消息;
?
從本意上講,它是承諾,承諾它過一段時間會給你一個結(jié)果。
?
promise有三種狀態(tài):pending(等待態(tài)),fulfiled(成功態(tài)),rejected(失敗態(tài));狀態(tài)一旦改變,就不會再變。創(chuàng)造promise實例后,它會立即執(zhí)行
promise是用來解決兩個問題的:
回調(diào)地獄,代碼難以維護, 常常第一個的函數(shù)的輸出是第二個函數(shù)的輸入這種現(xiàn)象
promise可以支持多個并發(fā)的請求,獲取并發(fā)請求中的數(shù)據(jù)
這個promise可以解決異步的問題,本身不能說promise是異步的
21、普通函數(shù)與箭頭函數(shù)的區(qū)別 ? ?
普通函數(shù)和箭頭函數(shù)的區(qū)別:
1.箭頭函數(shù)沒有prototype(原型),箭頭函數(shù)沒有自己的this,繼承的是外層代碼塊的this。
2.不可以當做構(gòu)造函數(shù),也就是說不可以使用new命令,否則會報錯的。
3.不可以使用arguments對象,該對象在函數(shù)體內(nèi)不存在。如果要用,可以用 rest 參數(shù)代替。
4.不可以使用yield命令,因此箭頭函數(shù)不能用作 Generator(生成器) 函數(shù)。
5.因為沒有this,所以不能使用call、bind、apply來改變this的指向。
22、設(shè)計模式有哪些, 分別說一說 ? ?
共23種設(shè)計模式,介紹其中6種應用較為廣泛的模式。
發(fā)布訂閱模式:這種設(shè)計模式可以大大降低程序模塊之間的耦合度,便于更加靈活的擴展和維護。
中介者模式 :觀察者模式通過維護一堆列表來管理對象間的多對多關(guān)系,中介者模式通過統(tǒng)一接口來維護一對多關(guān)系,且通信者之間不需要知道彼此之間的關(guān)系,只需要約定好API即可。
代理模式 :為其他對象提供一種代理以控制對這個對象的訪問。代理模式使得代理對象控制具體對象的引用。代理幾乎可以是任何對象:文件,資源,內(nèi)存中的對象,或者是一些難以復制的東西。
單例模式 :保證一個類只有一個實例,并提供一個訪問它的全局訪問點(調(diào)用一個類,任何時候返回的都是同一個實例)。
工廠模式 :工廠模式定義一個用于創(chuàng)建對象的接口,這個接口由子類決定實例化哪一個類。該模式使一個類的實例化延遲到了子類。而子類可以重寫接口方法以便創(chuàng)建的時候指定自己的對象類型
裝飾者模式 : 裝飾者(decorator)模式能夠在不改變對象自身的基礎(chǔ)上,在程序運行期間給對像動態(tài)的添加職責(方法或?qū)傩裕?。與繼承相比,裝飾者是一種更輕便靈活的做法。
23、Promsie 和 async/await 的區(qū)別和使用 ? ?
區(qū)別:
1)函數(shù)前面多了一個async關(guān)鍵字。await關(guān)鍵字只能用在async定義的函數(shù)內(nèi)。async函數(shù)會隱式地返回一個promise,該promise的reosolve值就是函數(shù)return的值。
2)第1點暗示我們不能在 外層代碼中使用await,因為不在async函數(shù)內(nèi)。使用:
1.async和await是配對使用的,await存在于async的內(nèi)部。否則會報錯 。
2.await表示在這里等待一個promise返回,再接下來執(zhí)行。
3.await后面跟著的應該是一個promise對象,(也可以不是,如果不是接下來也沒什么意義了…)
24、談一談垃圾回收機制 ? ?
垃圾回收是動態(tài)存儲管理技術(shù),會自動地釋放“垃圾‘’(不再被程序引用的對象),按照特定的垃圾收集算法來實現(xiàn)資源自動回收的功能。回收的兩種機制
1.標記清除(make-and-sweep)
2.引用計數(shù) ?垃圾回收器會按照固定的時間間隔周期性的執(zhí)行。
25、數(shù)組去重 ?
第一種:
第二種:
第三種:
第四種:
第五種:
第六種:
26、判斷對象為空 ? ?
第一種
使用JSON.stringify()將對象轉(zhuǎn)換為json字符串;
JSON.stringify(obj)?===?'{}'
第二種
第三種
Object.getOwnPropertyNames() 方法會返回該對象所有可枚舉和不可枚舉屬性的屬性名(不含Symbol
屬性)組成的數(shù)組。然后再通過判斷返回的數(shù)組長度是否為零,如果為零的話就是空對象。
Object.getOwnPropertyNames(obj).length?===?0
第四種
Object.keys() 是 ES5 新增的一個對象方法,該方法返回一個數(shù)組,包含指定對象自有的可枚舉屬性(不
含繼承的和Symbol屬性)。用此方法只需要判斷返回的數(shù)組長度是否為零,如果為零的話就是空對象。
27、如何用一次循環(huán)找到數(shù)組中兩個最大的值 ? ?
28、new 一個對象的過程 ?
1.開辟一個堆內(nèi)存,創(chuàng)建一個空對象
2.執(zhí)行構(gòu)造函數(shù),對這個空對象進行構(gòu)造
3.給這個空對象添加proto屬性
29、箭頭函數(shù)為什么不能用 new ? ?
因為箭頭函數(shù)沒有prototype也沒有自己的this指向并且不可以使用arguments。
30、如何實現(xiàn)數(shù)組的復制 ?
for循環(huán)逐一復制;
...方式
slice方法
concat方法
map方法
reduce