當裸辭遇到了面試難,你需要了解一下這些面試題

喝水會長肉發表於2021-12-23

為了讓更多的小夥伴可以在面試的時候取的更好的 offer,所以今天起我每天都會推送一到兩道面試題,俗稱每日一題(每日一坑)。方便找工作的小夥伴每日都會有新的收穫。


一道類陣列相關面試題

什麼是類陣列,類陣列就是 擁有 length屬性,且其他屬性(索引)為非負整數的物件,且不具備陣列所用於的方法。比如我們常用的 document.querySelectorAll返回的 NodeLists就是一個類陣列。這道題就是和類陣列相關的內容.

題目

請說出以下程式碼輸出的內容,需要區分 nodejs, chrome以及 chrome去掉 splice之後的輸出內容


var obj 
= 
{

    '2' : 3 ,
    '3' : 4 ,
    'length' : 2 ,
    'splice' : Array .prototype .splice ,
    'push' : Array .prototype .push
}
obj . push ( 1 )
obj . push ( 2 )
console . log (obj )

答案

這道題一共問了三種情況下面的輸出,下面依次說明答案

 1. node下面輸出


{ 
'2'
: 
1
,

  '3' : 2 ,
 length : 4 ,
 splice : [Function : splice ] ,
 push : [Function : push ] }

  2.chrome下面輸出


[empty × 
2
, 
1
, 
2
, splice
: ƒ
, push
: ƒ
]

3.chrome去掉 splice下面輸出

{2: 1, 3: 2, length: 4, push: ƒ}

通過上面輸出的內容,可以看出相同的程式碼,不同情況輸出的內容是有所不同的,下面進行詳細分解。

題解

在解答題目之前,我們再看看這段程式碼


const arr 
= 
new 
Array
(
2
)

// 輸出  2 [empty * 2]
console . log (arr .length , arr )
arr . push ( 1 )
// 輸出  3 [empty * 2, 1]
console . log (arr .length , arr )

可以看到 push方法會將陣列的 length + 1, 然後將值放在索引為 length - 1的位置,比如上面的程式碼,因為在初始化陣列的時候,已經將陣列長度指定為了 2, 所以在 push之後 length就變成了 3,然後 arr[3 - 1] = 1

MDN上面對 push的方法的解釋是:

push 方法具有通用性。該方法和  call() 或  apply() 一起使用時,可應用在類似陣列的物件上。 push 方法根據  length 屬性來決定從哪裡開始插入給定的值。如果  length 不能被轉成一個數值,則插入的元素索引為 0,包括  length 不存在時。當  length 不存在時,將會建立它。

根據 MDN解釋, push既可以使用到陣列中,也可以使用到類陣列中。而根據前文中對類陣列的解釋,可以看到題目中的 obj就是一個標準的類陣列,那就可以在 obj上面使用陣列的 push方法。

再看 obj.push(1), 因為 obj.length = 2, 所以會將 length + 1就變成了 3, 這時候 索引值時 obj[3 - 1] = 1 即 obj[2] = 1, 同理  obj.push(2) 也一樣的。因為在 obj中已經有了屬性(索引) 23,所以在 push的時候會覆蓋掉 23上面的預設值。

所以在 nodejs中就會輸出


{ 
'2'
: 
1
,

  '3' : 2 ,
 length : 4 ,
 splice : [Function : splice ] ,
 push : [Function : push ] }

但是在 chrome控制檯中輸出

[empty × 2, 1, 2, splice: ƒ, push: ƒ]

很奇怪,為什麼會輸出這樣呢?這一塊有一個很特殊的陷阱,就是 chrome控制檯是如何判斷列印的內容是陣列還是其他物件呢?對於這個, chrome就是通過判斷物件上面是否有 splicelength這兩個屬性來判斷的,所以如果你將 splice去掉之後,就會輸出以下內容


{
2
: 
1
, 
3
: 
2
, length
: 
4
, push
: ƒ
}

你也可以試試下面的程式碼:

console
.
log
(
{
splice
:
function
(
)
{
}
,length
:
1
}
)

console . log ( { slice : function ( ) { } ,length : 1 } )

邏輯面試題之小鼠喝毒-藥

小編當年畢業的時候面試就遇到過好幾次邏輯類的面試題,這道題就是一道邏輯類的面試題,一起來看看。

題目

有16瓶水,其中只有一瓶水有毒,小白鼠喝一滴之後一小時會死,請問最少用多少隻小白鼠,在1小時的時間一定可以找出有毒的水?

答案與題解

答案是至少需要 4只小鼠,怎麼理解呢?我們可以用二進位制去推理一下:

假設有4只小鼠,分別是甲乙丙丁,使用二進位制來表示小鼠喝藥的順序, 1代表喝藥, 0代表不喝藥

甲:  1111 1111 0000 0000

乙:  1111 0000 1111 0000

丙:  1100 1100 1100 1100

丁:  1010 1010 1010 1010

