2021-03-04 分類: 網(wǎng)站建設(shè)
人們認(rèn)為JavaScript是最適合初學(xué)者的語(yǔ)言。一部分原因在于JavaScript在互聯(lián)網(wǎng)中運(yùn)用廣泛,另一部分原因在于其自身特性使得即使編寫(xiě)的代碼不那么好依然可以運(yùn)行:無(wú)論是否少了一個(gè)分號(hào)或是內(nèi)存管理問(wèn)題,它都不像許多其他語(yǔ)言那樣嚴(yán)格,但在開(kāi)始學(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)制)開(kāi)始登上歷史舞臺(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)題容易被忽略。但在編寫(xiě)好代碼時(shí),了解下述問(wèn)題用處頗大。
4. 函數(shù)表達(dá)式與函數(shù)聲明有哪些不同?
函數(shù)聲明使用關(guān)鍵字function,后跟函數(shù)的名稱。相反,函數(shù)表達(dá)式以var,let或const開(kāi)頭,后跟函數(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)用它之前解釋。
如今,許多開(kāi)發(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)寫(xiě)。
要想完全杜絕這種簡(jiǎn)寫(xiě),可以編寫(xiě)嚴(yán)格模式,——在ES5中介紹過(guò)——在文檔頂部或特定函數(shù)中寫(xiě)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)用方法而異。 重新編寫(xiě)上面的代碼,以便結(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ù)開(kāi)發(fā)人員(以及大多數(shù)公司)不會(huì)建議這樣做。
如果希望多個(gè)對(duì)象進(jìn)行同樣的運(yùn)算,可以創(chuàng)建一個(gè)自定義對(duì)象(或定義你自己的“類”或“子類”),這些對(duì)象繼承內(nèi)置原型而不改變?cè)捅旧?。如果打算與其他開(kāi)發(fā)人員合作,他們對(duì)JavaScript的默認(rèn)行為有一定的預(yù)期,編輯此默認(rèn)行為很容易導(dǎo)致出錯(cuò)。
總的來(lái)說(shuō),這些問(wèn)題能夠幫助你更好理解JavaScript,包括其核心功能和其他鮮為人知的功能 ,并且望能助你為下次的面試做好準(zhǔn)備。
當(dāng)前題目:JavaScript九大面試問(wèn)題集錦
標(biāo)題來(lái)源:http://www.rwnh.cn/news/104194.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供手機(jī)網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)公司、全網(wǎng)營(yíng)銷推廣、品牌網(wǎng)站制作、定制網(wǎng)站、虛擬主機(jī)
聲明:本網(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)容