讓我印象深刻的 JavaScript 面試題

守候i發表於2017-11-22

1.前言

對於一個web前端來說,面試的時候,難免會遇到javascript的面試題。就我自己而言。有幾道面試題,有些是我面試遇到的,有些是在網上看到的,但是都印象深刻。今天就來簡單分析一下我遇到的,印象深刻的一些面試題!主要目的希望能讓小夥伴學到一些東西,如過以後遇到類似的情況,就記得不要掉坑了!

2.預解析

預解析:在當前作用域下,js執行之前,會把帶有var和function關鍵字的事先宣告,但不會賦值(個人見解)

對預解析印象深刻,並不是因為難,而是要細心,稍微一粗心,答案就寫錯了!我遇到預解析的題目不止一道,有兩道我現在還能記住,我說下!

2-1.預解析1

alert(a)
a();
var a=3;
function a(){
    alert(10)
}   
alert(a)
a=6;
a();  

------------分割線------------------

alert(a)
a();
var a=3;
var a=function(){
    alert(10)
}   
alert(a)
a=6;
a(); 
複製程式碼

看到這個程式碼,當時答錯了。後來請教了朋友,然後自己再理解下,就理順了!
考點其實就兩個,第一變數宣告提前,第二函式宣告優先於變數宣告!
下面我簡單分析一下,
第一部分執行結果:
1.函式宣告優先於變數宣告,所以,剛開始,a就是function a(){alert(10)} ,就會看到這個函式。
2.a(),執行函式,就是出現alert(10)
3.執行了var a=3; 所以alert(a)就是顯示3
4.由於a不是一個函式了,所以往下在執行到a()的時候, 報錯。
第二部分執行結果:
1.underfind
2.報錯
在之前說過,預解析是把帶有varfunction關鍵字的事先宣告,但不會賦值。所以一開始是underfind,然後報錯是因為執行到a()的時候,a並不是一個函式。

//函式表示式,和變數宣告同等
var a=function(){
    alert(10)
} 
//函式宣告,優於變數宣告    
function a(){
    alert(10)
} 
複製程式碼

2-2.預解析和作用域

var a=0;
function aa(){
    alert(a)
    a=3
}
//結果是什麼都沒發生,因為要執行aa函式才會執行alert(0)

------------分割線1------------------

var a=0;
function aa(){
    alert(a)
    var a=3
}
aa();
//underfind  在aa函式裡面,有var a=3,那麼在aa作用域裡面,就是把a這個變數宣告提前,但是不會賦值,所以是underfind

------------分割線2------------------

var a=0;
function aa(a){
    alert(a)
    var a=3
}
aa(5)
alert(a)
//5,0   在函式體內,引數a的優先順序高於變數a

------------分割線3------------------

var a=0;
function aa(a){
    alert(a)
    a=3
}
aa(5)
alert(a)
//5,0   在函式體內,執行alert(a)和a=3,修改的的並不是全域性變數a,而是引數a

------------分割線4------------------

var a=0;
function aa(a){
    alert(a)
    var a=3
    alert(a)
}
aa(5)
//5,3
//這個我也有點不理解,請教網上的說法,有兩個答案(小夥伴如果知道怎麼理解,歡迎在評論上指點)
//1.引數優先順序高於變數宣告,所以 變數a的宣告其實被忽略了,此時相當於
//var a=0;
//function aa(a){
//  var a=5;
//    alert(a)
//    a=3
//    alert(a)
//}
//aa(5)

//2.形參和區域性變數優先順序一樣,此時相當於
//var a=0;
//function aa(a){
//  var a;    先宣告
//  a=5      由於形參和變數名稱一樣,覆蓋了!
//    alert(a)
//    a=3
//    alert(a)
//}
//aa(5)

------------分割線5------------------

var a=0;
function aa(a){
    alert(a)
    a=3
    alert(a)
}
aa()
alert(a)
//underfind  3  0 
//首先,引數優先順序高於全域性變數,由於沒傳引數,所以是underfind
//a=3,實際上修改的時形參a的值,並不是全域性變數a,往下alert(a)也是形參a
//最後的alert(a),你懂的
複製程式碼

3.迴圈與遞迴

3-1.費波納茨陣列

這個不多說了,很簡單,但是很經典。就是當前項等於前兩項的和

var arr=[];
for(var i=0;i<10;i++ ){
    i<=1?arr.push(1):arr.push(arr[i-1]+arr[i-2]);
}
console.log(arr)複製程式碼

3-2.資料排列

