自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

看完這幾道 JavaScript 面試題,讓你與考官對答如流(上)

開發(fā) 前端
undefined 和 null 有什么區(qū)別?在理解undefined和null之間的差異之前,我們先來看看它們的相似類。

[[312620]]

1.undefined 和 null 有什么區(qū)別?

在理解undefined和null之間的差異之前,我們先來看看它們的相似類。

它們屬于 JavaScript 的 7 種基本類型。

  1. letprimitiveTypes=['string','number','null','undefined','boolean','symbol','bigint']; 

它們是屬于虛值,可以使用Boolean(value)或!!value將其轉(zhuǎn)換為布爾值時(shí),值為false。

  1. console.log(!!null);//falseconsole.log(!!undefined);//falseconsole.log(Boolean(null));//falseconsole.log(Boolean(undefined));//false 

接著來看看它們的區(qū)別。

undefined是未指定特定值的變量的默認(rèn)值,或者沒有顯式返回值的函數(shù),如:console.log(1),還包括對象中不存在的屬性,這些 JS 引擎都會為其分配 undefined 值。

  1. let_thisIsUndefined;constdoNothing=()=>{};constsomeObj={a:"ay",b:"bee",c:"si"};console.log(_thisIsUndefined);//undefinedconsole.log(doNothing());//undefinedconsole.log(someObj["d"]);//undefined 

