2021-03-04 分類: 網(wǎng)站建設(shè)
人們認(rèn)為JavaScript是最適合初學(xué)者的語(yǔ)言。一部分原因在于JavaScript在互聯(lián)網(wǎng)中運(yùn)用廣泛,另一部分原因在于其自身特性使得即使編寫的代碼不那么好依然可以運(yùn)行:無(wú)論是否少了一個(gè)分號(hào)或是內(nèi)存管理問(wèn)題,它都不像許多其他語(yǔ)言那樣嚴(yán)格,但在開始學(xué)習(xí)之前,要確保你已經(jīng)知道JavaScript的來(lái)龍去脈,包括可以自動(dòng)完成的事情和“幕后”的操作。
本文將介紹一些面試時(shí)關(guān)于JavaScript的常見(jiàn)問(wèn)題,以及一些突發(fā)難題。當(dāng)然,每次面試都是不同的,你也可能不會(huì)遇見(jiàn)這類問(wèn)題。但是知道的越多,準(zhǔn)備的就越充分。
第一部分:突發(fā)難題
如果在面試中突然問(wèn)到下列問(wèn)題,似乎很難回答。即便如此,這些問(wèn)題在準(zhǔn)備中仍發(fā)揮作用:它們揭示了JavaScript的一些有趣的功能,并強(qiáng)調(diào)在提出編程語(yǔ)言時(shí),首先必須做出的一些決定。
了解有關(guān)JavaScript的更多功能,建議訪問(wèn)https://wtfjs.com。
1. 為什么Math.max()小于Math.min()?
Math.max()> Math.min()輸出錯(cuò)誤這一說(shuō)法看上去有問(wèn)題,但其實(shí)相當(dāng)合理。
如果沒(méi)有給出參數(shù),Math.min()返回infinity(無(wú)窮大),Math.max()返回-infinity(無(wú)窮小)。這只是max()和min()方法規(guī)范的一部分,但選擇背后的邏輯值得深議。了解其中原因,請(qǐng)看以下代碼:
- Math.min(1) // 1
- Math.min(1, infinity)// 1
- Math.min(1, -infinity)// -infinity
如果-infinity(無(wú)窮小)作為Math.min()的默認(rèn)參數(shù),那么每個(gè)結(jié)果都是-infinity(無(wú)窮小),這毫無(wú)用處! 然而,如果默認(rèn)參數(shù)是infinity(無(wú)窮大),則無(wú)論添加任何參數(shù)返回都會(huì)是該數(shù)字 - 這就是我們想要的運(yùn)行方式。
2. 為什么0.1+0.2不等于0.3
簡(jiǎn)而言之,這與JavaScript在二進(jìn)制中存儲(chǔ)浮點(diǎn)數(shù)的準(zhǔn)確程度有關(guān)。在Google Chrome控制臺(tái)中輸入以下公式將得到:
- 0.1 + 0.2// 0.30000000000000004
- 0.1 + 0.2 - 0.2// 0.10000000000000003
- 0.1 + 0.7// 0.7999999999999999
如果是簡(jiǎn)單的等式,對(duì)準(zhǔn)確度沒(méi)有要求,這不太可能產(chǎn)生問(wèn)題。但是如果需要測(cè)試相等性,即使是簡(jiǎn)單地應(yīng)用也會(huì)導(dǎo)致令人頭疼的問(wèn)題。解決這些問(wèn)題,有以下幾種方案。
(1) Fixed Point固定點(diǎn)
例如,如果知道所需的大精度(例如,如果正在處理貨幣),則可以使用整數(shù)類型來(lái)存儲(chǔ)該值。因此,可以存儲(chǔ)499而非4.99美元,并在此基礎(chǔ)上執(zhí)行任何等式,然后可以使用類似result =(value / 100).toFixed(2)的表達(dá)式將結(jié)果顯示給最終用戶,該表達(dá)式返回一個(gè)字符串。
(2) BCD代碼
如果精度非常重要,另一種方法是使用二進(jìn)制編碼的十進(jìn)制(BCD)格式,可以使用BCD庫(kù)(https://formats.kaitai.io/bcd/javascript.html)訪問(wèn)JavaScript。每個(gè)十進(jìn)制值分別存儲(chǔ)在一個(gè)字節(jié)(8位)中。鑒于一個(gè)字節(jié)可以存儲(chǔ)16個(gè)單獨(dú)值,而該系統(tǒng)僅使用0-9位,所以這種方法效率低下。但是,如果十分注重精確度,采用何種方法都值得考量。
3. 為什么018減017等于3?
018-017返回3實(shí)際是靜默類型轉(zhuǎn)換的結(jié)果。這種情況,討論的是八進(jìn)制數(shù)。
(1) 八進(jìn)制數(shù)簡(jiǎn)介
你或許知道計(jì)算中使用二進(jìn)制(base-2)和十六進(jìn)制(base-16)數(shù)字系統(tǒng),但是八進(jìn)制(base-8)在計(jì)算機(jī)歷史中的地位也舉足親重:在20世紀(jì)50年代后期和 20世紀(jì)60年代間,八進(jìn)制被用于簡(jiǎn)化二進(jìn)制,削減高昂的制造系統(tǒng)中的材料成本。
不久以后Hexadecimal(十六進(jìn)制)開始登上歷史舞臺(tái):
1965年發(fā)布的IBM360邁出了從八進(jìn)制到十六進(jìn)制的決定性一步。我們這些習(xí)慣八進(jìn)制的人對(duì)這一舉措感到震驚! 沃恩·普拉特(Vaughan Pratt) |
(2) 如今的八進(jìn)制數(shù)
但在現(xiàn)代編程語(yǔ)言中,八進(jìn)制又有何作用呢?針對(duì)某些案例,八進(jìn)制比十六進(jìn)制更具優(yōu)勢(shì),因?yàn)樗恍枰魏畏菙?shù)字(使用0-7而不是0-F)。
一個(gè)常見(jiàn)用途是Unix系統(tǒng)的文件權(quán)限,其中有八個(gè)權(quán)限變體:
出于相似的原由,八進(jìn)制也用于數(shù)字顯示器。
(3) 回到問(wèn)題本身
在JavaScript中,前綴0將所有數(shù)字轉(zhuǎn)換為八進(jìn)制。但是,八進(jìn)制中不使用數(shù)字8,任何包含8的數(shù)字都將自動(dòng)轉(zhuǎn)換為常規(guī)十進(jìn)制數(shù)。
因此,018-017實(shí)際上等同于十進(jìn)制表達(dá)式:18-15,因?yàn)?17使用八進(jìn)制而018使用十進(jìn)制。
第二部分:常見(jiàn)問(wèn)題
本節(jié)中,將介紹面試中一些更加常見(jiàn)的JavaScript問(wèn)題。第一次學(xué)習(xí)JavaScript時(shí),這些問(wèn)題容易被忽略。但在編寫好代碼時(shí),了解下述問(wèn)題用處頗大。
4. 函數(shù)表達(dá)式與函數(shù)聲明有哪些不同?
函數(shù)聲明使用關(guān)鍵字function,后跟函數(shù)的名稱。相反,函數(shù)表達(dá)式以var,let或const開頭,后跟函數(shù)名稱和賦值運(yùn)算符=。請(qǐng)看以下代碼:
- // Function Declaration
- function sum(x, y) {
- return x + y;
- };
- // Function Expression: ES5
- var sum = function(x, y) {
- return x + y;
- };
- // Function Expression: ES6+
- const sum = (x, y) => { return x + y };
實(shí)際操作中,關(guān)鍵的區(qū)別在于函數(shù)聲明要被提升,而函數(shù)表達(dá)式則沒(méi)有。這意味著JavaScript解釋器將函數(shù)聲明移動(dòng)到其作用域的頂部,因此可以定義函數(shù)聲明并在代碼中的任何位置調(diào)用它。相比之下,只能以線性順序調(diào)用函數(shù)表達(dá)式:必須在調(diào)用它之前解釋。
如今,許多開發(fā)人員偏愛(ài)函數(shù)表達(dá)式有如下幾個(gè)原因:
5. var,let和const有什么區(qū)別?
自ES6發(fā)布以來(lái),現(xiàn)代語(yǔ)法已進(jìn)入各行各業(yè),這已是一個(gè)極其常見(jiàn)的面試問(wèn)題。Var是第一版JavaScript中的變量聲明關(guān)鍵字。但它的缺點(diǎn)導(dǎo)致在ES6中采用了兩個(gè)新關(guān)鍵字:let和const。
這三個(gè)關(guān)鍵字具有不同的分配,提升和域 - 因此我們將單獨(dú)討論。
(1) 分配
最基本的區(qū)別是let和var可以重新分配,而const則不能。這使得const成為不變變量的好選擇,并且它將防止諸如意外重新分配之類的失誤。注意,當(dāng)變量表示數(shù)組或?qū)ο髸r(shí),const確實(shí)允許變量改變,只是無(wú)法重新分配變量本身。
Let 和var都可重新分配,但是正如以下幾點(diǎn)應(yīng)該明確的那樣,如果不是所有情況都要求更改變量,多數(shù)選擇中,let具有優(yōu)于var的顯著優(yōu)勢(shì)。
(2) 提升
與函數(shù)聲明和表達(dá)式(如上所述)之間的差異類似,使用var聲明的變量總是被提升到它們各自的頂部,而使用const和let聲明的變量被提升,但是如果你試圖在聲明之前訪問(wèn),將會(huì)得到一個(gè)TDZ(時(shí)間死區(qū))錯(cuò)誤。由于var可能更容易出錯(cuò),例如意外重新分配,因此運(yùn)算是有用的。請(qǐng)看以下代碼:
- var x = "global scope";
- function foo() {
- var x = "functional scope";
- console.log(x);
- }
- foo(); // "functional scope"
- console.log(x); // "global scope"
這里,foo()和console.log(x)的結(jié)果與預(yù)期一致。但是,如果去掉第二個(gè)變量又會(huì)發(fā)生什么呢?
- var x = "global scope";
- function foo() {
- x = "functional scope";
- console.log(x);
- }
- foo(); // "functional scope"
- console.log(x); // "functional scope"
盡管在函數(shù)內(nèi)定義,但x =“functional scope”已覆蓋全局變量。需要重復(fù)關(guān)鍵字var來(lái)指定第二個(gè)變量x僅限于foo()。
(3) 域
雖然var是function-scoped(函數(shù)作用域),但let和const是block-scoped(塊作用域的:一般情況下,Block是大括號(hào){}內(nèi)的任何代碼,包括函數(shù),條件語(yǔ)句和循環(huán)。為了闡明差異,請(qǐng)看以下代碼:
- var a = 0;
- let b = 0;
- const c = 0;
- if (true) {
- var a = 1;
- let b = 1;
- const c = 1;
- }
- console.log(a); // 1
- console.log(b); // 0
- console.log(c); // 0
在條件塊中,全局范圍的var a已重新定義,但全局范圍的let b和const c則沒(méi)有。一般而言,確保本地任務(wù)保持在本地執(zhí)行,將使代碼更加清晰,減少出錯(cuò)。
6. 如果分配不帶關(guān)鍵字的變量會(huì)發(fā)生什么?
如果不使用關(guān)鍵字定義變量,又會(huì)如何?從技術(shù)上講,如果x尚未定義,則x = 1是window.x = 1的簡(jiǎn)寫。
要想完全杜絕這種簡(jiǎn)寫,可以編寫嚴(yán)格模式,——在ES5中介紹過(guò)——在文檔頂部或特定函數(shù)中寫use strict。后,當(dāng)你嘗試聲明沒(méi)有關(guān)鍵字的變量時(shí),你將收到一條報(bào)語(yǔ)法錯(cuò)誤:Uncaught SyntaxError:Unexpected indentifier。
7. 面向?qū)ο缶幊?OOP)和函數(shù)式編程(FP)之間的區(qū)別是什么?
JavaScript是一種多范式語(yǔ)言,即它支持多種不同的編程風(fēng)格,包括事件驅(qū)動(dòng),函數(shù)和面向?qū)ο蟆?/p>
編程范式各有不同,但在當(dāng)代計(jì)算中,函數(shù)編程和面向?qū)ο缶幊套顬榱餍?- 而JavaScript兩種都可執(zhí)行。
(1) 面向?qū)ο缶幊?/p>
OOP以“對(duì)象”這一概念為基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu),包含數(shù)據(jù)字段(JavaScript稱為類)和程序(JavaScript中的方法)。
一些JavaScript的內(nèi)置對(duì)象包括Math(用于random,max和sin等方法),JSON(用于解析JSON數(shù)據(jù))和原始數(shù)據(jù)類型,如String,Array,Number和Boolean。
無(wú)論何時(shí)采用的內(nèi)置方法,原型或類,本質(zhì)上都在使用面向?qū)ο缶幊獭?/p>
(2) 函數(shù)編程
FP(函數(shù)編程)以“純函數(shù)”的概念為基礎(chǔ),避免共享狀態(tài),可變數(shù)據(jù)和副作用。這可能看起來(lái)像很多術(shù)語(yǔ),但可能已經(jīng)在代碼中創(chuàng)建了許多純函數(shù)。
輸入相同數(shù)據(jù),純函數(shù)總是返回相同的輸出。這種方式?jīng)]有副作用:除了返回結(jié)果之外,例如登錄控制臺(tái)或修改外部變量等都不會(huì)發(fā)生。
至于共享狀態(tài),這里有一個(gè)簡(jiǎn)單的例子,即使輸入是相同的,狀態(tài)仍可以改變函數(shù)的輸出。設(shè)置一個(gè)具有兩個(gè)函數(shù)的代碼:一個(gè)將數(shù)字加5,另一個(gè)將數(shù)字乘以5。
- const num = {
- val: 1
- };
- const add5 = () => num.val += 5;
- const multiply5 = () => num.val *= 5;
如果先調(diào)用add5在調(diào)用乘以5,則整體結(jié)果為30。但是如果以相反的方式執(zhí)行函數(shù)并記錄結(jié)果,則輸出為10,與之前結(jié)果不一致。
這違背了函數(shù)式編程的原理,因?yàn)楹瘮?shù)的結(jié)果因Context調(diào)用方法而異。 重新編寫上面的代碼,以便結(jié)果更易預(yù)測(cè):
- const num = {
- val: 1
- };
- const add5 = () => Object.assign({}, num, {val: num.val + 5}); const multiply5 = () => Object.assign({}, num, {val: num.val * 5});
現(xiàn)在,num.val的值仍然為1,無(wú)論Context調(diào)用的方法如何,add5(num)和multiply5(num)將始終輸出相同的結(jié)果。
8. 命令式和聲明性編程之間有什么區(qū)別?
關(guān)于命令式編程和聲明式編程的區(qū)別,可以以O(shè)OP(面向?qū)ο缶幊?和FP(函數(shù)式編程)為參考。
這兩種是描述多種不同編程范式共有特征的概括性術(shù)語(yǔ)。FP(函數(shù)式編程)是聲明性編程的一個(gè)范例,而OOP(面向?qū)ο缶幊?是命令式編程的一個(gè)范例。
從基本的意義層面,命令式編程關(guān)注的是如何做某事。它以最基本的方式闡明了步驟,并以for和while循環(huán),if和switch陳述句等為特征。
- const sumArray = array => {
- let result = 0;
- for (let i = 0; i < array.length; i++) {
- result += array[i]
- };
- return result;
- }
相比之下,聲明性編程關(guān)注的是做什么,它通過(guò)依賴表達(dá)式將怎樣做抽出來(lái)。這通常會(huì)產(chǎn)生更簡(jiǎn)潔的代碼,但是在規(guī)模上,由于透明度低,調(diào)試會(huì)更加困難。
這是上述的sumArray()函數(shù)的聲明方法。
- const sumArray = array => { return array.reduce((x, y) => x + y) };
9. 是什么基于原型的繼承?
最后,要講到的是基于原型的繼承。面向?qū)ο缶幊逃袔追N不同的類型,JavaScript使用的是基于原型的繼承。該系統(tǒng)通過(guò)使用現(xiàn)有對(duì)象作為原型,允許重復(fù)運(yùn)行。
即使是首次遇到原型這一概念,使用內(nèi)置方法時(shí)也會(huì)遇到原型系統(tǒng)。 例如,用于操作數(shù)組的函數(shù)(如map,reduce,splice等)都是Array.prototype對(duì)象的方法。實(shí)際上,數(shù)組的每個(gè)實(shí)例(使用方括號(hào)[]定義,或者 -不常見(jiàn)的 new Array())都繼承自Array.prototype,這就是為什么map,reduce和spliceare等方法都默認(rèn)可用的原因。
幾乎所有內(nèi)置對(duì)象都是如此,例如字符串和布爾運(yùn)算:只有少數(shù),如Infinity,NaN,null和undefined等沒(méi)有類或方法。
在原型鏈的末尾,能發(fā)現(xiàn) Object.prototype,幾乎JavaScript中的每個(gè)對(duì)象都是Object的一個(gè)實(shí)例。比如Array. prototype和String. prototype都繼承了Object.prototype的類和方法。
要想對(duì)使用prototype syntax的對(duì)象添加類和方法,只需將對(duì)象作為函數(shù)啟動(dòng),并使用prototype關(guān)鍵字添加類和方法:
- function Person() {};
- Person.prototype.forename = "John";
- Person.prototype.surname = "Smith";
是否應(yīng)該覆蓋或擴(kuò)展原型運(yùn)算?
可以使用與創(chuàng)建擴(kuò)展prototypes同樣的方式改變內(nèi)置運(yùn)算,但是大多數(shù)開發(fā)人員(以及大多數(shù)公司)不會(huì)建議這樣做。
如果希望多個(gè)對(duì)象進(jìn)行同樣的運(yùn)算,可以創(chuàng)建一個(gè)自定義對(duì)象(或定義你自己的“類”或“子類”),這些對(duì)象繼承內(nèi)置原型而不改變?cè)捅旧?。如果打算與其他開發(fā)人員合作,他們對(duì)JavaScript的默認(rèn)行為有一定的預(yù)期,編輯此默認(rèn)行為很容易導(dǎo)致出錯(cuò)。
總的來(lái)說(shuō),這些問(wèn)題能夠幫助你更好理解JavaScript,包括其核心功能和其他鮮為人知的功能 ,并且望能助你為下次的面試做好準(zhǔn)備。
分享標(biāo)題:JavaScript九大面試問(wèn)題集錦
當(dāng)前URL:http://jinyejixie.com/news44/104194.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站制作、服務(wù)器托管、網(wǎng)站排名、電子商務(wù)、手機(jī)網(wǎng)站建設(shè)、微信小程序
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容