腾讯前端暑期实习一面小记

刚面完腾讯前端一面,记一下自己没答出来的东西。基础这方面还是太差了一些,学校学的完全不够这些公司招聘的笔面,趁着记忆还热乎,写一下。

JavaScript 闭包

闭包存在很多变量在外面没有办法回收,可能存在内存溢出的问题,所以要怎么处理变量。

这里问到了一个变量销毁,我答的是赋值undefined,但是面试官不满意这个答案,我提到是否是原型链不能废除。

对于原型链这个问题,null确实是没有原型链的,其顶层如果是null的话那么实际上它就不存在了。但是这个不是这个问题涉及到的东西。

面试官提到undefined好像是不能销毁的,要用null,null可以强制解除所有的引用。对于null可以强制解除引用这一点是无可置疑的,这个确实是这样,但是undefined是不是也能让一个变量消失,被GC回收,我查了很多资料,虽然感觉上是可以的,但是存在这样一个问题,比如下面这段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// declare x with the var keyword
var x = 1; // 1
document.write(typeof x); // number
document.write(window.hasOwnProperty(x)); // false

// delete x does not work.
delete x;
document.write(x); // 1
document.write(typeof x); // number
document.write(window.hasOwnProperty(x)); // false

x=null; // null
document.write(typeof x); // object
document.write(window.hasOwnProperty(x)); // false

x=undefined; // undefined
document.write(typeof x); // undefined
document.write(window.hasOwnProperty(x)); // true

设置成undefined并不能解决它在全局作用域下存在,下挂在了window上这个问题。GC一定要在变量没有任何引用的情况下才回去回收,所以设置成null确实是正解。

对于原型链,null的原型是null,不存在原型链,所以也不存在原型链问题。

JavaScript 递归

递归并没有问到递归的缺点或者某个东西的递归写法,问到的是工程上的问题。

1
2
3
4
5
6
function a(args){
if (某个条件) {
return ...;
}
a(args);
}

这是一个正常的递归写法,但是对于大工程来说一个方法很长,如果改了a这个函数名就要改两个地方,里面的递归方法名也要用,有没有办法解决这个问题,让函数自己调用自己。

我答的是用call(this),被追问call没有调用者,我答的是用Function.prototype。但这是错解,正确解法是函数里面有个arguments对象,可以用arguments.callee(args)来进行递归。

JavaScript 事件

事件问到了事件的生命周期,事件本身就是先捕获再冒泡,从Window依次往下在从元素本身依次往上。

然后提到了一个例子:

1
2
3
4
5
6
function clicked(e) {
e.stopPropagation();
console.log(e.target);
console.log(e.currentTarget);
console.log(e.relatedTarget);
}

我用了下面这个文件来测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<html>
<body>
<div>
<span>123</span>
<div id="test">
<span>456</span>
</div>
<div id="test2">
<span>789</span>
</div>
</div>
<script>
var test = document.getElementById('test');
test.addEventListener('click', (e) => {
e.stopPropagation();
console.log(e.target);
console.log(e.currentTarget);
console.log(e.relatedTarget);
});
</script>
</body>
</html>

e下面有三种target,分别是e.target、e.currentTarget、e.relatedTarget。

e.target是用户点了哪个元素会是哪个,不论有没有stopPropagation,e.target都会是用户点击的那个元素,即使我们绑定到了父元素上。

e.currentTarget指的是绑定事件监听的对象,这里是test,自然会输出test这个div,虽然它是span的父元素,且停止了冒泡。但是这一行输出不影响。

e.relatedTarget是和这个事件目标节点相关的节点,比如mouseover或者mouseout,e.relatedTarget就会是进入/离开目标节点鼠标离开/进入的那个节点。

stopPropagation存不存在三行输出都会是span、test div、null。

这里因为之前没有了解过e.currentTarget和e.relatedTarget(也有一定成分是没有听懂)说了没有接触过,接触过了这题过没有太多问题。

JavaScript this指向

考了一个this指向的问题,模型根据面试官的意思大概是这样:

1
2
3
4
5
var o = {
a: () => {
return () => { console.log(this); }
}
}

问执行o.a()()输出的this是什么。

匿名函数的this指向都是在Window上,这个没有调用者,没问题。

但是可能是我理解错了这个模型,根据我的思考,对于下面这个模型:

1
2
3
4
5
var o = {
a: function t() {
return () => { console.log(this); }
}
}