null是“不代表任何值的值”。null是已明確定義給變量的值。在此示例中,當(dāng)fs.readFile方法未引發(fā)錯(cuò)誤時(shí),我們將獲得null值。

  1. fs.readFile('path/to/file',(e,data)=>{console.log(e);//當(dāng)沒有錯(cuò)誤發(fā)生時(shí),打印nullif(e){console.log(e);}console.log(data);}); 

在比較null和undefined時(shí),我們使用==時(shí)得到true,使用===時(shí)得到false:

  1. console.log(null==undefined);//trueconsole.log(null===undefined);//false 

2. && 運(yùn)算符能做什么

&& 也可以叫邏輯與,在其操作數(shù)中找到第一個(gè)虛值表達(dá)式并返回它,如果沒有找到任何虛值表達(dá)式,則返回最后一個(gè)真值表達(dá)式。它采用短路來防止不必要的工作。

  1. console.log(false&&1&&[]);//falseconsole.log(""&&true&&5);//5 

使用if語句

  1. constrouter:Router=Router();router.get('/endpoint',(req:Request,res:Response)=>{letconMobile:PoolConnection;try{//dosomedboperations}catch(e){if(conMobile){conMobile.release();}}}); 

使用&&操作符

  1. constrouter:Router=Router();router.get('/endpoint',(req:Request,res:Response)=>{letconMobile:PoolConnection;try{//dosomedboperations}catch(e){conMobile&&conMobile.release()}}); 

3. || 運(yùn)算符能做什么

||也叫或邏輯或,在其操作數(shù)中找到第一個(gè)真值表達(dá)式并返回它。這也使用了短路來防止不必要的工作。在支持 ES6 默認(rèn)函數(shù)參數(shù)之前,它用于初始化函數(shù)中的默認(rèn)參數(shù)值。

  1. console.log(null||1||undefined);//1functionlogName(name){varn=name||"Mark";console.log(n);}logName();//"Mark" 

4. 使用 + 或一元加運(yùn)算符是將字符串轉(zhuǎn)換為數(shù)字的最快方法嗎?

根據(jù)MDN文檔,+是將字符串轉(zhuǎn)換為數(shù)字的最快方法,因?yàn)槿绻狄呀?jīng)是數(shù)字,它不會執(zhí)行任何操作。

5. DOM 是什么?

DOM 代表文檔對象模型,是 HTML 和 XML 文檔的接口(API)。當(dāng)瀏覽器第一次讀取(解析)HTML文檔時(shí),它會創(chuàng)建一個(gè)大對象,一個(gè)基于 HTM L文檔的非常大的對象,這就是DOM。它是一個(gè)從 HTML 文檔中建模的樹狀結(jié)構(gòu)。DOM 用于交互和修改DOM結(jié)構(gòu)或特定元素或節(jié)點(diǎn)。

假設(shè)我們有這樣的 HTML 結(jié)構(gòu):

  1. <!DOCTYPEhtml><htmllanghtmllang="en"><head><metacharsetmetacharset="UTF-8"><metanamemetaname="viewport"content="width=device-width,initial-scale=1.0"><metahttp-equivmetahttp-equiv="X-UA-Compatible"content="ie=edge"><title>DocumentObjectModel</title></head><body><div><p><span></span></p><label></label><input></div></body></html> 

等價(jià)的DOM是這樣的:

看完這幾道 JavaScript 面試題,讓你與考官對答如流(上)

JS 中的document對象表示DOM。它為我們提供了許多方法,我們可以使用這些方法來選擇元素來更新元素內(nèi)容,等等。

6. 什么是事件傳播?

當(dāng)事件發(fā)生在DOM元素上時(shí),該事件并不完全發(fā)生在那個(gè)元素上。在“冒泡階段”中,事件冒泡或向上傳播至父級,祖父母,祖父母或父級,直到到達(dá)window為止;而在“捕獲階段”中,事件從window開始向下觸發(fā)元素 事件或event.target。

事件傳播有三個(gè)階段:

  • 捕獲階段–事件從 window 開始,然后向下到每個(gè)元素,直到到達(dá)目標(biāo)元素。
  • 目標(biāo)階段–事件已達(dá)到目標(biāo)元素。
  • 冒泡階段–事件從目標(biāo)元素冒泡,然后上升到每個(gè)元素,直到到達(dá) window。

看完這幾道 JavaScript 面試題,讓你與考官對答如流(上)

7. 什么是事件冒泡?

當(dāng)事件發(fā)生在DOM元素上時(shí),該事件并不完全發(fā)生在那個(gè)元素上。在冒泡階段,事件冒泡,或者事件發(fā)生在它的父代,祖父母,祖父母的父代,直到到達(dá)window為止。

假設(shè)有如下的 HTML 結(jié)構(gòu):

  1. <divclassdivclass="grandparent"><divclassdivclass="parent"><divclassdivclass="child">1</div></div></div> 
對應(yīng)的 JS 代碼:
  1. functionaddEvent(el,event,callback,isCapture=false){if(!el||!event||!callback||typeofcallback!=='function')return;if(typeofel==='string'){el=document.querySelector(el);};el.addEventListener(event,callback,isCapture);}addEvent(document,'DOMContentLoaded',()=>{constchild=document.querySelector('.child');constparent=document.querySelector('.parent');constgrandparent=document.querySelector('.grandparent');addEvent(child,'click',function(e){console.log('child');});addEvent(parent,'click',function(e){console.log('parent');});addEvent(grandparent,'click',function(e){console.log('grandparent');});addEvent(document,'click',function(e){console.log('document');});addEvent('html','click',function(e){console.log('html');})addEvent(window,'click',function(e){console.log('window');})}); 

addEventListener方法具有第三個(gè)可選參數(shù)useCapture,其默認(rèn)值為false,事件將在冒泡階段中發(fā)生,如果為true,則事件將在捕獲階段中發(fā)生。如果單擊child元素,它將分別在控制臺上記錄child,parent,grandparent,html,document和window,這就是事件冒泡。

8. 什么是事件捕獲?

當(dāng)事件發(fā)生在 DOM 元素上時(shí),該事件并不完全發(fā)生在那個(gè)元素上。在捕獲階段,事件從window開始,一直到觸發(fā)事件的元素。

假設(shè)有如下的 HTML 結(jié)構(gòu):

  1. <divclassdivclass="grandparent"><divclassdivclass="parent"><divclassdivclass="child">1</div></div></div> 
對應(yīng)的 JS 代碼:
  1. functionaddEvent(el,event,callback,isCapture=false){if(!el||!event||!callback||typeofcallback!=='function')return;if(typeofel==='string'){el=document.querySelector(el);};el.addEventListener(event,callback,isCapture);}addEvent(document,'DOMContentLoaded',()=>{constchild=document.querySelector('.child');constparent=document.querySelector('.parent');constgrandparent=document.querySelector('.grandparent');addEvent(child,'click',function(e){console.log('child');});addEvent(parent,'click',function(e){console.log('parent');});addEvent(grandparent,'click',function(e){console.log('grandparent');});addEvent(document,'click',function(e){console.log('document');});addEvent('html','click',function(e){console.log('html');})addEvent(window,'click',function(e){console.log('window');})}); 

addEventListener方法具有第三個(gè)可選參數(shù)useCapture,其默認(rèn)值為false,事件將在冒泡階段中發(fā)生,如果為true,則事件將在捕獲階段中發(fā)生。如果單擊child元素,它將分別在控制臺上打印window,document,html,grandparent和parent,這就是事件捕獲。

9. event.preventDefault() 和 event.stopPropagation()方法之間有什么區(qū)別?

event.preventDefault() 方法可防止元素的默認(rèn)行為。如果在表單元素中使用,它將阻止其提交。如果在錨元素中使用,它將阻止其導(dǎo)航。如果在上下文菜單中使用,它將阻止其顯示或顯示。event.stopPropagation()方法用于阻止捕獲和冒泡階段中當(dāng)前事件的進(jìn)一步傳播。

10. 如何知道是否在元素中使用了`event.preventDefault()`方法?

我們可以在事件對象中使用event.defaultPrevented屬性。它返回一個(gè)布爾值用來表明是否在特定元素中調(diào)用了event.preventDefault()。

11. 為什么此代碼 `obj.someprop.x` 會引發(fā)錯(cuò)誤?

  1. constobj={};console.log(obj.someprop.x); 

顯然,由于我們嘗試訪問someprop屬性中的x屬性,而 someprop 并沒有在對象中,所以值為 undefined。記住對象本身不存在的屬性,并且其原型的默認(rèn)值為undefined。因?yàn)閡ndefined沒有屬性x,所以試圖訪問將會報(bào)錯(cuò)。

12. 什么是 event.target ?

簡單來說,event.target是發(fā)生事件的元素或觸發(fā)事件的元素。

假設(shè)有如下的 HTML 結(jié)構(gòu):

  1. <divonclickdivonclick="clickFunc(event)"style="text-align:center;margin:15px;border:1pxsolidred;border-radius:3px;"><divstyledivstyle="margin:25px;border:1pxsolidroyalblue;border-radius:3px;"><divstyledivstyle="margin:25px;border:1pxsolidskyblue;border-radius:3px;"><buttonstylebuttonstyle="margin:10px">Button</button></div></div></div> 
JS 代碼如下:
  1. functionclickFunc(event){console.log(event.target);} 

如果單擊 button,即使我們將事件附加在最外面的div上,它也將打印 button 標(biāo)簽,因此我們可以得出結(jié)論event.target是觸發(fā)事件的元素。

13. 什么是 event.currentTarget??

event.currentTarget是我們在其上顯式附加事件處理程序的元素。

假設(shè)有如下的 HTML 結(jié)構(gòu):

  1. <divonclickdivonclick="clickFunc(event)"style="text-align:center;margin:15px;border:1pxsolidred;border-radius:3px;"><divstyledivstyle="margin:25px;border:1pxsolidroyalblue;border-radius:3px;"><divstyledivstyle="margin:25px;border:1pxsolidskyblue;border-radius:3px;"><buttonstylebuttonstyle="margin:10px">Button</button></div></div></div> 
JS 代碼如下:
  1. functionclickFunc(event){console.log(event.currentTarget);} 

如果單擊 button,即使我們單擊該 button,它也會打印最外面的div標(biāo)簽。在此示例中,我們可以得出結(jié)論,event.currentTarget是附加事件處理程序的元素。

14. == 和 === 有什么區(qū)別?

==用于一般比較,===用于嚴(yán)格比較,==在比較的時(shí)候可以轉(zhuǎn)換數(shù)據(jù)類型,===嚴(yán)格比較,只要類型不匹配就返回flase。

先來看看 == 這兄弟:

強(qiáng)制是將值轉(zhuǎn)換為另一種類型的過程。在這種情況下,==會執(zhí)行隱式強(qiáng)制。在比較兩個(gè)值之前,==需要執(zhí)行一些規(guī)則。

假設(shè)我們要比較x == y的值。

  • 如果x和y的類型相同,則 JS 會換成===操作符進(jìn)行比較。
  • 如果x為null, y為undefined,則返回true。
  • 如果x為undefined且y為null,則返回true。
  • 如果x的類型是number, y的類型是string,那么返回x == toNumber(y)。
  • 如果x的類型是string, y的類型是number,那么返回toNumber(x) == y。
  • 如果x為類型是boolean,則返回toNumber(x)== y。
  • 如果y為類型是boolean,則返回x == toNumber(y)。
  • 如果x是string、symbol或number,而y是object類型,則返回x == toPrimitive(y)。
  • 如果x是object,y是string,symbol則返回toPrimitive(x) == y。
  • 剩下的 返回 false

注意:toPrimitive首先在對象中使用valueOf方法,然后使用toString方法來獲取該對象的原始值。

舉個(gè)例子。

  1. xyx == y55true1'1'truenullundefinedtrue0falsetrue'1,2'[1,2]true'[object Object]'{}true 

這些例子都返回true。

第一個(gè)示例符合條件1,因?yàn)閤和y具有相同的類型和值。

第二個(gè)示例符合條件4,在比較之前將y轉(zhuǎn)換為數(shù)字。

第三個(gè)例子符合條件2。

第四個(gè)例子符合條件7,因?yàn)閥是boolean類型。

第五個(gè)示例符合條件8。使用toString()方法將數(shù)組轉(zhuǎn)換為字符串,該方法返回1,2。

最后一個(gè)示例符合條件8。使用toString()方法將對象轉(zhuǎn)換為字符串,該方法返回[object Object]。

  1. xyx === y55true1'1'falsenullundefinedfalse0falsefalse'1,2'[1,2]false'[object Object]'{}false 

如果使用===運(yùn)算符,則第一個(gè)示例以外的所有比較將返回false,因?yàn)樗鼈兊念愋筒煌?,而第一個(gè)示例將返回true,因?yàn)閮烧叩念愋秃椭迪嗤?/p>

15. 為什么在 JS 中比較兩個(gè)相似的對象時(shí)返回 false?

先看下面的例子:

  1. leta={a:1};letb={a:1};letc=a;console.log(a===b);//打印false,即使它們有相同的屬性console.log(a===c);//true 

JS 以不同的方式比較對象和基本類型。在基本類型中,JS 通過值對它們進(jìn)行比較,而在對象中,JS 通過引用或存儲變量的內(nèi)存中的地址對它們進(jìn)行比較。這就是為什么第一個(gè)console.log語句返回false,而第二個(gè)console.log語句返回true。a和c有相同的引用地址,而a和b沒有。

16. !! 運(yùn)算符能做什么?

!!運(yùn)算符可以將右側(cè)的值強(qiáng)制轉(zhuǎn)換為布爾值,這也是將值轉(zhuǎn)換為布爾值的一種簡單方法。

  1. console.log(!!null);//falseconsole.log(!!undefined);//falseconsole.log(!!'');//falseconsole.log(!!0);//falseconsole.log(!!NaN);//falseconsole.log(!!'');//trueconsole.log(!!{});//trueconsole.log(!![]);//trueconsole.log(!!1);//trueconsole.log(!![].length);//false 

17. 如何在一行中計(jì)算多個(gè)表達(dá)式的值?

可以使用逗號運(yùn)算符在一行中計(jì)算多個(gè)表達(dá)式。它從左到右求值,并返回右邊最后一個(gè)項(xiàng)目或最后一個(gè)操作數(shù)的值。

  1. letx=5;x=(x++,x=addFive(x),x*=2,x-=5,x+=10);functionaddFive(num){returnnum+5;} 

上面的結(jié)果最后得到x的值為27。首先,我們將x的值增加到6,然后調(diào)用函數(shù)addFive(6)并將6作為參數(shù)傳遞并將結(jié)果重新分配給x,此時(shí)x的值為11。之后,將x的當(dāng)前值乘以2并將其分配給x,x的更新值為22。然后,將x的當(dāng)前值減去5并將結(jié)果分配給x x更新后的值為17。最后,我們將x的值增加10,然后將更新的值分配給x,最終x的值為27。

18. 什么是提升?

提升是用來描述變量和函數(shù)移動到其(全局或函數(shù))作用域頂部的術(shù)語。

為了理解提升,需要來了解一下執(zhí)行上下文。執(zhí)行上下文是當(dāng)前正在執(zhí)行的“代碼環(huán)境”。執(zhí)行上下文有兩個(gè)階段:編譯和執(zhí)行。

  • 編譯-在此階段,JS 引薦獲取所有函數(shù)聲明并將其提升到其作用域的頂部,以便我們稍后可以引用它們并獲取所有變量聲明(使用var關(guān)鍵字進(jìn)行聲明),還會為它們提供默認(rèn)值:undefined。
  • 執(zhí)行——在這個(gè)階段中,它將值賦給之前提升的變量,并執(zhí)行或調(diào)用函數(shù)(對象中的方法)。

注意:只有使用var聲明的變量,或者函數(shù)聲明才會被提升,相反,函數(shù)表達(dá)式或箭頭函數(shù),let和const聲明的變量,這些都不會被提升。

假設(shè)在全局使用域,有如下的代碼:

  1. console.log(y);y=1;console.log(y);console.log(greet("Mark"));functiongreet(name){return'Hello'+name+'!';}vary; 

上面分別打?。簎ndefined,1, Hello Mark!。

上面代碼在編譯階段其實(shí)是這樣的:

  1. functiongreet(name){return'Hello'+name+'!';}vary;//默認(rèn)值undefined//等待“編譯”階段完成,然后開始“執(zhí)行”階段/*console.log(y);y=1;console.log(y);console.log(greet("Mark"));*/ 

編譯階段完成后,它將啟動執(zhí)行階段調(diào)用方法,并將值分配給變量。

  1. functiongreet(name){return'Hello'+name+'!';}vary;//start"execution"phaseconsole.log(y);y=1;console.log(y);console.log(greet("Mark")); 

19. 什么是作用域?

JavaScript 中的作用域是我們可以有效訪問變量或函數(shù)的區(qū)域。JS 有三種類型的作用域:全局作用域、函數(shù)作用域和塊作用域(ES6)。

  • 全局作用域——在全局命名空間中聲明的變量或函數(shù)位于全局作用域中,因此在代碼中的任何地方都可以訪問它們。
    1. //globalnamespacevarg="global";functionglobalFunc(){functioninnerFunc(){console.log(g);//canaccess"g"because"g"isaglobalvariable}innerFunc();} 
  • 函數(shù)作用域——在函數(shù)中聲明的變量、函數(shù)和參數(shù)可以在函數(shù)內(nèi)部訪問,但不能在函數(shù)外部訪問。
    1. functionmyFavoriteFunc(a){if(true){varb="Hello"+a;}returnb;}myFavoriteFunc("World");console.log(a);//ThrowsaReferenceError"a"isnotdefinedconsole.log(b);//doesnotcontinuehere 
  • 塊作用域-在塊{}中聲明的變量(let,const)只能在其中訪問。
    1. functiontestBlock(){if(true){letz=5;}returnz;}testBlock();//ThrowsaReferenceError"z"isnotdefined 
  • 作用域也是一組用于查找變量的規(guī)則。如果變量在當(dāng)前作用域中不存在,它將向外部作用域中查找并搜索,如果該變量不存在,它將再次查找直到到達(dá)全局作用域,如果找到,則可以使用它,否則引發(fā)錯(cuò)誤,這種查找過程也稱為作用域鏈。
    1. /*作用域鏈內(nèi)部作用域->外部作用域->全局作用域*///全局作用域varvariable1="Comrades";varvariable2="Sayonara";functionouter(){//外部作用域varvariable1="World";functioninner(){//內(nèi)部作用域varvariable2="Hello";console.log(variable2+""+variable1);}inner();}outer();//HelloWorld 

看完這幾道 JavaScript 面試題,讓你與考官對答如流(上)

20. 什么是閉包?

這可能是所有問題中最難的一個(gè)問題,因?yàn)殚]包是一個(gè)有爭議的話題,這里從個(gè)人角度來談?wù)?,如果不妥,多多海涵?/p>

