好程式設計師Java教程分享JavaScript常見面試題三

好程式設計師IT發表於2019-10-28

   好程式設計師Java 教程分享JavaScript常見面試題三:1. 下列程式碼行 1-4 如何排序,使之能夠在執行程式碼時輸出到控制檯 為什麼 ?

  (function() { console.log(1);

  setTimeout(function(){console.log(2)}, 1000);

  setTimeout(function(){console.log(3)}, 0);

  console.log(4);

  })();

  序號如下:

  1

  4

  3

  2

  讓我們先來解釋比較明顯而易見的那部分:

  1  和  4 之所以放在前面,是因為它們是透過簡單呼叫  console.log()  而沒有任何延遲輸出的

  2  之所以放在  3 的後面,是因為  是延遲了 1000 毫秒 ( 即, 1 ) 之後輸出的,而  是延遲了 0 毫秒之後輸出的。

   好的。但是,既然 3  0 毫秒延遲之後輸出的,那麼是否意味著它是立即輸出的呢 ? 如果是的話,那麼它是不是應該在  之前輸出,既然  是在第二行輸出的 ?

   要回答這個問題,你需要正確理解JavaScript 的事件和時間設定。

   瀏覽器有一個事件迴圈,會檢查事件佇列和處理未完成的事件。例如,如果時間發生在後臺( 例如,指令碼的  onload  事件 ) 時,瀏覽器正忙 ( 例如,處理一個  onclick) ,那麼事件會新增到佇列中。當 onclick 處理程式完成後,檢查佇列,然後處理該事件 ( 例如,執行  onload  指令碼 )

   同樣的, setTimeout()  也會把其引用的函式的執行放到事件佇列中,如果瀏覽器正忙的話。

   setTimeout() 的第二個引數為 0 的時候,它的意思是“儘快”執行指定的函式。具體而言,函式的執行會放置在事件佇列的下一個計時器開始。但是請注意,這不是立即執行:函式不會被執行除非下一個計時器開始。這就是為什麼在上述的例子中,呼叫  console.log(4)  發生在呼叫  console.log(3)  之前 ( 因為呼叫  console.log(3)  是透過 setTimeout 被呼叫的,因此會稍微延遲 )

  

  2. 寫一個簡單的函式 ( 少於 80 個字元 ) ,要求返回一個布林值指明字串是否為迴文結構。

   下面這個函式在 str  是迴文結構的時候返回 true ,否則,返回 false

  function isPalindrome(str) {

  str = str.replace(/\W/g, '').toLowerCase(); return (str == str.split('').reverse().join(''));

  }

  例如:

  console.log(isPalindrome("level")); // logs 'true'console.log(isPalindrome("levels")); // logs 'false'console.log(isPalindrome("A car, a man, a maraca")); // logs 'true'

  

  3. 寫一個  sum 方法,在使用下面任一語法呼叫時,都可以正常工作。

  console.log(sum(2,3)); // Outputs 5console.log(sum(2)(3)); // Outputs 5

  ( 至少 ) 有兩種方法可以做到:

   方法1

  function sum(x) { if (arguments.length == 2) { return arguments[0] + arguments[1];

  } else { return function(y) { return x + y; };

  }

  }

   JavaScript 中,函式可以提供到  arguments  物件的訪問, arguments  物件提供傳遞到函式的實際引數的訪問。這使我們能夠使用  length  屬性來確定在執行時傳遞給函式的引數數量。

  如果傳遞兩個引數,那麼只需加在一起,並返回。

   否則,我們假設它被以 sum(2)(3) 這樣的形式呼叫,所以我們返回一個匿名函式,這個匿名函式合併了傳遞到  sum() 的引數和傳遞給匿名函式的引數。

   方法2

  function sum(x, y) { if (y !== undefined) { return x + y;

  } else { return function(y) { return x + y; };

  }

  }

   當呼叫一個函式的時候,JavaScript 不要求引數的數目匹配函式定義中的引數數量。如果傳遞的引數數量大於函式定義中引數數量,那麼多餘引數將簡單地被忽略。另一方面,如果傳遞的引數數量小於函式定義中的引數數量,那麼缺少的引數在函式中被引用時將會給一個  undefined 值。所以,在上面的例子中,簡單地檢查第 2 個引數是否未定義,就可以相應地確定函式被呼叫以及進行的方式。

  

  4. 請看下面的程式碼片段:

  for (var i = 0; i < 5; i++) { var btn = document.createElement('button');

  btn.appendChild(document.createTextNode('Button ' + i));

  btn.addEventListener('click', function(){ console.log(i); }); document.body.appendChild(btn);

  }

  (a) 當使用者點選“ Button 4 ”的時候會輸出什麼到控制檯,為什麼 ?(b) 提供一個或多個備用的可按預期工作的實現方案。

  (a) 無論使用者點選什麼按鈕,數字 5 將總會輸出到控制檯。這是因為,當  onclick  方法被呼叫 ( 對於任何按鈕 ) 的時候,  for  迴圈已經結束,變數  已經獲得了 5 的值。 ( 面試者如果能夠談一談有關如何執行上下文,可變物件,啟用物件和內部“範圍”屬性貢有助於閉包行為,則可以加分 )

  (b) 要讓程式碼工作的關鍵是,透過傳遞到一個新建立的函式物件,在每次傳遞透過  for  迴圈時,捕捉到  值。下面是三種可能實現的方法:

  for (var i = 0; i < 5; i++) { var btn = document.createElement('button');

  btn.appendChild(document.createTextNode('Button ' + i));

  btn.addEventListener('click', (function(i) { return function() { console.log(i); };

  })(i)); document.body.appendChild(btn);

  }

   或者,你可以封裝全部呼叫到在新匿名函式中的 btn.addEventListener 

  for (var i = 0; i < 5; i++) { var btn = document.createElement('button');

  btn.appendChild(document.createTextNode('Button ' + i));

  (function (i) {

  btn.addEventListener('click', function() { console.log(i); });

  })(i); document.body.appendChild(btn);

  }

   也可以呼叫陣列物件的本地 forEach  方法來替代  for  迴圈:

  ['a', 'b', 'c', 'd', 'e'].forEach(function (value, i) { var btn = document.createElement('button');

  btn.appendChild(document.createTextNode('Button ' + i));

  btn.addEventListener('click', function() { console.log(i); }); document.body.appendChild(btn);

  });

  

  5. 下面的程式碼將輸出什麼到控制檯,為什麼 ?

  var arr1 = "john".split('');var arr2 = arr1.reverse();var arr3 = "jones".split('');

  arr2.push(arr3);console.log("array 1: length=" + arr1.length + " last=" + arr1.slice(-1));console.log("array 2: length=" + arr2.length + " last=" + arr2.slice(-1));

  輸出結果是:

  "array 1: length=5 last=j,o,n,e,s""array 2: length=5 last=j,o,n,e,s"

  arr1  和  arr2  在上述程式碼執行之後,兩者相同了,原因是:

   呼叫陣列物件的 reverse()  方法並不只返回反順序的陣列,它也反轉了陣列本身的順序 ( 即,在這種情況下,指的是  arr1)

  reverse()  方法返回一個到陣列本身的引用 ( 在這種情況下即, arr1) 。其結果為, arr2  僅僅是一個到  arr1 的引用 ( 而不是副本 ) 。因此,當對  arr2 做了任何事情 ( 即當我們呼叫  arr2.push(arr3);) 時, arr1  也會受到影響,因為  arr1  和  arr2  引用的是同一個物件。

  這裡有幾個側面點有時候會讓你在回答這個問題時,陰溝裡翻船:

   傳遞陣列到另一個陣列的 push()  方法會讓整個陣列作為單個元素對映到陣列的末端。其結果是,語句  arr2.push(arr3);  在其整體中新增  arr3  作為一個單一的元素到  arr2  的末端 ( 也就是說,它並沒有連線兩個陣列,連線陣列是  concat()  方法的目的 )

Python 一樣, JavaScript 標榜陣列方法呼叫中的負數下標,例如  slice()  可作為引用陣列末尾元素的方法:例如, -1 下標表示陣列中的最後一個元素,等等。

 

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913892/viewspace-2661632/,如需轉載,請註明出處,否則將追究法律責任。

相關文章