整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          Web前端:20道非常基礎的JavaScript測試題

          .我們可以在下列哪個 HTML 元素中放置 Javascript 代碼?()

          A.<script>

          B.<javascript>

          C.<js>

          D.<scripting>

          2.寫 "Hello World" 的正確 Javascript 語法是?()

          A.("Hello World")

          B."Hello World"

          C.response.write("Hello World")

          D.document.write("Hello World")

          3.插入 Javacript 的正確位置是?()

          A.<body>部分

          B.<head>部分

          C.<body>部分和<head>部分均可

          4.引用名為 "xxx.js" 的外部腳本的正確語法是?()

          A.<script src="xxx.js">

          B.<script href="xxx.js">

          C.<script name="xxx.js">

          5.如何在警告框中寫入 "Hello World"?()

          A.alertBox="Hello World"

          B.msgBox("Hello World")

          C.alert("Hello World")

          D.alertBox("Hello World")

          6.如何創建函數?()

          A.function:myFunction()

          B.function myFunction()

          C.function=myFunction()

          7.如何調用名為 "myFunction" 的函數?()

          A.call function myFunction

          B.call myFunction()

          C.myFunction()

          8.如何編寫當 i 等于 5 時執行一些語句的條件語句?()

          A.if (i==5)

          B.if i=5 then

          C.if i=5

          D.if i==5 then

          9.如何編寫當 i 不等于 5 時執行一些語句的條件語句?()

          A.if =! 5 then

          B.if >< 5

          C.if (i >< 5)

          D.if (i != 5)

          10.在 JavaScript 中,有多少種不同類型的循環?()

          A.兩種。for 循環和 while 循環。

          B.四種。for 循環、while 循環、do...while 循環以及 loop...until 循環。

          C.一種。for 循環。

          11.for 循環如何開始?()

          A.for (i <= 5; i++)

          B.for (i = 0; i <= 5; i++)

          C.for (i = 0; i <= 5)

          D.for i = 1 to 5

          12.如何在 JavaScript 中添加注釋?()

          A.' This is a comment

          B.<!--This is a comment-->

          C.//This is a comment

          13.可插入多行注釋的 JavaScript 語法是?()

          A./*This comment has more than one line*/

          B.//This comment has more than one line//

          C.<!--This comment has more than one line-->

          14.定義 JavaScript 數組的正確方法是?()

          A.var txt = new Array="George","John","Thomas"

          B.var txt = new Array(1:"George",2:"John",3:"Thomas")

          C.var txt = new Array("George","John","Thomas")

          D.var txt = new Array:1=("George")2=("John")3=("Thomas")


          15.如何把 7.25 四舍五入為最接近的整數?()

          A.round(7.25)

          B.rnd(7.25)

          C.Math.rnd(7.25)

          D.Math.round(7.25)

          16.如何求得 2 和 4 中最大的數?()

          A.Math.ceil(2,4)

          B.Math.max(2,4)

          C.ceil(2,4)

          D.top(2,4)

          17.打開名為 "window2" 的新窗口的 JavaScript 語法是?()

          A.open.new("http://www.w3cschool.cn","window2")

          B.new.window("http://www.w3cschool.cn","window2")

          C.new("http://www.w3cschool.cn","window2")

          D.window.open("http://www.w3cschool.cn","window2")


          18.如何在瀏覽器的狀態欄放入一條消息?()

          A.statusbar = "put your message here"

          B.window.status = "put your message here"

          C.window.status("put your message here")

          D.status("put your message here")

          19.如何獲得客戶端瀏覽器的名稱?()

          A.client.navName

          B.navigator.appName

          C.browser.name

          20.外部腳本必須包含 <script> 標簽。()

          A.正確

          B.錯誤

          請把你的答案寫在留言區。^_^

          者:Mark A
          譯者:前端小智
          來源:dev

          考題列表

          • 1. undefined 和 null 有什么區別?
          • 2. && 運算符能做什么
          • 3. || 運算符能做什么
          • 4. 使用 + 或一元加運算符是將字符串轉換為數字的最快方法嗎?
          • 5. DOM 是什么?
          • 6. 什么是事件傳播?
          • 7. 什么是事件冒泡?
          • 8. 什么是事件捕獲?
          • 9. event.preventDefault() 和 event.stopPropagation()方法之間有什么區別?
          • 10. 如何知道是否在元素中使用了event.preventDefault()方法?
          • 11. 為什么此代碼obj.someprop.x會引發錯誤?
          • 12. 什么是event.target?
          • 13. 什么是event.currentTarget?
          • 14. == 和 === 有什么區別?
          • 15. 為什么在 JS 中比較兩個相似的對象時返回 false?
          • 16. !! 運算符能做什么?
          • 17. 如何在一行中計算多個表達式的值?
          • 18. 什么是提升?
          • 19. 什么是作用域?
          • 20. 什么是閉包?
          • 21. JavaScript中的虛值是什么?
          • 22. 如何檢查值是否虛值?
          • 23. 'use strict' 是干嘛用的?
          • 24. JavaScript中 this 值是什么?
          • 25. 對象的 prototype 是什么?

          1.undefined 和 null 有什么區別?

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

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

          ?let?primitiveTypes?=?['string','number','null','undefined','boolean','symbol',?'bigint'];
          

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

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

          接著來看看它們的區別。

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

          let?_thisIsUndefined;
          const?doNothing?=?()?=>?{};
          const?someObj?=?{
          ??a?:?"ay",
          ??b?:?"bee",
          ??c?:?"si"
          };
          
          console.log(_thisIsUndefined);?//?undefined
          console.log(doNothing());?//?undefined
          console.log(someObj["d"]);?//?undefined
          

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

          fs.readFile('path/to/file',?(e,data)?=>?{
          ???console.log(e);?//?當沒有錯誤發生時,打印?null
          ???if(e){
          ?????console.log(e);
          ???}
          ???console.log(data);
          ?});
          

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

          ?console.log(null?==?undefined);?//?true
          ?console.log(null?===?undefined);?//?false
          

          2. && 運算符能做什么

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

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

          使用if語句

          const?router:?Router?=?Router();
          
          router.get('/endpoint',?(req:?Request,?res:?Response)?=>?{
          ???let?conMobile:?PoolConnection;
          ???try?{
          ??????//do?some?db?operations
          ???}?catch?(e)?{
          ???if?(conMobile)?{
          ????conMobile.release();
          ???}
          ??}
          });

          使用&&操作符

          const?router:?Router?=?Router();
          
          router.get('/endpoint',?(req:?Request,?res:?Response)?=>?{
          ??let?conMobile:?PoolConnection;
          ??try?{
          ?????//do?some?db?operations
          ??}?catch?(e)?{
          ????conMobile?&&?conMobile.release()
          ??}
          });

          3. || 運算符能做什么

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

          console.log(null?||?1?||?undefined);?//?1
          
          function?logName(name)?{
          ??var?n?=?name?||?"Mark";
          ??console.log(n);
          }
          
          logName();?//?"Mark"

          4. 使用 + 或一元加運算符是將字符串轉換為數字的最快方法嗎?

          根據MDN文檔,+是將字符串轉換為數字的最快方法,因為如果值已經是數字,它不會執行任何操作。

          5. DOM 是什么?

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

          假設我們有這樣的 HTML 結構:

          <!DOCTYPE?html>
          <html?lang="en">
          
          <head>
          ???<meta?charset="UTF-8">
          ???<meta?name="viewport"?content="width=device-width,?initial-scale=1.0">
          ???<meta?http-equiv="X-UA-Compatible"?content="ie=edge">
          ???<title>Document?Object?Model</title>
          </head>
          
          <body>
          ???<div>
          ??????<p>
          ?????????<span></span>
          ??????</p>
          ??????<label></label>
          ??????<input>
          ???</div>
          </body>
          
          </html>
          

          等價的DOM是這樣的:

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

          6. 什么是事件傳播?

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

          事件傳播有三個階段:

          1. 捕獲階段–事件從 window 開始,然后向下到每個元素,直到到達目標元素。
          2. 目標階段–事件已達到目標元素。
          3. 冒泡階段–事件從目標元素冒泡,然后上升到每個元素,直到到達 window。

          7. 什么是事件冒泡?

          事件發生在DOM元素上時,該事件并不完全發生在那個元素上。在冒泡階段,事件冒泡,或者事件發生在它的父代,祖父母,祖父母的父代,直到到達window為止。

          假設有如下的 HTML 結構:

          <div?class="grandparent">
          ??<div?class="parent">
          ????<div?class="child">1</div>
          ??</div>
          </div>

          對應的 JS 代碼:

          function?addEvent(el,?event,?callback,?isCapture?=?false)?{
          ??if?(!el?||?!event?||?!callback?||?typeof?callback?!==?'function')?return;
          ??if?(typeof?el?===?'string')?{
          ????el?=?document.querySelector(el);
          ??};
          ??el.addEventListener(event,?callback,?isCapture);
          }
          
          addEvent(document,?'DOMContentLoaded',?()?=>?{
          ??const?child?=?document.querySelector('.child');
          ??const?parent?=?document.querySelector('.parent');
          ??const?grandparent?=?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方法具有第三個可選參數useCapture,其默認值為false,事件將在冒泡階段中發生,如果為true,則事件將在捕獲階段中發生。如果單擊child元素,它將分別在控制臺上記錄child,parent,grandparent,html,document和window,這就是事件冒泡。

          8. 什么是事件捕獲?

          當事件發生在 DOM 元素上時,該事件并不完全發生在那個元素上。在捕獲階段,事件從window開始,一直到觸發事件的元素。

          假設有如下的 HTML 結構:

          <div?class="grandparent">
          ??<div?class="parent">
          ????<div?class="child">1</div>
          ??</div>
          </div>
          

          對應的 JS 代碼:

          function?addEvent(el,?event,?callback,?isCapture?=?false)?{
          ??if?(!el?||?!event?||?!callback?||?typeof?callback?!==?'function')?return;
          ??if?(typeof?el?===?'string')?{
          ????el?=?document.querySelector(el);
          ??};
          ??el.addEventListener(event,?callback,?isCapture);
          }
          
          addEvent(document,?'DOMContentLoaded',?()?=>?{
          ??const?child?=?document.querySelector('.child');
          ??const?parent?=?document.querySelector('.parent');
          ??const?grandparent?=?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方法具有第三個可選參數useCapture,其默認值為false,事件將在冒泡階段中發生,如果為true,則事件將在捕獲階段中發生。如果單擊child元素,它將分別在控制臺上打印window,document,html,grandparent和parent,這就是事件捕獲

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

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

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

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

          11. 為什么此代碼 `obj.someprop.x` 會引發錯誤?

          const?obj?=?{};
          console.log(obj.someprop.x);
          

          顯然,由于我們嘗試訪問someprop屬性中的x屬性,而 someprop 并沒有在對象中,所以值為 undefined。記住對象本身不存在的屬性,并且其原型的默認值為undefined。因為undefined沒有屬性x,所以試圖訪問將會報錯。

          12. 什么是 event.target ?

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

          假設有如下的 HTML 結構:

          <div?onclick="clickFunc(event)"?style="text-align:?center;margin:15px;
          border:1px?solid?red;border-radius:3px;">
          ????<div?style="margin:?25px;?border:1px?solid?royalblue;border-radius:3px;">
          ????????<div?style="margin:25px;border:1px?solid?skyblue;border-radius:3px;">
          ??????????<button?style="margin:10px">
          ?????????????Button
          ??????????</button>
          ????????</div>
          ????</div>
          ?</div>
          

          JS 代碼如下:

          function?clickFunc(event)?{
          ??console.log(event.target);
          }
          

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

          13. 什么是 event.currentTarget??

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

          假設有如下的 HTML 結構:

          <div?onclick="clickFunc(event)"?style="text-align:?center;margin:15px;
          border:1px?solid?red;border-radius:3px;">
          ????<div?style="margin:?25px;?border:1px?solid?royalblue;border-radius:3px;">
          ????????<div?style="margin:25px;border:1px?solid?skyblue;border-radius:3px;">
          ??????????<button?style="margin:10px">
          ?????????????Button
          ??????????</button>
          ????????</div>
          ????</div>
          ?</div>
          

          JS 代碼如下:

          function?clickFunc(event)?{
          ??console.log(event.currentTarget);
          }
          

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

          14. == 和 === 有什么區別?

          ==用于一般比較,===用于嚴格比較,==在比較的時候可以轉換數據類型,===嚴格比較,只要類型不匹配就返回flase。

          先來看看 == 這兄弟:

          強制是將值轉換為另一種類型的過程。在這種情況下,==會執行隱式強制。在比較兩個值之前,==需要執行一些規則。

          假設我們要比較x == y的值。

          1. 如果x和y的類型相同,則 JS 會換成===操作符進行比較。
          2. 如果x為null, y為undefined,則返回true。
          3. 如果x為undefined且y為null,則返回true。
          4. 如果x的類型是number, y的類型是string,那么返回x == toNumber(y)。
          5. 如果x的類型是string, y的類型是number,那么返回toNumber(x) == y。
          6. 如果x為類型是boolean,則返回toNumber(x)== y。
          7. 如果y為類型是boolean,則返回x == toNumber(y)。
          8. 如果x是string、symbol或number,而y是object類型,則返回x == toPrimitive(y)。
          9. 如果x是object,y是string,symbol則返回toPrimitive(x) == y。
          10. 剩下的 返回 false

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

          舉個例子。

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

          這些例子都返回true。

          第一個示例符合條件1,因為x和y具有相同的類型和值。

          第二個示例符合條件4,在比較之前將y轉換為數字。

          第三個例子符合條件2。

          第四個例子符合條件7,因為y是boolean類型。

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

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

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

          如果使用===運算符,則第一個示例以外的所有比較將返回false,因為它們的類型不同,而第一個示例將返回true,因為兩者的類型和值相同。

          具體更多規則可以對參考我之前的文章:

          我對 JS 中相等和全等操作符轉化過程一直很迷惑,直到有了這份算法

          15. 為什么在 JS 中比較兩個相似的對象時返回 false?

          先看下面的例子:

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

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

          16. !! 運算符能做什么?

          !!運算符可以將右側的值強制轉換為布爾值,這也是將值轉換為布爾值的一種簡單方法。

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

          17. 如何在一行中計算多個表達式的值?

          可以使用逗號運算符在一行中計算多個表達式。它從左到右求值,并返回右邊最后一個項目或最后一個操作數的值。

          let?x?=?5;
          
          x?=?(x++?,?x?=?addFive(x),?x?*=?2,?x?-=?5,?x?+=?10);
          
          function?addFive(num)?{
          ??return?num?+?5;
          }
          

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

          18. 什么是提升?

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

          為了理解提升,需要來了解一下執行上下文執行上下文是當前正在執行的“代碼環境”。執行上下文有兩個階段:編譯和執行。

          編譯-在此階段,JS 引薦獲取所有函數聲明并將其提升到其作用域的頂部,以便我們稍后可以引用它們并獲取所有變量聲明(使用var關鍵字進行聲明),還會為它們提供默認值:undefined。

          執行——在這個階段中,它將值賦給之前提升的變量,并執行或調用函數(對象中的方法)。

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

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

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

          上面分別打印:undefined,1, Hello Mark!。

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

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

          編譯階段完成后,它將啟動執行階段調用方法,并將值分配給變量。

          function?greet(name)?{
          ??return?'Hello?'?+?name?+?'!';
          }
          
          var?y;
          
          //start?"execution"?phase
          
          console.log(y);
          y?=?1;
          console.log(y);
          console.log(greet("Mark"));
          

          19. 什么是作用域?

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

          • 全局作用域——在全局命名空間中聲明的變量或函數位于全局作用域中,因此在代碼中的任何地方都可以訪問它們。
          //global?namespace
          var?g?=?"global";
          
          function?globalFunc(){
          ??function?innerFunc(){
          ????console.log(g);?//?can?access?"g"?because?"g"?is?a?global?variable
          ??}
          ?innerFunc();
          }??
          
          • 函數作用域——在函數中聲明的變量、函數和參數可以在函數內部訪問,但不能在函數外部訪問。
          function?myFavoriteFunc(a)?{
          ??if?(true)?{
          ????var?b?=?"Hello?"?+?a;
          ??}
          ??return?b;
          }
          
          myFavoriteFunc("World");
          
          console.log(a);?//?Throws?a?ReferenceError?"a"?is?not?defined
          console.log(b);?//?does?not?continue?here?
          
          • 塊作用域-在塊{}中聲明的變量(let,const)只能在其中訪問。
          ?function?testBlock(){
          ???if(true){
          ?????let?z?=?5;
          ???}
          ???return?z;?
          ?}
          
          ?testBlock();?//?Throws?a?ReferenceError?"z"?is?not?defined
          

          作用域也是一組用于查找變量的規則。如果變量在當前作用域中不存在,它將向外部作用域中查找并搜索,如果該變量不存在,它將再次查找直到到達全局作用域,如果找到,則可以使用它,否則引發錯誤,這種查找過程也稱為作用域鏈

          ???/*?作用域鏈
          
          ?????內部作用域->外部作用域->?全局作用域
          ??*/
          
          ??//?全局作用域
          ??var?variable1?=?"Comrades";???
          ??var?variable2?=?"Sayonara";
          
          ??function?outer(){
          ??//?外部作用域
          ????var?variable1?=?"World";
          ????function?inner(){
          ????//?內部作用域
          ??????var?variable2?=?"Hello";
          ??????console.log(variable2?+?"?"?+?variable1);
          ????}
          ????inner();
          ??}??
          ??outer();?//?Hello?World
          



          20. 什么是閉包?

          這可能是所有問題中最難的一個問題,因為閉包是一個有爭議的話題,這里從個人角度來談談,如果不妥,多多海涵。

          閉包就是一個函數在聲明時能夠記住當前作用域、父函數作用域、及父函數作用域上的變量和參數的引用,直至通過作用域鏈上全局作用域,基本上閉包是在聲明函數時創建的作用域。

          看看小例子:

          ???//?全局作用域
          ???var?globalVar?=?"abc";
          
          ???function?a(){
          ?????console.log(globalVar);
          ???}
          
          ???a();?//?"abc"?
          

          在此示例中,當我們聲明a函數時,全局作用域是a閉包的一部分。

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

          來看一個更復雜的例子:

          var?globalVar?=?"global";
          var?outerVar?=?"outer"
          
          function?outerFunc(outerParam)?{
          ??function?innerFunc(innerParam)?{
          ????console.log(globalVar,?outerParam,?innerParam);
          ??}
          ??return?innerFunc;
          }
          
          const?x?=?outerFunc(outerVar);
          outerVar?=?"outer-2";
          globalVar?=?"guess"
          x("inner");
          

          上面打印結果是 guess outer inner。

          當我們調用outerFunc函數并將返回值innerFunc函數分配給變量x時,即使我們為outerVar變量分配了新值outer-2,outerParam也繼續保留outer值,因為重新分配是在調用outerFunc之后發生的,并且當我們調用outerFunc函數時,它會在作用域鏈中查找outerVar的值,此時的outerVar的值將為 "outer"。

          現在,當我們調用引用了innerFunc的x變量時,innerParam將具有一個inner值,因為這是我們在調用中傳遞的值,而globalVar變量值為guess,因為在調用x變量之前,我們將一個新值分配給globalVar。

          下面這個示例演示沒有理解好閉包所犯的錯誤:

          const?arrFuncs?=?[];
          for(var?i?=?0;?i?<?5;?i++){
          ??arrFuncs.push(function?(){
          ????return?i;
          ??});
          }
          console.log(i);?//?i?is?5
          
          for?(let?i?=?0;?i?<?arrFuncs.length;?i++)?{
          ??console.log(arrFuncs[i]());?//?都打印?5
          }
          

          由于閉包,此代碼無法正常運行。var關鍵字創建一個全局變量,當我們 push 一個函數時,這里返回的全局變量i。因此,當我們在循環后在該數組中調用其中一個函數時,它會打印5,因為我們得到i的當前值為5,我們可以訪問它,因為它是全局變量。

          因為閉包在創建變量時會保留該變量的引用而不是其值。我們可以使用IIFES或使用 let 來代替 var 的聲明。

          21. JavaScript 中的虛值是什么?

          ?const?falsyValues?=?['',?0,?null,?undefined,?NaN,?false];
          

          簡單的來說虛值就是是在轉換為布爾值時變為 false 的值。

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

          使用 Boolean 函數或者 !! 運算符。

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

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

          嚴格模式的一些限制:

          1. 變量必須聲明后再使用
          2. 函數的參數不能有同名屬性,否則報錯
          3. 不能使用with語句
          4. 不能對只讀屬性賦值,否則報錯
          5. 不能使用前綴 0 表示八進制數,否則報錯
          6. 不能刪除不可刪除的屬性,否則報錯
          7. 不能刪除變量delete prop,會報錯,只能刪除屬性delete global[prop]
          8. eval不能在它的外層作用域引入變量
          9. eval和arguments不能被重新賦值
          10. arguments不會自動反映函數參數的變化
          11. 不能使用arguments.callee
          12. 不能使用arguments.caller
          13. 禁止this指向全局對象
          14. 不能使用fn.caller和fn.arguments獲取函數調用的堆棧
          15. 增加了保留字(比如protected、static和interface)

          設立”嚴格模式”的目的,主要有以下幾個:

          1. 消除Javascript語法的一些不合理、不嚴謹之處,減少一些怪異行為;
          2. 消除代碼運行的一些不安全之處,保證代碼運行的安全;
          3. 提高編譯器效率,增加運行速度;
          4. 為未來新版本的Javascript做好鋪墊。

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

          基本上,this指的是當前正在執行或調用該函數的對象的值。this值的變化取決于我們使用它的上下文和我們在哪里使用它。

          const?carDetails?=?{
          ??name:?"Ford?Mustang",
          ??yearBought:?2005,
          ??getName(){
          ????return?this.name;
          ??},
          ??isRegistered:?true
          };
          
          console.log(carDetails.getName());?//?Ford?Mustang
          

          這通常是我們期望結果的,因為在getName方法中我們返回this.name,在此上下文中,this指向的是carDetails對象,該對象當前是執行函數的“所有者”對象。

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

          var?name?=?"Ford?Ranger";
          var?getCarName?=?carDetails.getName;
          
          console.log(getCarName());?//?Ford?Ranger
          

          上面打印Ford Ranger,這很奇怪,因為在第一個console.log語句中打印的是Ford Mustang。這樣做的原因是getCarName方法有一個不同的“所有者”對象,即window對象。在全局作用域中使用var關鍵字聲明變量會在window對象中附加與變量名稱相同的屬性。請記住,當沒有使用“use strict”時,在全局作用域中this指的是window對象。

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

          本例中的this和window引用同一個對象。

          解決這個問題的一種方法是在函數中使用apply和call方法。

          console.log(getCarName.apply(carDetails));?//?Ford?Mustang
          console.log(getCarName.call(carDetails));??//?Ford?Mustang
          

          apply和call方法期望第一個參數是一個對象,該對象是函數內部this的值。

          IIFE或立即執行的函數表達式,在全局作用域內聲明的函數,對象內部方法中的匿名函數和內部函數的this具有默認值,該值指向window對象。

          ???(function?(){
          ?????console.log(this);
          ???})();?//?打印?"window"?對象
          
          ???function?iHateThis(){
          ??????console.log(this);
          ???}
          
          ???iHateThis();?//?打印?"window"?對象
          
          ???const?myFavoriteObj?=?{
          ?????guessThis(){
          ????????function?getName(){
          ??????????console.log(this.name);
          ????????}
          ????????getName();
          ?????},
          ?????name:?'Marko?Polo',
          ?????thisIsAnnoying(callback){
          ???????callback();
          ?????}
          ???};
          
          
          ???myFavoriteObj.guessThis();?//?打印?"window"?對象
          ???myFavoriteObj.thisIsAnnoying(function?(){
          ?????console.log(this);?//?打印?"window"?對象
          ???});
          

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

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

          const?myFavoriteObj?=?{
          ?guessThis(){
          ??const?self?=?this;?//?把?this?值保存在?self?變量中
          ??function?getName(){
          ????console.log(self.name);
          ??}
          ??getName();
          ?},
          ?name:?'Marko?Polo',
          ?thisIsAnnoying(callback){
          ???callback();
          ??}
          };
          

          第二種方式是使用箭頭函數

          const?myFavoriteObj?=?{
          ??guessThis(){
          ?????const?getName?=?()?=>?{?
          ???????console.log(this.name);
          ?????}
          ?????getName();
          ??},
          ??name:?'Marko?Polo',
          ??thisIsAnnoying(callback){
          ???callback();
          ??}
          };
          

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

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

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

          const?o?=?{};
          console.log(o.toString());?//?logs?[object?Object]?
          

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

          console.log(o.toString?===?Object.prototype.toString);?//?logs?true
          

          由于篇幅過長,我將此系列分成上中下三篇,下篇我們在見。


          原文:

          https://dev.to/macmacky/70-javascript-interview-questions-5gfi#1-whats-the-difference-between-undefined-and-null

          const arr = [1,1,1,1,1,1,3,3,3,3,32,2,2,2,2,3,3,4,-1,-10,-10,-1,4,4,5,5,9]
          
          // set方式去重
          // 不改變源數組的數據
          console.log([...new Set(arr)])
          
          // includes方式去重,  時間復雜度 O(n)
          function uniq(arr) {
              let _result = []
              for(let i=0; i < arr.length; i++) {
                  if (!_result.includes(arr[i])) {
                      _result.push(arr[i])
                  }
              }
              return _result
          }
          console.log(uniq(arr))
          
          冒泡排序
          let arr = [1,2,5,3,1,6,7,3,4,10,12,3,21]
          
          function bubbleSort(arr) {
              // 淺克隆, 對外部傳入的參數不進行更改, 保證函數是一個純函數
              let _arr = [].concat(arr)
              // 核心邏輯
              for(let i=0; i<_arr.length -1; i++) {
                  for(let j=0; j<_arr.length-i-1; j++) {
                      if (_arr[j] > _arr[j+1]) {
                          let temp = _arr[j]
                          _arr[j] = _arr[j + 1]
                          _arr[j + 1] = temp
                      }
                  }
              }
              return _arr
          }
          
          console.log(bubbleSort(arr))
          
          快速排序(二分法)
          let arr = [300,432,1342,543,23,656,45,6465,4345,232,87,97,754,345]
          
          function quickSort(arr) {
          
              if(arr.length <= 1) {
                  return arr
              }
          
              const pivot = arr[0]
              let bigger = []
              let smaller = []
          
              for(let i=1; i<arr.length; i++) {
                  if (arr[i] > pivot) {
                      bigger.push(arr[i])
                  }
              }
          
              for(let i=1; i<arr.length; i++) {
                  if (arr[i] < pivot) {
                      smaller.push(arr[i])
                  }
              }
              return quickSort(smaller).concat(pivot, quickSort(bigger))
          }
          
          console.log(quickSort(arr))
          
          函數柯里化
          案例一: 
          function curry(fn) {
              return function() {
                  let arg = arguments
                  return function() {
                      return fn(...arg, ...arguments)
                  }
              }
          }
          
          function fn(a,b,c,d) {
              return a+b+c+d
          }
          
          let fun = curry(fn)
          let fun2 = fun(1,2,3)
          console.log(fun2(5))
          
          案例二: 
          let fn = a => b => c => a+b+c
          console.log(fn(1)(2)(3))
          
          數組扁平化
          let arr = [0,[3,4,5],[[[[12,5,6,7,54,34],43,34],33]], {a:1}]
          
          
          function flatten(arr) {
              let _arr = []
              for(let i=0; i<arr.length; i++) {
                  const leixing = Object.prototype.toString.call(arr[i])
                  if (leixing !== '[object Array]') {
                      _arr.push(arr[i])
                  } else {
                      _arr = _arr.concat(flatten(arr[i]))
                  }
              }
              return _arr
          }
          
          console.log(flatten(arr))
          
          原型鏈上擴展方法
          Array.prototype.max =  function max() {
              console.log(this)
              return Math.max.apply(Math, this)
          }
          let array = [1,2,3,4]
          console.log(array.max())
          
          深克隆
          let arr = [1,2,3,[4,5,6], {a:1}]
          
          function deepClone(o) {
              if (
                  typeof o == 'number'
                  ||
                  typeof o == 'string'
                  ||
                  typeof o == 'boolean'
                  ||
                  typeof o == 'undefined'
              ) {
                  return o
              } else if(Array.isArray(o)) {
                  let _arr = []
                  for(let i=0; i<o.length; i++) {
                      _arr.push(deepClone(o[i]))
                  }
                  return _arr
              } else if(typeof o == 'object') {
                  let _o = {}
                  for(let k in o) {
                      _o[k] = deepClone(o[k])
                  }
                  return _o
              }
          }
          
          let deep = deepClone(arr)
          console.log(arr[3] == deep[3]) // false
          
          樣本篩選函數
          // 功能: 傳入一個數值, 隨機生成指定范圍內的樣本數據
          // 參數: 樣本個數
          // start: 樣本起始數值
          // end: 樣本結束數值
          function sample(num, start, end) {
              end -= 1
              let _arr = []
              while(num != _arr.length){
                  let data = parseInt(Math.random() * end) + start
                  if (!_arr.includes(data)) {
                      _arr.push(data)
                  }
              }
              return _arr
          }
          console.log(sample(30, 2, 32))
          //  輸出結果
          //   [
          //     9, 27, 18, 28, 24, 13, 31, 11,  6,
          //     19,  7, 17, 21, 26, 30, 22,  8, 25,
          //     10,  3,  2,  5,  4, 12, 20, 14, 29,
          //     15, 32, 23
          //   ]
          

          字符串反轉函數

          let str = 'abcde'
          function myReverse(str) {
              return str.split('').reverse().join('')
          }
          
          let res = myReverse(str)
          console.log(res)
          
          
          偏函數
          偏函數的作用: 調用之后能夠獲得一個特定功能的函數
          // 需求: 實現一個檢查類型的偏函數
          function checkType(type) {
              return function(o) {
                  return Object.prototype.toString.call(o) == `[object ${type}]`
              }
          }
          
          let checkIsArray = checkType('Array')
          console.log(checkIsArray([1,2,3]))
          // 輸出結果
          // true
          
          閉包
          閉包的特點: 調用永久記住當前作用域的變量
          
          案例一: 
          var a = 2
          
          function foo() {
              var a = 1
              function bar() {
                  console.log(a)
              }
              bar()
          }
          foo()
          //輸出結果
          //1
          
          案例二: 
          var a = 1
          function bar() {
              console.log(a)
          }
          
          (function(fn) {
              var a = 2
              fn()
          })(bar)
          // 輸出結果
          // 1
          
          箭頭函數
          // 箭頭函數this跟定義時上下文永遠綁定
          // 普通函數的this, 視運行環境而改變
          function fun() {
              return () => {
                  console.log(this)
              }
          }
          
          let laowang = {name: 'laowang'}
          let xiaoliu = {name: 'xiaoliu'}
          
          let arrowFun = fun.call(laowang)
          
          arrowFun() // { name: 'laowang' }
          
          arrowFun.call(xiaoliu) // { name: 'laowang' }
          
          arrowFun = arrowFun.bind(xiaoliu)
          arrowFun() // { name: 'laowang' }
          
          函數新特征
          // 函數非嚴格模式下實參與實參列表的關系
          function fun(a, b) {
              a = (typeof a !== 'undefined') ? a : 10
              b = (typeof b !== 'undefined') ? b : 20
          
              console.log(a == arguments[0])
              console.log(b == arguments[1])
          
              a = 123
              b = 456
          
              console.log(a == arguments[0])
              console.log(b == arguments[1])
          }
          fun(1, 2)
          // 輸出結果
          // true
          // true
          // true
          // true
          
          // 函數嚴格模式下實參與實參列表的關系
          function fun(a, b) {
              'use strict'
              a = (typeof a !== 'undefined') ? a : 10
              b = (typeof b !== 'undefined') ? b : 20
          
              console.log(a == arguments[0])
              console.log(b == arguments[1])
          
              a = 123
              b = 456
          
              console.log(a == arguments[0])
              console.log(b == arguments[1])
          }
          
          fun(1, 2)
          // true
          // true
          // false
          // false
          
          // 函數改良
          // 這種方式跟非嚴格模式下的執行結果是一致的
          function fun(a=10, b=20) {
              console.log(a == arguments[0])
              console.log(b == arguments[1])
          
              a = 123
              b = 456
          
              console.log(a == arguments[0])
              console.log(b == arguments[1])
          }
          
          fun(1, 2)
          // true
          // true
          // false
          // false
          
          暫時性死區
          解釋: 變量在定義之后, 但沒有聲明的情況下, 是暫時不能訪問的
          // 案例一: 函數后面的默認參數可以訪問前面的參數
          // 實參其實相當于使用 let來聲明一個變量
          function foo(a) {
              return a + 5
          }
          
          function fun(a, b = foo(a)) {
              console.log(a + b)
          }
          
          fun(1) // 7
          fun(1, 2) // 3
          
          // 案例二: 函數后面的參數無法訪問前面參數的值
          function add(a = b, b) {
              return a + b
          }
          console.log(add(1, 2)) // 3
          console.log(add(undefined, 2)) // ReferenceError: Cannot access 'b' before initialization
          
          展開運算符
          // 不使用展開運算符
          let arr = [1,2,3,4]
          let max = Math.max.apply(null,arr)
          console.log(max)
          
          // 改進
          let arr = [1,2,3,4]
          let max = Math.max(...arr)
          console.log(max)
          
          為什么使用嚴格模式
          參考資料: https://www.runoob.com/js/js-strict.html
          use strict解釋: 為什么使用嚴格模式:
          
          消除Javascript語法的一些不合理、不嚴謹之處,減少一些怪異行為;
          消除代碼運行的一些不安全之處,保證代碼運行的安全;
          提高編譯器效率,增加運行速度;
          為未來新版本的Javascript做好鋪墊。
          "嚴格模式"體現了Javascript更合理、更安全、更嚴謹的發展方向,包括IE 10在內的主流瀏覽器,都已經支持它,許多大項目已經開始全面擁抱它。
          
          另一方面,同樣的代碼,在"嚴格模式"中,可能會有不一樣的運行結果;一些在"正常模式"下可以運行的語句,在"嚴格模式"下將不能運行。掌握這些內容,有助于更細致深入地理解Javascript,讓你變成一個更好的程序員。
          
          迭代器
          // 需求: 封裝一個迭代器
          function arrIterator(arr) {
              let i = 0
              return {
                  next: function() {
                      let done = i > arr.length - 1 ? true : false
                      let value = !done ? arr[i++] : 'undefined'
                      return {
                          done,
                          value
                      }
                  }
              }
          }
          
          let arr = [1,2,3,4,5]
          let iterator = arrIterator(arr)
          console.log(iterator.next())
          console.log(iterator.next())
          console.log(iterator.next())
          console.log(iterator.next())
          console.log(iterator.next())
          console.log(iterator.next())
          
          // 輸出結果
          // { done: false, value: 1 }
          // { done: false, value: 2 }
          // { done: false, value: 3 }
          // { done: false, value: 4 }
          // { done: false, value: 5 }
          // { done: true, value: 'undefined' }
          
          生成器
          // 生成器
          // 作用: 用于生成迭代器
          function *generator(arr) {
              for(let i=0; i<arr.length; i++) {
                  yield arr[i]
              }
          }
          
          let arr = [1,2,3,4,5]
          const arrIterator = generator(arr)
          console.log(arrIterator.next())
          console.log(arrIterator.next())
          console.log(arrIterator.next())
          console.log(arrIterator.next())
          console.log(arrIterator.next())
          console.log(arrIterator.next())
          
          // 生成器
          // 作用: 用于生成迭代器
          // 案例一
          function *generator(arr) {
              for(let i=0; i<arr.length; i++) {
                  yield arr[i]
              }
          }
          
          let arr = [1,2,3,4,5]
          const arrIterator = generator(arr)
          console.log(arrIterator.next())
          console.log(arrIterator.next())
          console.log(arrIterator.next())
          console.log(arrIterator.next())
          console.log(arrIterator.next())
          console.log(arrIterator.next())
          
          // 輸出結果
          // { value: 1, done: false }
          // { value: 2, done: false }
          // { value: 3, done: false }
          // { value: 4, done: false }
          // { value: 5, done: false }
          // { value: undefined, done: true }
          
          
          // 案例二
          // 生成器可以yield 一個Promise實例對象
          function *generator() {
              yield sumAfter1000ms(1,2).then(res => console.log(res))
              yield sumAfter1000ms(2,2).then(res => console.log(res))
          }
          
          function sumAfter1000ms(a,b) {
              return new Promise((resolve, reject) => {
                  setTimeout(function(){
                      resolve(a+b)
                  }, 2000)
              })
          }
          
          const iterator = generator()
          console.log(iterator.next())
          console.log(iterator.next())
          console.log(iterator.next())
          
          // 輸出結果
          // { value: Promise { <pending> }, done: false }
          // { value: Promise { <pending> }, done: false }
          // { value: undefined, done: true }
          // 3
          // 4
          
          Promise
          promise作用: 
          - 解決毀掉地獄的問題
          - 使代碼調用更加清晰易懂
          
          promise的三種狀態: 
          - pending
          - resolve
          - reject. 
          
          promise特點: 
          - 使用resolve和reject封裝結果回調函數
          - Promise的實例會調用.then方法
          
          // 案例一
          // 不使用promise的情況
          function fun(a, b, cb) {
              setTimeout(function(){
                  return cb(a + b)
              }, 2000)
          }
          
          fun(1,2, res => {
              console.log(res)
              fun(3,4, res => {
                  console.log(res)
                  fun(4, 5, res => {
                      console.log(res)
                  })
              })
          })
          
          // 案例二: 使用promise的寫法
          function sum(a,b) {
              return new Promise((resolve, reject) => {
                  setTimeout(function() {
                      resolve(a + b)
                  }, 2000)
              })
          }
          
          sum(1,2) 
          .then(res => {
              console.log(res)
          })
          
          // 案例三: 使用promise寫法封裝一個讀文件操作函數
          const fs = require('fs')
          function readFile(filename) {
              return new Promise((resolve, reject) => {
                  fs.readFile(filename, (err, res) => {
                      if (err) {
                          reject(new Error('所讀的文件不存在'))
                          return
                      } 
                      resolve(res.toString())
                  })
              })
          }
          
          readFile('./1.txt').then(res => {
              console.log(res)
          }).catch(err => {
              console.log(err)
          })
          
          async await

          主站蜘蛛池模板: 国模无码人体一区二区| 日韩一区二区视频在线观看| 久久久久人妻一区二区三区vr| 久久久精品人妻一区二区三区 | 国产一区二区精品| 精品无码一区二区三区在线| 中文字幕在线观看一区二区 | 亚洲Av高清一区二区三区| 国产一区二区三区美女| 伊人久久精品一区二区三区| 亚洲AV成人一区二区三区AV| 在线精品国产一区二区三区| 狠狠做深爱婷婷综合一区 | 国产乱人伦精品一区二区| 日本亚洲成高清一区二区三区| 高清一区二区三区| 香蕉久久AⅤ一区二区三区 | 一区二区无码免费视频网站| 激情亚洲一区国产精品| 91精品福利一区二区三区野战| 国产在线一区二区| 无码人妻少妇色欲AV一区二区 | 老熟妇高潮一区二区三区| 亚洲丶国产丶欧美一区二区三区| 人妻体内射精一区二区三区 | 国偷自产视频一区二区久| 成人精品一区久久久久| 激情爆乳一区二区三区| 国产精品女同一区二区久久| 中文乱码精品一区二区三区| 一区二区三区亚洲视频| 久久久久人妻精品一区三寸蜜桃 | 国产拳头交一区二区| 国产一区二区三区日韩精品 | 亚洲一区二区无码偷拍| 精品国产日韩亚洲一区在线| 欧洲精品一区二区三区在线观看 | 国产精品一区不卡| 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 精品综合一区二区三区| 精品无码综合一区|