閉包就是一個(gè)函數(shù)在聲明時(shí)能夠記住當(dāng)前作用域、父函數(shù)作用域、及父函數(shù)作用域上的變量和參數(shù)的引用,直至通過作用域鏈上全局作用域,基本上閉包是在聲明函數(shù)時(shí)創(chuàng)建的作用域。

看看小例子:

  1. //全局作用域varglobalVar="abc";functiona(){console.log(globalVar);}a();//"abc" 

在此示例中,當(dāng)我們聲明a函數(shù)時(shí),全局作用域是a閉包的一部分。

看完這幾道 JavaScript 面試題,讓你與考官對答如流(上)

變量globalVar在圖中沒有值的原因是該變量的值可以根據(jù)調(diào)用函數(shù)a的位置和時(shí)間而改變。但是在上面的示例中,globalVar變量的值為abc。

來看一個(gè)更復(fù)雜的例子:

  1. varglobalVar="global";varouterVar="outer"functionouterFunc(outerParam){functioninnerFunc(innerParam){console.log(globalVar,outerParam,innerParam);}returninnerFunc;}constx=outerFunc(outerVar);outerVar="outer-2";globalVar="guess"x("inner"); 

看完這幾道 JavaScript 面試題,讓你與考官對答如流(上)

上面打印結(jié)果是 guess outer inner。

