1. 程式人生 > >騰訊實習前端工程師面經-一面

騰訊實習前端工程師面經-一面

# 騰訊前端面經一面 [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來做嗎?",**而是你自己在回答的時候就覺察出來**,並直接展示出來。   但是對於你不熟悉的技術,千萬別硬摻雜在一系列名詞中吐露出來,面試官萬一就覺得你可能不會,硬問這個,你就難頂了。   希望大家都能收穫自己期望的