2018春節後前端面試小記

超人他不會飛發表於2018-03-02

寫在前面

    唉,我還是前端小渣渣一個。

最近一次的面試:

是一家雲服務產品公司,面試流程也比較簡單,前端負責人拿了一塊白板和記號筆,心想一會要手寫程式碼了。。。。

不過這種面試方式還是不錯的。

去之前以為自己準備的差不多,其實準備的遠遠不夠充足啊。

關於自我介紹

一開始一般會讓你進行一個簡單的自我介紹,我就主要說了一下上家公司的工作經歷,描述了一下我負責過的專案,每個專案的業務功能,主要詳細介紹每個專案用到的技術。

雖然我說了很多,但是事後覺得我在表達的時候,語言的條理性、邏輯性、準確性都不是很好,表達能力的強弱也是面試官比較看中的一部分,畢竟有可能以後和他共事交流工作內容,探討技術等,所以,自我介紹這一塊,覺得也挺重要的,自我介紹代表了面試官對你的第一印象,即便你面試很多次了,也說過很多次了,這方面還是應該好好梳理下自己的語言。


接下來考察js了,面試官慢慢的拿起了他的小白板,我的心裡默默的有點小緊張。。。。

考察方式也比較中規中矩,按照js裡的大類挨個考察。

  • 首先是函式方面

 for (var i = 0; i < 5; i++) { 

 setTimeout(function() {  

  console.log(i);  

}, 1000); 

}複製程式碼

“咦?。。。,上一次的面試不是也碰到了這個?”

然後我淡定的說出了答案:

setTimeout函式會延遲執行,那麼等到執行console.log()的時候,i已經變成5了,所以最後會一次性列印出5個5;”

問:“那我要輸出0~4呢?”

“怎麼也有這個問題?是不是要問我有幾種改法。。。”

我直接說var 改成let就可以了

for (let i = 0; i < 5; i++) { 

 setTimeout(function() {  

  console.log(i); 

  }, 1000);

 }複製程式碼

或者加個閉包:

for (var i = 0; i < 5; i++) { 

 (function(i) {

setTimeout(function() {  

  console.log(i); 

 }, 1000); 

 })(i)

}

複製程式碼

或者這樣:

for(var i = 1;i < 5;i++){  

  var a = function(){  

      var j = i;    

    setTimeout(function(){  

          console.log(j);  

      },1000)  
  }  
  
a();

}複製程式碼

這也是用了閉包的方法,其實就相當於把var化成了let效果一樣,這樣i的值一開始不會被預設繫結,每執行一次迴圈的時候都會給i賦予新值。


問:“如果去掉function裡的 i呢?”

“這樣其實對記憶體沒有保持引用, i 最後還是5。”


由於類似的面試題頻繁遇到,整理了一些相關的面試題:

比如這個:

for (var i = 0; i < 5; i++) { 

 setTimeout((function(i) { 

   console.log(i); 

 })(i), i * 1000);
}複製程式碼

延時函式的第一個引數變成了一個立即執行函式,在這裡應該是一個undefined,等價於:

setTimeout( undefined, … );

立即函式會立馬執行,所以是立馬就輸出0~4;

Promise考察:

setTimeout(function() { 

 console.log(1)}, 0);

new Promise(function executor(resolve) { 

 console.log(2);  

for( var i=0 ; i<10000 ; i++ ) { 

   i == 9999 && resolve(); 

 } 
 console.log(3);

}).then(function() {  

console.log(4);

});

console.log(5);複製程式碼

考察執行機制,首先Promise是非同步的,Promise只有三中狀態,pending、fulfilled(成功)、rejected(失敗),後兩者統稱為resolve(已定型),一旦狀態定下句就無法再改變。

第一個延時函式首先會設定一個定時,在定時結束後傳遞這個函式將它放到任務佇列中去,因此一開始不會輸出1;

Promise裡的函式會按順序執行,輸出2 3 ,Promise裡的then就是會非同步執行,放到當前Promise任務佇列的最後執行,而console.log(5)是按順序執行的,所以先輸出5,再輸出4。Promise.then()裡面的回撥屬於 microtask, 會在當前 Event Loop 的最後執行, 而 SetTimeout 內的回撥屬於 macrotask, 會在下一個 Event Loop 中執行

最後,才會輸出1。

最後輸出: 2 3 5 4 1

  • 物件考察

先來個最簡單的

var obj = {
  a: "1"
};

var obj2 = obj;

obj2.a = "2";

console.log(obj.a);複製程式碼

“肯定是輸出 2 啊”

ojb2只是對obj例項的一個引用,到最後還是修改的obj的值。


this指標

    name = "name of window";  

    function show() {   

     var name = "name in function show()";  

      alert(this.name);   
 }  

  show();複製程式碼

這裡定義了一個全域性變數 name ,這個變數是屬於 window 的,在 show 函式裡也宣告瞭一個name 變數。

this 的定義是指向呼叫當前函式的那個物件, show() 函式是在全域性被呼叫的,所以this 應該指向的是當前 window物件。

再看下一個:

 var myObj = {   

     name: " my Object",

        show: function() {    

        var name = "my Object in function";  
 
         alert(this.name);  
      },  
  };   
 myObj.show();複製程式碼