當(dāng)我們調(diào)用outerFunc函數(shù)并將返回值innerFunc函數(shù)分配給變量x時(shí),即使我們?yōu)閛uterVar變量分配了新值outer-2,outerParam也繼續(xù)保留outer值,因?yàn)橹匦路峙涫窃谡{(diào)用outerFunc之后發(fā)生的,并且當(dāng)我們調(diào)用outerFunc函數(shù)時(shí),它會在作用域鏈中查找outerVar的值,此時(shí)的outerVar的值將為 "outer"。

現(xiàn)在,當(dāng)我們調(diào)用引用了innerFunc的x變量時(shí),innerParam將具有一個(gè)inner值,因?yàn)檫@是我們在調(diào)用中傳遞的值,而globalVar變量值為guess,因?yàn)樵谡{(diào)用x變量之前,我們將一個(gè)新值分配給globalVar。

下面這個(gè)示例演示沒有理解好閉包所犯的錯(cuò)誤:

  1. constarrFuncs=[];for(vari=0;i<5;i++){arrFuncs.push(function(){returni;});}console.log(i);//iis5for(leti=0;i<arrFuncs.length;i++){console.log(arrFuncs[i]());//都打印5} 

由于閉包,此代碼無法正常運(yùn)行。var關(guān)鍵字創(chuàng)建一個(gè)全局變量,當(dāng)我們 push 一個(gè)函數(shù)時(shí),這里返回的全局變量i。因此,當(dāng)我們在循環(huán)后在該數(shù)組中調(diào)用其中一個(gè)函數(shù)時(shí),它會打印5,因?yàn)槲覀兊玫絠的當(dāng)前值為5,我們可以訪問它,因?yàn)樗侨肿兞俊?/p>