比如 123454321 23456765432
這個怎麼做呢?當時我的做法的分兩步寫,先展示前面,再展示後面
程式碼是

//01234543210
//先展示前面的   01234
//n:開始的數字    m:結束的數字
function num1(n,m){
    for(var i=n;i<m;i++){
        //再展示後面的 543210
        console.log(i);
        if(i===m-1){
            num2(n,m)
        }
    }
}
function num2(n,m){
    for(var i=m;i>=n;i--){
        console.log(i)
    }
}
num1(2,5)  //2345432複製程式碼

這樣程式碼太多了,後來研究了這種

function num(n,m){
    console.log(n);
    if(n<m){
        num(n+1,m);
        console.log(n);
    }
}
num(2,5)  //2345432複製程式碼

解釋如下

1.首先執行num(2,5),就是
console.log(2); ->  num(3,5);  ->  console.log(2);      
//執行num(3,5);  就是是相當於   console.log(3); -> num(4,5); -> console.log(3); 下面以此類推
console.log(2); -> console.log(3); -> num(4,5); -> console.log(3); ->  console.log(2);  

然後就是

console.log(2); -> console.log(3); -> console.log(4); -> num(5,5); -> console.log(4); -> console.log(3); ->  console.log(2);

最後就是

console.log(2); -> console.log(3); -> console.log(4); -> console.log(5); -> console.log(4); -> console.log(3); ->  console.log(2);

複製程式碼

4.其它

4-1

function foo1()
{
 return {
     bar: "hello"
 };
}
 
function foo2()
{
 return
 {
     bar: "hello"
 };
}
var a=foo1();
var b=foo2();
console.log(a) //Object {bar: "hello"}
console.log(b) //underfind
//仔細看就知道了複製程式碼

4-2

網上看到的題目,我自己改造下 80%應聘者都不及格的JS面試題

for (var i = 0; i < 5; i++) {
  console.log(i);
}
console.log(i);
//這個大家應該很快就知道了,012345



for (var i = 0; i < 5; i++) {
 setTimeout(function() {
  console.log(i);
 }, 1000);
}
console.log(i);
//這個大家就要小心一點了,答案是5    55555
//在setTimeout執行之前,for迴圈早就執行完了,i的值早已經是5了,所以一開始是執行,最後面的console.log(i);
//在for迴圈的時候一下子自定義5個setTimeout,大概一秒後,就是輸出55555



for (var i = 0; i < 5; i++) {
 (function(j) { // j = i
  setTimeout(function() {
   console.log(j);
  }, 1000);
 })(i);
}
console.log(i); 
//這裡的解析和上面基本一樣,只是用閉包來記錄每一次迴圈的i,
//所以答案是5     01234



var output = function (i) {
 setTimeout(function() {
  console.log(i);
 }, 1000);
};
 
for (var i = 0; i < 5; i++) {
 output(i); // 這裡傳過去的 i 值被複制了
}
console.log(i);

//這裡的解析和上面基本一樣,把i當引數傳進output,記錄每一次迴圈的i,
//所以答案是5     01234



for (let i = 0; i < 5; i++) {
 setTimeout(function() {
  console.log(i);
 }, 1000);
}
console.log(i);
//結果是  報錯   01234 
//注意i是用let定義的,不是var複製程式碼

5.小結

首先,要說一個就是這些是我自己遇到的題目裡面,印象比較深刻的一些題目,並不一定是常見的題目。
然後,這篇文章可以說是我的一個筆記,記錄著我遇到過的題目。我發這樣的面試題文章給小夥伴看,目的不是為了讓小夥伴們記住題目和答案,或者是應付面試,這樣沒有意義,也不現實!我的目的是為了讓大家可以學習一下,通過題目來知道一些原理和執行的機制,或者是知道一些可能的‘陷阱’。
另外,我遇到過的實際的操作題也很多,比如陣列去重,打亂陣列,統計陣列各個元素出現的次數, 字串各個字元的出現次數,獲取地址連結的各個引數等等。這些題目不僅在面試題出現的比較多,在實際專案開發也會經常用到,小夥伴可以自己學習。當然我自己也有封裝過一些函式,就是實現上面說的那些操作的函式,這個我近期也會寫文章,記錄我封裝過哪些函式,封裝過哪些常用的功能,到時候再分享。有什麼需要改正的,或者好的建議,也歡迎指出!


-------------------------華麗的分割線--------------------
想了解更多,關注關注我的微信公眾號:守候書閣

讓我印象深刻的 JavaScript 面試題


相關文章