ITPub博客

首页 > 应用开发 > Java > 当裸辞遇到了面试难,你需要了解一下这些面试题

当裸辞遇到了面试难,你需要了解一下这些面试题

Java 作者:喝水会长肉 时间:2021-12-23 14:06:36 0 删除 编辑

为了让更多的小伙伴可以在面试的时候取的更好的 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中已经有了属性(索引) 2和 3,所以在 push的时候会覆盖掉 2和 3上面的默认值。

所以在 nodejs中就会输出


{ 
'2'
: 
1
,

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

但是在 chrome控制台中输出

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

很奇怪,为什么会输出这样呢?这一块有一个很特殊的陷阱,就是 chrome控制台是如何判断打印的内容是数组还是其他对象呢?对于这个, chrome就是通过判断对象上面是否有 splice和 length这两个属性来判断的,所以如果你将 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. 。。。 依次类推

其实对于这道题,可以使用 2的 n次方来判断,比如有 32瓶水,那么就是 2的 5次方,所以就需要 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, 然后因为这时候 fn的 this是 window,  this.num += n相当于 window.num += n, 即 window.num = 65

6. num++, 因为闭包的原因,第三步 num是 21,所以这一步  num变成了 22, 同时输出 22

7.然后 obj.fn(10),这时候 fn的 this为 obj, obj.num默认值是 20,  this.num += n相当于  obj.num += 10

8.和第七步一样,  num + 1 输出  23

9. console.log(num, obj.num)相当于  console.log(window.num, obj.num),从上面几步可知,  window.num = 65,  obj.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.如果非 number与 number比较,会将其转换为 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) 是 1,  Number(false)是 0, 所以结果是  1


// 输出 1 

console . log ( true + false )

https://shimo.im/docs/tJK3DJjRkdkrpygK   J ava  最常见 的 200+ 面试题:面试必备

总结

面试造火箭,工作拧螺丝。虽然我只想拧螺丝,但是我却需要通过造火箭来找到拧螺丝的工作,每日一题,每天都有新的面试题目,

结语

不要吹灭你的灵感和你的想象力; 不要成为你的模型的奴隶。 ——文森特・梵高



来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70010294/viewspace-2849058/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2021-11-19

  • 博文量
    199
  • 访问量
    86383