因?yàn)殚]包在創(chuàng)建變量時(shí)會保留該變量的引用而不是其值。我們可以使用IIFES或使用 let 來代替 var 的聲明。

21. JavaScript 中的虛值是什么?

  1. constfalsyValues=['',0,null,undefined,NaN,false]; 

簡單的來說虛值就是是在轉(zhuǎn)換為布爾值時(shí)變?yōu)?false 的值。

22. 如何檢查值是否虛值?

使用 Boolean 函數(shù)或者 !! 運(yùn)算符。

23. 'use strict' 是干嘛用的?

"use strict" 是 ES5 特性,它使我們的代碼在函數(shù)或整個(gè)腳本中處于嚴(yán)格模式。嚴(yán)格模式幫助我們在代碼的早期避免 bug,并為其添加限制。

嚴(yán)格模式的一些限制:

  • 變量必須聲明后再使用
  • 函數(shù)的參數(shù)不能有同名屬性,否則報(bào)錯(cuò)
  • 不能使用with語句
  • 不能對只讀屬性賦值,否則報(bào)錯(cuò)
  • 不能使用前綴 0 表示八進(jìn)制數(shù),否則報(bào)錯(cuò)
  • 不能刪除不可刪除的屬性,否則報(bào)錯(cuò)
  • 不能刪除變量delete prop,會報(bào)錯(cuò),只能刪除屬性delete global[prop]
  • eval不能在它的外層作用域引入變量
  • eval和arguments不能被重新賦值
  • arguments不會自動反映函數(shù)參數(shù)的變化
  • 不能使用arguments.callee
  • 不能使用arguments.caller
  • 禁止this指向全局對象
  • 不能使用fn.caller和fn.arguments獲取函數(shù)調(diào)用的堆棧
  • 增加了保留字(比如protected、static和interface)

