關(guān)于JavaScript必學(xué)的基礎(chǔ)知識(shí)(下)
16. JavaScript 中“this”的值是多少?
基本上,this 指的是當(dāng)前正在執(zhí)行或調(diào)用函數(shù)的對(duì)象的值。 this 的價(jià)值根據(jù)我們使用它的上下文和我們使用它的地方而變化。
這通常是我們所期望的,因?yàn)樵谖覀兎祷?this.name 的 getName 方法中。 在此上下文中,this 指的是 carDetails 對(duì)象,它是執(zhí)行函數(shù)的當(dāng)前“所有者”對(duì)象。
接下來(lái)我們做一些奇怪的事情:
它在上面打印了‘maxwell’,這很奇怪,因?yàn)榈谝粋€(gè) console.log 語(yǔ)句打印了‘maxwell’。 這樣做的原因是 getCarName 方法有一個(gè)不同的“所有者”對(duì)象,即窗口對(duì)象。
在全局范圍內(nèi)使用 var 關(guān)鍵字聲明變量時(shí),它們將作為屬性附加到具有相同變量名的 window 對(duì)象。
請(qǐng)注意,當(dāng)不使用“use strict”時(shí),全局范圍內(nèi)的 this 指的是 window 對(duì)象。
在這個(gè)例子中,this 和 window 指的是同一個(gè)對(duì)象。
解決此問(wèn)題的一種方法是在函數(shù)中使用 apply 和 call 方法。
apply 和 call 方法期望第一個(gè)參數(shù)是一個(gè)對(duì)象,這將是函數(shù)內(nèi)部 this 的值。
IIFE 或立即調(diào)用函數(shù)表達(dá)式、在全局范圍內(nèi)聲明的函數(shù)、對(duì)象方法中的匿名函數(shù)和內(nèi)部函數(shù)都具有指向窗口對(duì)象的默認(rèn)值 this。
如果我們想獲取myFavoriteObj對(duì)象中name屬性(Maxwell)的值,有兩種方法可以解決這個(gè)問(wèn)題。
一種方法是將 this 的值保存在變量中。
第二種方法是使用箭頭函數(shù)。
箭頭函數(shù)沒(méi)有自己的 this。 它們從封閉的詞法范圍繼承 this 值。 在此示例中,this 值是 myFavoriteObj 對(duì)象,它位于 getName 內(nèi)部函數(shù)之外。
17. ‘var’、‘let’和‘const’有什么區(qū)別?
用 var 聲明的變量被提升并附加到 window 對(duì)象,而用 let 和 const 聲明的變量則不會(huì)。
用 var 聲明的變量會(huì)進(jìn)行變量提升,而用 let 和 const 聲明的變量不會(huì)被提升。
let 和 const 聲明創(chuàng)建塊作用域。
在同一范圍內(nèi),let 和 const 不能聲明同名變量,而 var 允許。
const
18. 什么是箭頭函數(shù)?
與函數(shù)表達(dá)式相比,箭頭函數(shù)表達(dá)式具有更簡(jiǎn)潔的語(yǔ)法,并且沒(méi)有自己的 this、arguments、super 或 new.target。 箭頭函數(shù)表達(dá)式更適合原本使用匿名函數(shù)的情況,不能作為構(gòu)造函數(shù)使用。
在這個(gè)例子中,在 ES5 版本中,我們有 function(){} 聲明和 return 關(guān)鍵字,它們分別是創(chuàng)建函數(shù)和返回值所必需的。
在箭頭函數(shù)版本中,我們只需要括號(hào) () 而不需要 return 語(yǔ)句,因?yàn)槿绻覀冎挥幸粋€(gè)表達(dá)式或值要返回,則箭頭函數(shù)具有隱式返回。
我們還可以在箭頭函數(shù)中使用與函數(shù)表達(dá)式和函數(shù)聲明相同的參數(shù)。 如果我們?cè)诩^函數(shù)中有一個(gè)參數(shù),我們可以省略括號(hào)。
箭頭函數(shù)無(wú)法訪問(wèn)參數(shù)對(duì)象。 因此,調(diào)用第一個(gè) getArgs 函數(shù)會(huì)拋出錯(cuò)誤。 相反,我們可以使用剩余參數(shù)來(lái)獲取箭頭函數(shù)中傳遞的所有參數(shù)。
箭頭函數(shù)沒(méi)有自己的 this 值。 它們捕獲詞法作用域函數(shù)的 this 值。 在此示例中,addAll 函數(shù)將從 computeResult 方法繼承 this 值。 如果我們?cè)谌址秶鷥?nèi)聲明一個(gè)箭頭函數(shù),則 this 值將是 window 對(duì)象。
19. 什么是對(duì)象的原型?
簡(jiǎn)單來(lái)說(shuō),原型就是一個(gè)對(duì)象的藍(lán)圖。 如果它存在于當(dāng)前對(duì)象中,則用作屬性和方法的回退。 它是對(duì)象之間共享屬性和功能的一種方式,也是 JavaScript 中實(shí)現(xiàn)繼承的核心。
即使 o 對(duì)象沒(méi)有 o.toString 方法,它也不會(huì)拋出錯(cuò)誤而是返回字符串 [object Object]。
當(dāng)一個(gè)對(duì)象中沒(méi)有找到某個(gè)屬性時(shí),它會(huì)在它的原型中尋找它,如果仍然不存在,它會(huì)繼續(xù)在原型的原型中尋找,以此類推,直到找到同名的屬性 在原型鏈中。
原型鏈的末端是 Object.prototype。
20. 什么是 IIFE,它的目的是什么?
IIFE 或立即調(diào)用函數(shù)表達(dá)式,是在創(chuàng)建或聲明后立即調(diào)用或執(zhí)行的函數(shù)。 創(chuàng)建 IIFE 的語(yǔ)法是將函數(shù) (){} 包裹在圓括號(hào) () 中,然后用另一對(duì)圓括號(hào) () 調(diào)用它,例如 (function(){})()。
所有這些示例都是有效的 IIFE。 倒數(shù)第二個(gè)示例演示了我們可以將參數(shù)傳遞給 IIFE 函數(shù)。 最后一個(gè)示例表明我們可以將 IIFE 的結(jié)果保存到一個(gè)變量中供以后使用。
IIFE 的主要目的之一是避免命名沖突或全局范圍內(nèi)的變量污染全局命名空間。 這是一個(gè)例子:
假設(shè)我們已經(jīng)導(dǎo)入了一個(gè)指向 omelibr.js 的鏈接,它提供了我們?cè)诖a中使用的一些全局函數(shù)。 但是,這個(gè)庫(kù)有兩個(gè)方法,createGraph 和 drawGraph,我們沒(méi)有使用它們,因?yàn)樗鼈冇绣e(cuò)誤。 我們要實(shí)現(xiàn)自己的 createGraph 和 drawGraph 方法。
解決這個(gè)問(wèn)題的一種方法是直接覆蓋它們。
當(dāng)我們使用這個(gè)解決方案時(shí),我們重寫了庫(kù)提供的兩個(gè)方法。
另一種方法是我們自己重命名它們。
當(dāng)我們使用這個(gè)解決方案時(shí),我們將函數(shù)調(diào)用更改為新的函數(shù)名稱。
另一種方法是使用 IIFE
在這個(gè)解決方案中,我們聲明了一個(gè)變量 graphUtility 來(lái)存儲(chǔ) IIFE 執(zhí)行的結(jié)果。 該函數(shù)返回一個(gè)包含兩個(gè)方法的對(duì)象,createGraph 和 drawGraph。
IIFE 也可以用來(lái)解決常見(jiàn)的面試問(wèn)題。
假設(shè)我們有一個(gè)類為 list-group 的 <ul> 元素,它有 5 個(gè) <li> 子元素。 當(dāng)我們點(diǎn)擊一個(gè)單獨(dú)的 <li> 元素時(shí),我們想要打印它對(duì)應(yīng)的索引值。 但是,上面的代碼沒(méi)有按預(yù)期工作。在這種情況下,我們每次點(diǎn)擊<li>時(shí),他都將i的值打印為5,這是由于閉包造成的。
元素時(shí),它會(huì)打印 5,因?yàn)檫@是稍后在回調(diào)函數(shù)中引用 i 時(shí)的值。
閉包只是函數(shù)從其當(dāng)前作用域、父函數(shù)作用域和全局作用域記住變量的能力。 當(dāng)我們?cè)谌址秶鷥?nèi)使用 var 關(guān)鍵字聲明一個(gè)變量時(shí),我們創(chuàng)建了一個(gè)全局變量 i。 因此,當(dāng)我們點(diǎn)擊 <li> 元素時(shí),它會(huì)打印 5,因?yàn)檫@是稍后在回調(diào)函數(shù)中引用 i 時(shí)的值。
使用 IIFE 可以解決這個(gè)問(wèn)題。
該解決方案之所以有效,是因?yàn)?IIFE 為每次迭代創(chuàng)建了一個(gè)新范圍。 我們捕獲 i 的值并將其作為 currentIndex 參數(shù)傳遞,因此當(dāng)調(diào)用 IIFE 時(shí),每次迭代都有不同的 currentIndex 值。
21. Function.prototype.apply 方法的目的是什么?
apply() 方法調(diào)用具有給定 this 值的函數(shù),并將參數(shù)作為數(shù)組(或類似數(shù)組的對(duì)象)提供。
call() 方法的用途與 apply() 方法類似,區(qū)別在于 call() 接受參數(shù)列表,而 apply() 接受參數(shù)數(shù)組。
22. Function.prototype.call 方法的作用是什么?
call() 方法用于調(diào)用具有指定 this 值和提供的各個(gè)參數(shù)的函數(shù)。
注意:此方法的語(yǔ)法和用途類似于 apply() 方法,唯一的區(qū)別是 call() 接受參數(shù)列表,而 apply() 接受包含多個(gè)參數(shù)的數(shù)組
23. Function.prototype.apply 和 Function.prototype.call 有什么區(qū)別?
apply() 方法可以調(diào)用具有指定 this 值和參數(shù)數(shù)組(或類數(shù)組對(duì)象)的函數(shù)或方法。 call() 方法類似于 apply(),唯一的區(qū)別是 call() 接受參數(shù)作為參數(shù)列表。
24. Function.prototype.bind() 的作用是什么?
bind() 方法創(chuàng)建一個(gè)新函數(shù),在調(diào)用時(shí)將其 this 值設(shè)置為 bind() 的第一個(gè)參數(shù),后續(xù)參數(shù)在調(diào)用時(shí)作為新函數(shù)的參數(shù)提供。
25. 什么是高階函數(shù)?
高階函數(shù)簡(jiǎn)單來(lái)說(shuō)就是將函數(shù)作為參數(shù)或返回函數(shù)的函數(shù)。
26. 什么是“arguments”對(duì)象?
arguments 對(duì)象是作為參數(shù)傳遞給函數(shù)的值的集合。 它是一個(gè)類似數(shù)組的對(duì)象,因?yàn)樗哂小伴L(zhǎng)度”屬性,并且可以使用數(shù)組索引符號(hào)(如 arguments[1])訪問(wèn)各個(gè)值。 但是,它沒(méi)有內(nèi)置的數(shù)組方法,如 forEach、reduce、filter 和 map。
我們可以使用 Array.prototype.slice 將參數(shù)對(duì)象轉(zhuǎn)換為數(shù)組。
注意:箭頭函數(shù)沒(méi)有參數(shù)對(duì)象。
當(dāng)我們調(diào)用函數(shù)四時(shí),它會(huì)拋出 ReferenceError: arguments is not defined 錯(cuò)誤。 可以使用 rest 語(yǔ)法解決此問(wèn)題。
這將自動(dòng)將所有參數(shù)值放入一個(gè)數(shù)組中。
27.如何創(chuàng)建沒(méi)有原型的對(duì)象?
我們可以使用 Object.create 方法來(lái)創(chuàng)建一個(gè)沒(méi)有原型的對(duì)象。
28.什么是class?
class 是一種在 JavaScript 中編寫構(gòu)造函數(shù)的新方法。 它是構(gòu)造函數(shù)的語(yǔ)法糖,在底層仍然使用原型和基于原型的繼承。
覆蓋方法并從另一個(gè)類繼承。
那么我們?cè)趺粗浪趦?nèi)部使用了原型呢?
29.什么是模板字符串?
模板字符串是一種在 JavaScript 中創(chuàng)建字符串的新方法。 我們可以使用反引號(hào) (`) 使字符串成為模板字符串。
在 ES5 中,我們需要使用轉(zhuǎn)義字符來(lái)實(shí)現(xiàn)多行效果,但是有了模板字符串,我們就不需要經(jīng)歷那些麻煩了。
在 ES5 版本中,我們需要添加 \n 來(lái)在字符串中添加新行。 在模板字符串中,我們不需要這樣做。
在 ES5 版本中,如果我們需要在字符串中包含表達(dá)式或值,我們必須使用 + 運(yùn)算符。 在模板字符串中,我們可以使用 ${expr} 來(lái)嵌入一個(gè)表達(dá)式,這使得它比 ES5 版本更干凈。
30.什么是對(duì)象解構(gòu)?
對(duì)象解構(gòu)是一種新的、更簡(jiǎn)潔的從對(duì)象或數(shù)組中提取值的方法。 假設(shè)我們有以下對(duì)象:
以前,要從對(duì)象中提取屬性,傳統(tǒng)的方法是創(chuàng)建一個(gè)與對(duì)象屬性同名的變量。 這種方法很麻煩,因?yàn)槲覀儽仨殲槊總€(gè)屬性創(chuàng)建一個(gè)新變量。 假設(shè)我們有一個(gè)包含許多屬性和方法的大對(duì)象,使用這種方法提取屬性會(huì)很麻煩。
使用解構(gòu)語(yǔ)法使其更加簡(jiǎn)潔:
我們還可以為屬性分配別名:
當(dāng)然,如果屬性值未定義,我們也可以指定一個(gè)默認(rèn)值:
總結(jié)
以上就是我們今天這篇文章想與你分享的全部?jī)?nèi)容,希望對(duì)你有用。
最后,感謝你的閱讀。