那麼我們就可以這樣去判斷:

  1. 甲乙丙丁都死了,說明第一瓶有毒

  2. 甲乙丙死了,說明第二瓶有毒

  3. 甲乙丁死了,說明第三瓶有毒

  4. 甲乙死了,說明第四瓶有毒

  5. 甲丙丁死了,說明第五瓶有毒

  6. 。。。 依次類推

其實對於這道題,可以使用 2n次方來判斷,比如有 32瓶水,那麼就是 25次方,所以就需要 5只小鼠。

arguments 面試題

ES6中,我們如果一個函式引數個數不確定,我們一般會使用擴充套件運算子即 function(...rest){},得到一個引數陣列 rest,但是在 ES6之前,我們是不能使用擴充套件運算子的,這時候就需要考慮使用 arguments

題目

請說出以下程式輸出的內容(chrome輸出內容)


let obj 
= 
{

 age : 18 ,
  foo : function ( func ) {
    func ( )
   arguments [ 0 ] ( )
  }
}

var age = 10
function fn ( ) {
 console . log ( this .age )
}

obj . foo (fn )

答案

本題的答案是:


// 第一個輸出 10

func ( )
// 第一個輸出 undefined
arguments [ 0 ] ( )

有點出乎意料了嗎?

先來解釋一下第一個,為什麼不是輸出 18呢,雖然 func()是在 foo函式裡面呼叫的,但是並沒有顯式指明作用域,這時候會使用預設作用域 window,而對於瀏覽器來說,在全域性通過 var宣告的變數會自動掛載到 window上面,所以 var age = 10相當於 window.age = 10, 而第一個 func()裡面的 this.age相當於 window.age

第二個可能許多人有點蒙,為啥是 undefined,先看一下下面的程式碼


const arr 
= 
[
function
(
) 
{console
.
log
(
this
[
1
]
)
}
, 
'我是子君'
]

// 輸出 我是子君
console . log (arr [ 0 ] ( ) )

我們通過 arr[0]獲取到函式,這時候函式的作用域就是這個陣列,所以再呼叫的時候, this就是 arr, 所以 this[1]就是陣列第二項。

這時候回過頭來看 arguments,這個其實是一個類陣列,裡面存的是函式傳入的引數,第一項就是傳入的函式,和上面例子一樣, arguments[0]的作用域就是 arguments,而 arguments上面並沒有 age屬性,所以是 undefined

this指向問題

this指向問題一直是比較混亂的,在箭頭函式出現之前, this的指向與程式碼在哪裡定義並沒有關係,而是取決於是被誰執行的,正因為此,所以許多開發人員經常會搞不清楚 this到底是誰。下面的兩道題都是和 this指向相關的問題。

題目一(青銅)

請說出以下程式碼輸出的內容


var num 
= 
1
;

let obj = {
   num : 2 ,
    add : function ( ) {
        this .num = 3 ;
        ( function ( ) {
           console . log ( this .num ) ;
            this .num = 4 ;
        } ) ( ) ;
       console . log ( this .num ) ;
    } ,
    sub : function ( ) {
       console . log ( this .num )
    }
}
obj . add ( ) ;
console . log (obj .num ) ;
console . log (num ) ;
const sub = obj .sub ;
sub ( ) ;

題目二(黃金)

請說出以下程式碼輸出的內容


var num 
= 
10

const obj = {num : 20 }
obj .fn = ( function ( num ) {
  this .num = num * 3
 num ++
  return function ( n ) {
    this .num += n
   num ++
   console . log (num )
  }
} ) (obj .num )
var fn = obj .fn
fn ( 5 )
obj . fn ( 10 )
console . log (num , obj .num )

答案

題目一

輸出結果:  1, 3, 3, 4, 4, 你答對了嗎?下面我們來看看程式碼解析


var num 
= 
1
;

let obj = {
   num : 2 ,
    add : function ( ) {
        this .num = 3 ;
      // 這裡的立即指向函式,因為我們沒有手動去指定它的this指向,所以都會指向window
        ( function ( ) {
            // 所有這個 this.num 就等於 window.num
           console . log ( this .num ) ;
            this .num = 4 ;
        } ) ( ) ;
       console . log ( this .num ) ;
    } ,
    sub : function ( ) {
       console . log ( this .num )
    }
}
// 下面逐行說明列印的內容
//java學習交流:737251827  進入可領取學習資源及對十年開發經驗大佬提問,免費解答!
/**
* 在通過obj.add 呼叫add 函式時,函式的this指向的是obj,這時候第一個this.num=3
* 相當於 obj.num = 3 但是裡面的立即指向函式this依然是window,
* 所以 立即執行函式裡面console.log(this.num)輸出1,同時 window.num = 4
*立即執行函式之後,再輸出`this.num`,這時候`this`是`obj`,所以輸出3
*/

obj . add ( ) // 輸出 1 3

// 通過上面`obj.add`的執行,obj.name 已經變成了3
console . log (obj .num ) // 輸出3
// 這個num是 window.num
console . log (num ) // 輸出4
// 如果將obj.sub 賦值給一個新的變數,那麼這個函式的作用域將會變成新變數的作用域
const sub = obj .sub
// 作用域變成了window window.num 是 4
sub ( ) // 輸出4