設(shè)立”嚴(yán)格模式”的目的,主要有以下幾個(gè):

  • 消除Javascript語法的一些不合理、不嚴(yán)謹(jǐn)之處,減少一些怪異行為;
  • 消除代碼運(yùn)行的一些不安全之處,保證代碼運(yùn)行的安全;
  • 提高編譯器效率,增加運(yùn)行速度;
  • 為未來新版本的Javascript做好鋪墊。

24. JavaScript 中 `this` 值是什么?

基本上,this指的是當(dāng)前正在執(zhí)行或調(diào)用該函數(shù)的對象的值。this值的變化取決于我們使用它的上下文和我們在哪里使用它。

  1. constcarDetails={name:"FordMustang",yearBought:2005,getName(){returnthis.name;},isRegistered:true};console.log(carDetails.getName());//FordMustang 

這通常是我們期望結(jié)果的,因?yàn)樵趃etName方法中我們返回this.name,在此上下文中,this指向的是carDetails對象,該對象當(dāng)前是執(zhí)行函數(shù)的“所有者”對象。

接下我們做些奇怪的事情:

  1. varname="FordRanger";vargetCarName=carDetails.getName;console.log(getCarName());//FordRanger 

上面打印Ford Ranger,這很奇怪,因?yàn)樵诘谝粋€(gè)console.log語句中打印的是Ford Mustang。這樣做的原因是getCarName方法有一個(gè)不同的“所有者”對象,即window對象。在全局作用域中使用var關(guān)鍵字聲明變量會在window對象中附加與變量名稱相同的屬性。請記住,當(dāng)沒有使用“use strict”時(shí),在全局作用域中this指的是window對象。

  1. console.log(getCarName===window.getCarName);//trueconsole.log(getCarName===this.getCarName);//true 