这里调用o.a()(),this的指向是在o上的,我的回答是指向在o上,这也是这个this指向的正确结果。但是面试官的意思是答案不对,所以我反复确认了模型的细节,如果是匿名函数返回匿名函数的话,那么确实是指向window。

JavaScript DOM操作

DOM操作问的是document.createElement()和document.createDocumentFragment(),问什么时候用前者什么时候用后者,没接触过后者,跳了。

后者是创建一个文档片段,里面可以包含很多的DOM节点(相当于是虚拟了一个根节点出来展开一个树),然后作为一个整体一次性操作,document.createElement()只能操作单一的节点或者这个节点展开的树。

JavaScript 新特性

面试官提到了Array这边的新特性,应该问的是Array.prototype.includes(),我答没怎么用过(有一定没听清的成分),这一块跳过,其实回过头来看不应该调过的。

之后问到了Promise和async、await,什么时候用前者什么时候用后者。这个问题难度不高这里不写,略过。

参考:
ES6、ES7、ES8、ES9、ES10新特性一览

Vue 生命周期

这个link到官方文档就是:

Vue生命周期图示

Vue 请求

问到了Vue怎么请求,会不会遇到什么问题。我答请求用的是axios,但是没有意识到面试官想问的可能是跨域,而是谈了axios的坑,是发挥问题,问到这里已经思维已经开始迟滞了。

面试官提示了还有没有其他问题,但是脑子空白没想到跨域这个点上。

axios的坑是POST这个,它默认请求头application/json,如果要按表单的方式提交需要另外配置一下。

对于跨域问题,link到之前的笔记:
前端跨域问题小记

Vue router

vue-router是Vue的基础件,面试官问到了router有个导航守卫,这个是vue-router文档进阶部分的东西。

面试官问到router的钩子函数是在什么地方执行的,和beforeCreate谁先。

由于我对这个导航守卫不太了解所以他一说钩子函数有点懵,然后说对钩子不太了解,但是是在beforeCreate前,路由是先执行它的逻辑。

面试官提到一个场景,如果有一个页面没权限的不允许他访问,在路由上就要卡下来而不是进入到beforeCreate,这个时候要设置全局前置守卫。

根据路由的生命周期,全局前置守卫在路由跳转前触发,页面没有加载机会,更没有beforeCreate一说。

全局解析守卫是路径在路由其他守卫和路由组件解析了之后,但是在跳转前触发的。

全局后置钩子和是在路由跳转完成后触发。

参考:
导航守卫 | Vue Router

Vue watch

这里问到了一个watch是从Vue生命周期哪个节点开始生效的,这个其实也是生命周期的问题,涉及到里面的细节,但是很遗憾细节没有记清楚,没有答上。一开始回答的是created后,但是面试官提到在created之前也能观测到router。

之后面试官反复提到你觉得这个时候beforeCreate完成了吗(记忆不是很清楚了,也可能是created,如果是created的话那我就完全答错)。

我的答案是完成了。面试官提到因为router在这个阶段也可以被观测到,但是router如果设置了守卫它的执行在beforeCreate前面,而watch可以观测到router,所以watch在监测变量的时候beforeCreate完成了吗。这里我坚持回答完成了,但是我的考虑方向不对,我的思路是变量都还没有初始化没办法观测,会出问题。

根据Vue的生命周期,Vue是在beforeCreate到created中间就已经开始观测数据,watch在这个时候就已经能够生效了。$router、$route是在这个阶段初始化的,而不是在beforeCreate之前,但是created被调用的时候它们已经被初始化且被观测。

CSS

CSS是两个问题,px、rem、em、vw、vh什么时候用,还有水平垂直居中,这里略过。

其他

有让介绍一下项目,我很简单的说了一下没深挖,然后问了一下前端的未来发展趋势和新技术,我谈到了就是框架、Serverless和Electron,用前端扩展到客户端,Serverless小谈了一下没有深入。

面试官提到前端的方向还有数据可视化、GraphQL这方面以及结合wasm做项目,我一时间想到的还是太窄了点。

Vue发请求部分顺便问到了一些状态码,这个我有个别脑子空白想不到了,还是记得不够深刻,要再多看看。

样式部分问到了一个移动端专站和响应式的问题,这个我答的是分情况看。

小结

面得很一般,应该是凉了。JavaScript基础和Vue的基础还是太薄弱,好多问题不知道,这个估计是不行的,如果有二面的话那是比较奇迹的事情了。

结果还没更新,希望运气能好一点。这个面试也是第一次,感受到了难度,该看的还是要多看看,特别是基础这一方面。