腾讯前端面经一面
写在前面
博主现在读大三,前端小白一只,上一个随笔发出了最近的美团一面的面试题与注意事项,这里博主整理了一下腾讯二月二十九日的第一次面试题与解题思路,注意事项,希望对大家的面试有所帮助。
面试题相关
垂直居中问题
题目
屏幕正中间有一个元素A,随着屏幕宽度的增加,需要满足以下条件:
- A元素垂直居中于屏幕中央;
- A元素距离屏幕左右边距各10px;
- A元素里面的文字"A"的font-size:20px;水平垂直居中;
- A元素高度始终为A元素宽度的50%;(如果搞不定可以实现为A元素的高度固定为200px)
请用html及css实现
解题思路
这个题目考察的是主要是垂直居中的措施,具体的方法大家可以自行查找,这里贴出我自己的代码。主要的地方是使用calc计算属性去设置左右边距,然后height也顺带实现A元素高度始终为A元素宽度的50%
<!-- CSS -->
* {
margin: 0;
padding: 0;
}
body {
100%;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.fa-area {
position: relative;
calc(100% - 20px);
height: calc(50% - 10px);
margin-left: 10px;
background-color: #376AF3;
}
.fa-area>div {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
color: #fff;
font-size: 20px;
}
<!-- html -->
<div class="fa-area">
<div>A</div>
</div>
arguments
题目
函数中的arguments是数组吗?若不是,如何将它转化为真正的数组?
解题思路
这个题目考察对arguments的认识,以及call的使用,并没有提及手写call函数。
不是
转化方案:
arguments = [].slice.call(arguments);
隐式类型转换
题目
请说出以下代码打印的结果
if([] == false) {console.log(1);}
if({} == false) {console.log(2);}
if([]) {console.log(3);}
if([1] == [1]) {console.log(4);}
解题思路
这个题目主要考察对JS隐式转换的知识。
值得注意的是,当使用 == 的时候,JS会将两侧数据转换为number值,再进行==判断,再转换为bool值。所以第一行会打印,第二行不会打印(这里的原因是,对象转number的时候,会调用toString()方法,返回一个字符串直接量,js将这个字符串转换成数字类型,并返回这个数字。这一段在《JavaScript权威指南》可以查到)。
而若直接空数组转bool的话,所有的对象object,用于判断条件时就会被转化为true,所以第三行会打印。
第四行的话,对象是引用类型,看起来都是一样的两个空数组,但是其实是不同的两个对象,在内存中的地址是不同的,所以第四行不打印。
这里当时不太明白,所以只根据自己的想象打出了答案,但是没有讲出1、2、3行的理由。
答:1 3
异步问题
题目
请说出以下代码打印的结果
async function async1(){
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2(){
console.log('async2');
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
});
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');
解题思路
这个题目主要考察对JS异步、JS执行机制的知识。
这题其实我没有很大把握,所以面试官准许我放在node环境下打印后问我原因,然后根据async1、async2的样子写出对应的Promise语句。
new Promise((resolve) => {
console.log('async1 start');
new Promise((resolve1) => {
console.log('async2');
})
}).then(() => {
console.log('async1 end');
})
JS是一个单线程语言,所以是按照语句的执行顺序执行的。一般任务分为两类
- 同步任务:该任务在主线程上排队,一次执行
- 异步任务:没有立马执行的任务,放在任务队列中执行
而除了这两种,任务还可以分为以下两种
- 宏任务:整体代码script,setTimeout,setInterval等
- 微任务:Promise,process.nextTick等
在event loop中,宏任务执行完后,会判断内部有无可执行微任务,若有则执行可执行微任务,若无则执行接下来的宏任务。
所以我们可以这么分析这类题目:先执行宏代码,遇到微任务就先加入队列等待执行,宏任务执行完后按入队列顺序执行,再执行setTimeout队列代码。
答:
script start
async1 start
async2
promise1
script end
promise2
async1 end
setTimeout
this指向
题目
以最小的改动解决以下代码的错误(可以使用ES6)
const obj = {
name: 'jsCoder',
skill: ['es6', 'react', 'angular'],
say: function () {
for (var i = 0, len = this.skill.length; i < len; i++) {
setTimeout(function() {
console.log('N0.' + i + this.name);
console.log(this.skill[i]);
console.log('------------------');
}, 0);
console.log(i);
}
}
}
obj.say();
// 期望得到以下结果
1
2
3
N0.1 jsCoder
es6
------------------
N0.2 jsCoder
react
------------------
N0.3 jsCoder
angular
------------------
解题思路
这个题目主要考察对this指向、闭包的知识。
最初运行的时候是报错了,显示数组越界,所以for循环里的i
改成了i + 1
,然后var i = 0
改成了let i = 0
处理了这里的闭包问题(我并不希望setTimeout
里面的i
全是4
),然后this
的指向我是使用了匿名函数取代了setTimeout
里面的函数,或者大家可以在外面使用var that = this;
来绑定this
。
以下是我的答案:
const obj = {
name: 'jsCoder',
skill: ['es6', 'react', 'angular'],
say: function () {
for (let i = 0, len = this.skill.length; i < len; i++) {
setTimeout(()=> {
console.log('N0.' + (i + 1) + this.name);
console.log(this.skill[i]);
console.log('------------------');
}, 0);
console.log(i + 1);
}
}
}
obj.say();
手写bind
题目
实现Function的bind方法
解题思路
这个bind方法在各个博客中都有很详细的原理与解析,所以这里我只将我的答案贴上,希望轻喷。
Function.prototype.bind = function (context) {
// 这里要存一下this而不能把返回里的函数对象转为匿名函数
// 因为这本身就是为了因为bind()函数发布在ES5中,不能很好的兼容所有浏览器
var self = this;
return function () {
return self.apply(context, arguments);
}
}
手写节流函数
题目
实现一个节流函数
这里其实是用了一个很复杂的图来说节流的好处,然后让我写节流。
当时我不会写节流函数,但是我会写防抖,所以我和面试官说我的项目上的防抖的原理,所以面试官让我先写了一个防抖函数,写完之后解释了节流函数,再让我写了一次。不得不夸一下,这个面试官非常的有耐心,节流和要点都有和我讲到,所以我才能安心写出这个我没接触过的函数。下面贴出此题一种解法。
解题思路
window.onload = () => {
// 这两行代码大家可以不用管,是因为我想演示效果,所以大家随便用一个点击div的事件就可以
let myInput = document.getElementById('myInput');
let inputSet;
// 节流函数
myInput.addEventListener('click', () => {
if (!inputSet) {
// 第一次执行
console.log(myInput.value);
inputSet = setTimeout(() => {
inputSet = undefined;
}, 500);
}
})
}
算法题
题目
手写排序算法
这里面试官是问了你知道哪些常见的排序算法?然后我说冒泡排序、快速排序、归并排序、希尔排序(注意这个希尔我是不会的,所以千万放后面说,如果面试官对快速或归并感兴趣,会让你停下来的,别硬讲你不懂的技术,不然很拉低面试官的印象分),然后他让我写一个快速排序,这个我有写过,但是当时写的时候里面的逻辑没有理清,面试官一直陪着梳理思路,最后还是写完了这个算法。
解题思路
function sort(arr, flag) {
function swap(arr, a, b) {
let temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
function partition(arr, left, right) {
// 基准
let pt = arr[right];
// 指针
let storeIndex = left;
for (let i = left; i < right; i++) {
if (arr[i] < pt) {
swap(arr, i, storeIndex);
storeIndex++;
}
}
swap(arr, right, storeIndex);
return storeIndex;
}
function quickSort(arr, left, right) {
if (left > right) return;
var storeIndex = partition(arr, left, right);
quickSort(arr, left, storeIndex - 1);
quickSort(arr, storeIndex + 1, right);
}
quickSort(arr, 0, arr.length - 1);
return arr;
}
console.log(sort([1, 4, 2, 10, 5, 7, 2, 4, 6, 7]));
总结
其实一面都是一些很基础的问题,但是它会将考察点掺杂在所有的问题中,一旦你触及了这个方面,他就会问你这个相关知识,所以你需要在问题中提炼出他想问的知识点,不要等他来问:"这个可以用call来做吗?",而是你自己在回答的时候就觉察出来,并直接展示出来。
但是对于你不熟悉的技术,千万别硬掺杂在一系列名词中吐露出来,面试官万一就觉得你可能不会,硬问这个,你就难顶了。
希望大家都能收获自己期望的offer!