本例中的this和window引用同一個(gè)對象。

解決這個(gè)問題的一種方法是在函數(shù)中使用apply和call方法。

  1. console.log(getCarName.apply(carDetails));//FordMustangconsole.log(getCarName.call(carDetails));//FordMustang 

apply和call方法期望第一個(gè)參數(shù)是一個(gè)對象,該對象是函數(shù)內(nèi)部this的值。

IIFE或立即執(zhí)行的函數(shù)表達(dá)式,在全局作用域內(nèi)聲明的函數(shù),對象內(nèi)部方法中的匿名函數(shù)和內(nèi)部函數(shù)的this具有默認(rèn)值,該值指向window對象。

  1. (function(){console.log(this);})();//打印"window"對象functioniHateThis(){console.log(this);}iHateThis();//打印"window"對象constmyFavoriteObj={guessThis(){functiongetName(){console.log(this.name);}getName();},name:'MarkoPolo',thisIsAnnoying(callback){callback();}};myFavoriteObj.guessThis();//打印"window"對象myFavoriteObj.thisIsAnnoying(function(){console.log(this);//打印"window"對象}); 

如果我們要獲取myFavoriteObj對象中的name屬性(即Marko Polo)的值,則有兩種方法可以解決此問題。

一種是將 this 值保存在變量中。

  1. constmyFavoriteObj={guessThis(){constself=this;//把this值保存在self變量中functiongetName(){console.log(self.name);}getName();},name:'MarkoPolo',thisIsAnnoying(callback){callback();}}; 

第二種方式是使用箭頭函數(shù)

  1. constmyFavoriteObj={guessThis(){constgetName=()=>{console.log(this.name);}getName();},name:'MarkoPolo',thisIsAnnoying(callback){callback();}}; 

箭頭函數(shù)沒有自己的 this。它復(fù)制了這個(gè)封閉的詞法作用域中this值,在這個(gè)例子中,this值在getName內(nèi)部函數(shù)之外,也就是myFavoriteObj對象。

25. 對象的 prototype(原型) 是什么?

簡單地說,原型就是對象的藍(lán)圖。如果它存在當(dāng)前對象中,則將其用作屬性和方法的回退。它是在對象之間共享屬性和功能的方法,這也是JavaScript實(shí)現(xiàn)繼承的核心。

  1. consto={};console.log(o.toString());//logs[objectObject] 

即使o對象中不存在o.toString方法,它也不會引發(fā)錯(cuò)誤,而是返回字符串[object Object]。當(dāng)對象中不存在屬性時(shí),它將查看其原型,如果仍然不存在,則將其查找到原型的原型,依此類推,直到在原型鏈中找到具有相同屬性的屬性為止。原型鏈的末尾是Object.prototype。

  1. console.log(o.toString===Object.prototype.toString);//logstrue 

 

責(zé)任編輯:趙寧寧 來源: 今日頭條
相關(guān)推薦

2020-01-18 07:55:28

JavaScript開發(fā)

2023-04-10 14:57:57

AI復(fù)活逝者

2021-02-26 05:20:42

Java參數(shù)化泛型

2019-07-18 15:42:53

Redisoffer數(shù)據(jù)庫

2024-03-07 07:37:03

AQS線程獨(dú)占鎖

2022-03-31 09:50:45

JS面試題

2019-12-26 09:52:33

Redis集群線程

2013-01-05 14:51:34

JavaScriptjQuery面試

2024-06-04 14:52:28

2024-07-09 13:47:00

2024-03-04 00:25:00

機(jī)器人GPT-4

2023-09-04 08:28:34

JavaScripforEach 循環(huán)

2023-11-15 07:54:03

HashMap數(shù)據(jù)結(jié)構(gòu)

2020-09-25 15:40:22

toStringvalueOf前端

2019-09-10 10:48:10

RedisJava面試題

2020-04-20 13:11:21

HashMap底層存儲

2019-08-13 08:43:07

JavaScript前端面試題

2021-05-08 14:20:27

Redis面試數(shù)據(jù)庫

2020-04-29 09:30:48

Google面試題工程師

2015-08-27 09:27:34

JavaScript面試題
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號