时间匆匆,不知不觉大三就过了一半了,至今还没有面试过的小萌新就有想法了,趁着临近过年,在年前面一次试试水,为明年开学的春招做准备,所以做了一份简历,找了学长学姐聊了聊,试着内推了一下。整场面试(1小时)下来,暴露了自己的一些问题,文末有个人总结。
面试开始
面试是视频面,以下为个人知识总结,欢迎各位大佬指正。
经典自我介绍
我叫xxx,来自xxx,目前就读xxx大学,是一名大三学生。我将从以下三点来介绍自己:
- 校园经历:xxx...
- 项目经历:xxx...
- 学习习惯:xxx...
一、 你说有自己的理解你会输出一些文章,那你讲一讲你输出了那些文章
这问题一出,我愣了2-3秒,想了一下很快就概况讲了一下我少的可怜的三篇文章。主要是对文章的出现的场景和内容讲解。
二、你说axios中使用了Promise链式调用,那你讲一下Promise吧
一听Promise,呦呵,这不是面试常问吗?
- promise有三种状态:
pending
表示初始状态,fulfiled
表示成功状态,它对应的方法是resolve
,当你在Promise
回调中使用了resolve()
则会发生状态改变,变为成功状态,rejected
表示失败状态,对应的是reject()
,使用后状态变为失败。状态一旦改变就不会再变。 Promise
是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大,可以将异步操作以同步操作的流程表达出来,避免出现回调地狱
——层层嵌套的回调函数。Promise
一旦new
了就会立即执行,而且无法取消Promise
,如果不设置回调函数的话,Promise
内部出现的错误不会反映到外面。
三、Promise有哪些方法?
比较常见的有: resolve
, reject
,all
, race
, any
resolve
: 将传入的参数转为状态为fulfiled
的Promise
对象,参数会立即执行。如果参数本身就是一个Promise
,那么就会返回该Promise
本身。方法的参数,会原封不动地作为fulfiled
的理由,变成后续方法的参数。resolve()
的 Promise 对象,是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时。reject
:和resolve
类似,状态为reject
all
: 参数为一个Promise数组
,数组每个元素都是Promise
实例。如果不是Promise
,会调用Promise.resolve
将其转化为Promise
。只有数组中所有的Promise
状态都为fulfiled
,Promise
的状态才会变为fulfiled
,而且会将所有元素的返回值组成一个数组作为参数传递给调用all
的Promise
的回调函数。若数组中有一个状态变为rejectd
,会将第一个rejectd
的返回值作为参数传递给回调函数。race
: 同all
一样参数为一个Promise数组
,数组哪一个元素率先改变状态,那么就将他返回的结果和状态传递给回调函数。any
: 和race
很像,但不同的是any
不会随着一个rejectd
而结束Promise
,必须等所有都变为rejectd
才会结束。 当然还有其他方法,我这就不一一介绍了。
四、换个话题,css的position属性有哪些值?
一共五个值:inherit
, static
,relative
, absolute
, fixed
, sticky
,开启position
后,可以通过top
,right
,bottom
,left
四个属性来定位移动。
-
inherit
: 继承父元素的position
的值,如果父元素没有设置position
属性,则这个属性无效。 -
static
: 元素为正常布局行为,不会脱离文档流,top
等属性作用无效,效果相当于没有设置这个属性。 -
relative
: 相对定位,基于他原来位置来定位移动。原来的位置会留白。 -
absolute
: 绝对定位,元素会脱离文档流,不会占据文档流的位置,基于离它最近的非static
定位祖先元素来定位移动,绝对定位可也设置margin
,且不会产生边距重合问题。 -
fixed
:固定定位,元素会脱离文档流,也不会占据文档流的位置,它是基于屏幕视口来进行定位移动。元素的位置在屏幕滚动时不变,打印时,会出现在每页的固定位置。fixed
会创建新的层叠上下文,当祖先元素的transform
、perspective
或filter
属性非none时,容器会改为该祖先。 -
sticky
:粘性定位,在屏幕范围内该元素没有达到偏移阈值(设置的top
等属性),此时该元素设置的(top
,left
等属性)无效,而且没有脱离文档流,会产生留白效果,类似relative
的效果。如果该元素达到其设置的阈值,该元素则会变为固定定位的效果,会固定在阈值的位置,而且还是会有留白效果。总结一下:
sticky
没达到阈值就像relative
,达到或超过就会变为fixed
,且留白效果还存在。
五、display属性的block
, inline
, inline-block
的区别
block
: 设置后元素变为块级元素- 块级元素会独占一行,多个相邻的块级元素会各自新开一行,默认情况下,元素宽度自动占满其父元素宽度。
- 块级元素可以设置
width
和height
,即使设置width
,元素还是会独占一行,但多余的部分不在是width
,而是使用margin-right
填充满。 - block元素可以设置
margin
和padding
属性
inline
:设置后元素变为行内元素inline
元素不会独占一行,多个相邻的行内元素会排列在同一行里,直到一行排列不下,才会新换一行,其宽度随元素的内容而变化。- inline元素设置
width,height
属性无效。 - inline元素的
margin
和padding
属性,水平方向的padding-left, padding-right, margin-left, margin-right
都产生边距效果;但竖直方向的padding-top, padding-bottom, margin-top, margin-bottom
不会产生边距效果。
inline-block
: 设置后元素会变为行内块元素- 结合了inline与block的一些特点,结合了上述inline的第1个特点和block的第2,3个特点。
- 通俗讲就是不独占一行的块级元素。
默认下
inline
元素与其他元素之间会出现空白间隙,所以inline-blick
使用后同样也有。那么这些空白间隙是什么呢,都是空白符。
在浏览器中,空白符是不会被浏览器忽略的,多个空白符会合并为一个。而我们在编写代码的时候,使用的空格、换行都会产生空格符。如何解决呢
常用的方法就是给其父元素设置font-size:0
,本质上空白符也是一个字符,也受字体大小控制。
六、换一下js的吧,instanceOf了解吗
instanceof
运算符用于检测构造函数的prototype
属性是否出现在某个实例对象的原型链上。
function myInstanceof(left, right){
const baseType = ["number", "string", "boolean", "undefined", "symbol"]
if(left == null || baseType.includes(typeof left)) return false
let proto = left.__proto
while(true){
if(proto == null) return false
if(proto == right.prototype) return true
proto == proto.__proto
}
}
七、 [2,3,4] instanceOf Object
的结果是什么
答案是true
[2,3,4].__proto__ == Array.prototype
[2,3,4].__proto__.__proto__ == Object.prototype
八、 讲一下原型链
说起原型链,不禁让我想到一张图: (图来源于冴羽大佬的文章)
每一个构造函数实例都有一个__proto__
属性,它指向其构造函数的原型对象,当构造函数的原型对象指向另一个实例或者原型时,就形成了原型链。
__proto__
在绝大数浏览器都支持这个方法访问实例的原型,但在prototype
上并没用这个属性,可以理解使用了Object.getPrototypeOf(obj)
。
九、 出了一道题目
Object.prototype.a = "a"
Function.prototype.a = "a1"
function Person() {}
let yideng = new Person()
console.log(Person.a)
console.log(yideng.a)
console.log(yideng.__proto__.__proto__.constructor.constructor.constructor.constructor)
问上面代码中三个console.log
分别打印了什么?
答案为: 1."a1" 2."a" 3."[Function: Function]"
- 第一个
console.log
: 这里使用Person.a
,表示此时的Person
为一个实例,该实例上没有找到a
属性,所以会去他的原型对象上找,相当于Person.__proto__.a
,Person
是Function
构造函数的一个实例,所以Person.__proto__ == Function.prototype
,此时Function.prototype
上有a
属性,就将其值"a1"
返回。 - 第二个
console.log
:这里的yideng
是Person
构造函数的一个实例,该实例上没有a
属性,去它原型Person.prototype
上找,也没有找到,则会去Person.prototype.__proto__
上找,也就是Object.prototype
,找到了a
属性并返回结果。
yideng.__proto__ === Person.prototype
yideng.__proto__.__proto__ == Person.prototype.__proto__
Person.prototype.__proto__ == Object.prototype
- 第三个
console.log
: 这里在第二个延伸了一下,相当于Object.prototype
点一连串的constructor
Object.prototype.constructor //ƒ Object() { [native code] }
Object.prototype.constructor.constructor //ƒ Function() { [native code] }
Object.prototype.constructor.constructor.constructor // ƒ Function() { [native code] }
...
在多的.constructor
都是ƒ Function() { [native code] }
十、 也是一道题
$("test").click(function (){
console.log("2")
})
setTimeout(()=>{
console.log("1")
},0)
while(true){
console.log(Math.random())
}
上面click
和setTimeout
会执行打印吗?
答案: 不会
因为click
是一个事件、setTimeout
是一个定时器,他们都属于异步任务,在当前所有同步代码执行完后,才会执行异步任务。而while(true)
这段同步任务会一直打印一个随机数,不会结束,导致阻塞了主进程,就算异步任务满足条件也不会执行。
讲一讲Event Loop
同步和异步的执行顺序
- JavaScript将任务分为同步任务和异步任务,首先同步任务进入主线程,碰到异步任务后,将其放入
Event Table
进行回调函数注册 - 当异步任务的触发条件满足条件后,会将其回调函数从
Event Table
压入Event Queue
中。 - 当主线程里的同步任务执行完毕后,会从
Event Queue
中读取异步的回调函数。
- 只要主线程没有任务可以执行了,就会去
Event Queue
中读取异步的回调函数,这个过程叫做Event Loop
这样会存在很多问题,举个例子:(例子来自Jiasm的文章)
在柜台办理业务,你前边的一位老大爷可能在存款,在存款这个业务办理完以后,
柜员会问老大爷还有没有其他需要办理的业务,这时老大爷想了一下:“最近P2P爆雷有点儿多,是不是要选择稳一些的理财呢”,
然后告诉柜员说,要办一些理财的业务,这时候柜员肯定不能告诉老大爷说:“您再上后边取个号去,重新排队”。 所以本来快轮到你来办理业务,会因为老大爷临时添加的“理财业务”而往后推。 也许老大爷在办完理财以后还想 再办一个信用卡?或者 再买点儿纪念币
相当于在setTimeout
中在定义了很多别的异步任务,按之前的说法,那么他只会在外层的setTimeout
满足条件后执行后才会将其内部的异步回调注册进入Event Table
中,这就不符合实际情况。
所以引入了宏任务
和微任务
异步任务概念。setTimeout
就是作为宏任务来存在的,而Promise.then
则是具有代表性的微任务,
这里就需要对同步、异步、宏任务、微任务的执行顺序有一个清楚的认知。
- 首先执行同步代码,每一个
script
都属于一个宏任务。 - 所有同步代码执行完毕,去查看是否有异步代码需要执行。
- 如果有的话执行异步代码中的微任务。
- 所以微任务执行后,至此第一轮Event Loop就结束了。(之后就是渲染)
- 开始新的一轮Event Loop,开始执行异步任务中的宏任务。
并且在浏览器中引入了多线程的使用,事件触发线程
、定时器触发线程
、js引擎线程
、异步Http请求线程
、GUI渲染线程
。
面试个人总结
- 面试的时候要沉稳一些,不要急躁。
- 回答问题前要思考思考,组织一下回答的语言
- 回答问题的时候最好想好一个流程,引导面试官提问准备好的。
- 回答问题时,建议回答清晰,举例一个情境,问题出现的原因和解决方案。
如果面试前紧张,最好在面试前睡一会,静下心回顾一下基础知识。临近面试如果还是紧张,建议什么都不想,听一首音乐,轻轻哼唱。