這次,呼叫 myObj.show() 的物件是 myObj, 所以就會輸出  my Object

  • 陣列Array

先來個排序吧:

var arr = [ 2, 4, 50, 20, 3 ];複製程式碼

氣泡排序:

var arr = [ 2, 4, 50, 20, 3 ];

for(var i = 0 ; i < arr.length-1; i ++){

    for(var j = 0; j < arr.length-i; j++ ){

        var ls;

        if(arr[j] > arr[j+1]){

            ls = arr[j];

            arr[j] = arr[j+1]

            arr[j+1] = ls

        }
    }
}

console.log(arr);複製程式碼

其實我要開始想到的是用sort() ,但是sort排出來的不是很穩定,他預設排序是根據字串Unicode碼點。

還問我sort有幾個引數,第二個引數是什麼?

我當時沒想起來,後續整理出來吧!

可選引數是一個比較函式, compareFunction ,用來指定按某種順序進行排列的函式。如果省略,元素按照轉換為的字串的各個字元的Unicode位點進行排序。

  • 如果 compareFunction(a, b) 小於 0 ,那麼 a 會被排列到 b 之前;
  • 如果 compareFunction(a, b) 等於 0 , a 和 b 的相對位置不變;
  • 如果 compareFunction(a, b) 大於 0 , b 會被排列到 a 之前。
  • compareFunction(a, b) 必須總是對相同的輸入返回相同的比較結果,否則排序的結果將是不確定的。

要比較數字而非字串,比較函式可以簡單的以 a 減 b,如下的函式將會將陣列升序排列

function compareNumbers(a, b) {
  return a - b;
}複製程式碼

所以上邊那個排序就可以簡單的寫成:

var arr = [ 2, 4, 50, 20, 3 ];arr.sort(function (a, b) {

    return a - b;
});

console.log(arr);複製程式碼

或者更簡潔一點:

var arr = [ 2, 4, 50, 20, 3 ];

arr.sort((a, b) => a -b );

console.log(arr);複製程式碼

又給我改了一下,說怎麼用sort 來排序一個物件?

var obj = [
  { name: 'a', value: 21 },
  { name: 'b', value: 37 },
  { name: 'c', value: 45 },
  { name: 'd', value: -12 },
  { name: 'e' }
];複製程式碼

應該是這樣:

obj.sort(function (a, b) {

    return (a.value - b.value);

});複製程式碼

順便貼上MDN的詳解


零零碎碎的問了不少,其他的記不太清了,都是一些知識性的東西,不羅列了。

然後問了一些react、 redux相關的技術原理,生命週期、單向資料流、虛擬DOM等等。。。

這些我回答的還好,因為工作天天用這個,也比較熟悉,js基礎類的一些題回答的不太好,我也知道我js基礎不紮實,再者,面試題看少了,雖然這些基礎的知識點在工作中用的不多,有的記不清楚的就google了,也不會影響開發進度,但是,即便react 用的再熟練,重中之重的js基礎!才是最重要的,框架都是js寫的。

反思一下,之前工作中碰到了一些不會的或者生疏不常用的技術,google出來答案後直接就用上了,也沒有仔細的去研究其中的原理,知其然不知其所以然!

事後也沒有總結出來,下次再碰到這個技術點,可能又要google了。。。


不說廢話了!

整理一些網上看到的不錯的面試題:(轉載)

  1. 關於變數宣告提升和函式宣告提升

alert(a);

a();

var a=3;

function a(){

    alert(10)
}   

alert(a);

a=6;

a();
複製程式碼

果不其然,我自己看一遍的時候就分析錯了。

關鍵的一點就是:var 宣告的變數 和function生命的函式都會提前,只是提前到作用域開始的位置,但不會進行賦值操作;

1.函式宣告優先於變數宣告,所以,剛開始,a就是function a(){alert(10)} ,就會看到這個函式。
2.a(),執行函式,就是出現alert(10)
3.執行了var a=3; 所以alert(a)就是顯示3
4.由於a不是一個函式了,所以往下在執行到a()的時候, 報錯。 

再來看:

alert(a);

a();

var a=3;

var a=function(){

    alert(10)
}   
alert(a);

a=6;

a();
複製程式碼

區別是,函式這次用var宣告瞭,根據原理,他只是宣告被提前,但a 沒有被賦值為一個函式,

所以,一開始alert(a) 是undefined;

a() 報錯;

類似的題目:

 var a=0;

function aa(){

    alert(a);

    var a=3;
}

 aa();複製程式碼

在aa函式裡面,有var a=3,那麼在aa作用域裡面,就是把a這個變數宣告提前,但是不會賦值,所以是undefined

var a=0;

function aa(a){ 
 
    alert(a); 
 
    var a=3; 

};

aa(5);

alert(a);

//5,0   複製程式碼

在函式體內,引數a的優先順序高於變數a ;

var a=0;

function aa(a){

    alert(a);

    a=3;

    alert(a);

}
aa();

alert(a);
複製程式碼

首先沒有傳引數進去,aa() undefined

a=3,實際上修改的是形參a的值,並不是全域性變數a,往下alert(a)也是形參a;

最後的alert(a); 是全域性的a;


寫在最後

不說了!。。。

我要去刷面試題,繼續啃我的JavaScript 語言精粹了。



相關文章