題目二

輸出結果為:  22  23  65  30, 你答對了嗎? 下面我們解析一下


var num 
= 
10

const obj = {num : 20 }
obj .fn = ( function ( num ) {
  this .num = num * 3
 num ++
  return function ( n ) {
    this .num += n
   num ++
   console . log (num )
  }
} ) (obj .num )
var fn = obj .fn
fn ( 5 )
obj . fn ( 10 )
console . log (num , obj .num )

我們把上面的程式碼分為以下幾步進行分析

  1. 先看第三行程式碼,是一個賦值操作,我們知道賦值操作是從右向左的,而 =號右邊是一個立即執行函式,所以會優先執行立即執行函式,立即執行函式沒有手動指定 this,這時候 this = window,而立即函式的引數 num是傳進來的 obj.num,所以 num引數預設值是  20

  2. 第四行相當於 window.num = 20 * 3

  3. 第五行為傳入的引數加一,所以  num = 20 + 1

  4. 第六行 return了一個函式,而這個函式就是 obj.fn的值, 但是因為 return的函式引用了立即執行函式裡面的 num,所以形成了閉包。這時候

    var fn = obj.fn, 將 obj.fn賦值給新的變數,而這個變數的作用域是 window

obj
.
fn 
= 
function
(
n
) 
{

  this .num += n
  // 這個num是立即執行函式裡面的num
 num ++
 console . log (num )
}

 5. 在呼叫 fn(5)的時候, 在第二步, window.num的值已經變成了 60, 然後因為這時候 fnthiswindowthis.num += n相當於 window.num += n, 即 window.num = 65

6. num++, 因為閉包的原因,第三步 num21,所以這一步  num變成了 22, 同時輸出 22

7.然後 obj.fn(10),這時候 fnthisobj, obj.num預設值是 20this.num += n相當於  obj.num += 10

8.和第七步一樣,  num + 1 輸出  23

9. console.log(num, obj.num)相當於  console.log(window.num, obj.num),從上面幾步可知,  window.num = 65obj.num = 30

擴充套件題

如果將上面兩道題的  var改成  let, 又會輸出什麼結果呢?

資料型別轉換問題

雖然在日常開發中,我們隱氏型別轉換用的比較少(不一定),但是這個還是面試常問問題,掌握還是要掌握的,一起來看看這道題目吧.

題目(王炸/青銅,我也不知道)

請說出以下程式碼輸出的內容

console
.
log
(
[
] 
+ 
[
]
)

console . log ( { } + [ ] )
console . log ( [ ] == ! [ ] )
console . log ( true + false )

答案

一起來看看答案吧

  1. 第一行程式碼


// 輸出 "" 空字串

console . log ( [ ] + [ ] )

這行程式碼輸出的是空字串 "", 包裝型別在運算的時候,會先呼叫 valueOf方法,如果 valueOf返回的還是包裝型別,那麼再呼叫 toString方法


// 還是 陣列

const val = [ ] . valueOf ( )
// 陣列 toString 預設會將陣列各項使用逗號 "," 隔開, 比如 [1,2,3].toSting 變成了"1,2,3",空陣列 toString 就是空字串
const val1 = val . toString ( ) // val1 是空字串

所以上面的程式碼相當於

console.log("" + "")

2.第二行程式碼

和第一題道理一樣,物件  {}隱氏轉換成了 [object Object],然後與 ""相加


// 輸出 "[object Object]" 

console . log ( { } + [ ] )

3. 第三行程式碼對於 ===, 會嚴格比較兩者的值,但是對於 ==就不一樣了

1. 比如  null == undefined

2.如果非 numbernumber比較,會將其轉換為 number

3.如果比較的雙方中由一方是 boolean,那麼會先將 boolean轉換為 number

所以對於上面的程式碼,看下面一步一步分析


// 這個輸出 false

console . log ( ! [ ] )
// 套用上面第三條 將 false 轉換為 數值
// 這個輸出 0
console . log ( Number ( false ) )
// 包裝型別與 基本型別 == 先將包裝型別通過 valueOf toString 轉換為基本型別
// 輸出 ""
console . log ( [ ] . toString ( ) )
// 套用第2條, 將空字串轉換為數值、
// 輸出 0
console . log ( Number ( "" ) )
// 所以
console . log ( 0 == 0 )

4. 第四行程式碼

兩個基本型別相加,如果其中一方是字元,則將其他的轉換為字元相加,否則將型別轉換為 Number,然後相加,  Number(true) 是 1Number(false)0, 所以結果是  1


// 輸出 1 

console . log ( true + false )

J ava  最常見 的 200+ 面試題:面試必備

總結

面試造火箭,工作擰螺絲。雖然我只想擰螺絲,但是我卻需要通過造火箭來找到擰螺絲的工作,每日一題,每天都有新的面試題目,

結語

不要吹滅你的靈感和你的想象力; 不要成為你的模型的奴隸。 ——文森特・梵高



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

相關文章