首页 > 应用开发 > Java > 当裸辞遇到了面试难,你需要了解一下这些面试题
为了让更多的小伙伴可以在面试的时候取的更好的
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
那么我们就可以这样去判断:
甲乙丙丁都死了,说明第一瓶有毒
甲乙丙死了,说明第二瓶有毒
甲乙丁死了,说明第三瓶有毒
甲乙死了,说明第四瓶有毒
甲丙丁死了,说明第五瓶有毒
。。。 依次类推
其实对于这道题,可以使用
2的
n次方来判断,比如有
32瓶水,那么就是
2的
5次方,所以就需要
5只小鼠。
在
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指向相关的问题。
请说出以下代码输出的内容
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
)
我们把上面的代码分为以下几步进行分析
先看第三行代码,是一个赋值操作,我们知道赋值操作是从右向左的,而
=号右边是一个立即执行函数,所以会优先执行立即执行函数,立即执行函数没有手动指定
this,这时候
this = window,而立即函数的参数
num是传进来的
obj.num,所以
num参数默认值是
20
第四行相当于
window.num = 20 * 3
第五行为传入的参数加一,所以
num = 20 + 1
第六行
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
)
一起来看看答案吧
第一行代码
// 输出 "" 空字符串
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/ ,如需转载,请注明出处,否则将追究法律责任。