騰訊實習前端工程師面經-一面
阿新 • • 發佈:2020-03-20
# 騰訊前端面經一面
[TOC]
## 寫在前面
博主現在讀大三,前端小白一隻,上一個隨筆發出了最近的美團一面的面試題與注意事項,這裡博主整理了一下騰訊二月二十九日的第一次面試題與解題思路,注意事項,希望對大家的面試有所幫助。
## 面試題相關
### 垂直居中問題
***題目***
**螢幕正中間有一個元素A,隨著螢幕寬度的增加,需要滿足以下條件:**
+ A元素垂直居中於螢幕中央;
+ A元素距離螢幕左右邊距各10px;
+ A元素裡面的文字"A"的font-size:20px;水平垂直居中;
+ A元素高度始終為A元素寬度的50%;(如果搞不定可以實現為A元素的高度固定為200px)
請用**html**及**css**實現
![圖1](https://images.cnblogs.com/cnblogs_com/JobsOfferings/1363202/o_2003191531301.png "圖1")
---
***解題思路***
這個題目考察的是主要是**垂直居中**的措施,具體的方法大家可以自行查詢,這裡貼出我自己的程式碼。主要的地方是使用calc計算屬性去設定左右邊距,然後height也順帶實現A元素高度始終為A元素寬度的50%
```html
* {
margin: 0;
padding: 0;
}
body {
width: 100%;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.fa-area {
position: relative;
width: 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;
}
A
```
### arguments
***題目***
**函式中的arguments是陣列嗎?若不是,如何將它轉化為真正的陣列?**
---
***解題思路***
這個題目考察對arguments的認識,以及call的使用,並沒有提及手寫call函式。
`不是`
轉化方案:
`arguments = [].slice.call(arguments);`
### 隱式型別轉換
***題目***
**請說出以下程式碼列印的結果**
```js
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`
### 非同步問題
***題目***
**請說出以下程式碼列印的結果**
```js
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語句。
```js
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)
```js
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`。
以下是我的答案:
```js
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方法在各個部落格中都有很詳細的原理與解析,所以這裡我只將我的答案貼上,希望輕噴。
```js
Function.prototype.bind = function (context) {
// 這裡要存一下this而不能把返回裡的函式物件轉為匿名函式
// 因為這本身就是為了因為bind()函式釋出在ES5中,不能很好的相容所有瀏覽器
var self = this;
return function () {
return self.apply(context, arguments);
}
}
```
### 手寫節流函式
***題目***
**實現一個節流函式**
這裡其實是用了一個很複雜的圖來說節流的好處,然後讓我寫節流。
當時我不會寫節流函式,但是我會寫防抖,所以我和麵試官說我的專案上的防抖的原理,所以面試官讓我先寫了一個防抖函式,寫完之後解釋了節流函式,再讓我寫了一次。不得不誇一下,這個面試官非常的有耐心,節流和要點都有和我講到,所以我才能安心寫出這個我沒接觸過的函式。下面貼出此題一種解法。
---
***解題思路***
```js
window.onload = () => {
// 這兩行程式碼大家可以不用管,是因為我想演示效果,所以大家隨便用一個點選div的事件就可以
let myInput = document.getElementById('myInput');
let inputSet;
// 節流函式
myInput.addEventListener('click', () => {
if (!inputSet) {
// 第一次執行
console.log(myInput.value);
inputSet = setTimeout(() => {
inputSet = undefined;
}, 500);
}
})
}
```
### 演算法題
***題目***
**手寫排序演算法**
這裡面試官是問了你知道哪些常見的排序演算法?然後我說氣泡排序、快速排序、歸併排序、希爾排序(注意這個希爾我是不會的,所以千萬放後面說,如果面試官對快速或歸併感興趣,會讓你停下來的,別硬講你不懂的技術,不然很拉低面試官的印象分),然後他讓我寫一個快速排序,這個我有寫過,但是當時寫的時候裡面的邏輯沒有理清,面試官一直陪著梳理思路,最後還是寫完了這個演算法。
---
***解題思路***
```js
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來做嗎?",**而是你自己在回答的時候就覺察出來**,並直接展示出來。
但是對於你不熟悉的技術,千萬別硬摻雜在一系列名詞中吐露出來,面試官萬一就覺得你可能不會,硬問這個,你就難頂了。
希望大家都能收穫自己期望的