前端面試篇(一)


作為一個前端菜鳥的我,面試經驗和工作經驗並不豐富,但大大小小也面試過不少互聯網聖地,今天就講講筆者今年初面試鵝廠的經驗,希望對大家有所幫助!后面的答案為自行整理,如有疏漏,歡迎指正!

第二篇地址

先說整體情況

適用范圍: 一到兩年的菜鳥前端開發工程師

筆者情況: 筆者一共面試了好幾輪技術面,最終結果技術面通過。

筆者感言: 可能是鵝廠大佬感覺我的經驗不豐富的原因,感覺面試的大部分問題都是以基礎為主。個人感覺大廠還是非常重視基礎的,特別是對工作經驗尚淺或者是校招生而言。所以

重視基礎和原理

重視基礎和原理

重視基礎和原理

正文走起來

以下,筆者會結合面試官問的問題一一道來...

一面——那是一個電話

騰訊面試官(小騰):你好,我是騰訊面試官,巴拉巴拉......先自我介紹一下(聲音特別溫柔😝)!

筆者:我...

小騰:那我們就簡單的聊一下一些基礎的前端知識!

。。。。。。

這通面試電話,面試官主要問了我4個前端相關問題。

1.知道什么是事件委托嗎?

2.對Promise了解嗎?

3.window的onload事件和domcontentloaded誰先誰后?

4.你之前遇到過跨域問題嗎?是怎么解決的。

眾人皆知,不以結婚為目的的戀愛都是耍流氓,額,不,跑題了😁。。。不給答案的面試題都是來騙點擊量的😝!!!由於這些問題實在過於簡單,但是涉及面又挺廣的,還請大家自行百度(千萬不要因為這個不給我贊,你的贊是寶寶持續分享的動力QAQ)。

 

 

二面——QQ遠程面

啊呀,羅里吧嗦的,老太婆的裹腳布...,我寫到這里,被主管劈頭蓋臉就是一頓!現在的年輕人時間寶貴,喜歡干貨,不喜歡你這磨磨唧唧的!如此,只能干貨先行了(大家如果喜歡我的行文風格,就點個贊,或者評論一下唄,筆者特別想懟一下那個主管)!

干貨如下,答案為自己整理,如果有誤,歡迎指出!

一.有一個類如下:

function Person(name) {
    this.name = name
}
let p = new Person('Tom');

 

1. p.__proto__等於什么?

答案: Person.prototype

2. Person.__proto__等於什么?

答案: Function.prototype

解析:

1,2兩問其實問的是同一個問題,都是考察原型鏈相關的知識,我們只需要記住一句話就可以迎刃而解。實例的__proto__屬性(原型)等於其構造函數的prototype屬性。實例p的構造函數為Person,而Person的構造函數為Function,結果就一目了然了。

觸類旁通

var foo = {},
    F = function(){};
Object.prototype.a = 'value a';
Function.prototype.b = 'value b';

console.log(foo.a)   
console.log(foo.b)    
console.log(F.a)      
console.log(F.b)  

 

 

這里就不給答案了,大家自己分析一下,然后再去控制台運行一下吧!冬天到了,動動手,暖一暖,有木有覺得筆者還是相當的貼心的!!!

3. 若將題干改為

function Person(name) {
    this.name = name
    return name;
}
let p = new Person('Tom');

 

 

實例化Person過程中,Person返回什么(或者p等於什么)?

答案:

{name: 'Tom'}

 

 

4. 若將題干改為

function Person(name) {
    this.name = name
    return {}
}
let p = new Person('Tom');

 

 

實例化Person過程中,Person返回什么(或者p等於什么)?

答案:

{}

 



解析

構造函數不需要顯示的返回值。使用new來創建對象(調用構造函數)時,如果return的是非對象(數字、字符串、布爾類型等)會忽而略返回值;如果return的是對象,則返回該對象(注:若return null也會忽略返回值)。

5. typeof和instanceof的區別

答案:

在 JavaScript 中,判斷一個變量的類型嘗嘗會用 typeof 運算符,在使用 typeof 運算符時采用引用類型存儲值會出現一個問題,無論引用的是什么類型的對象,它都返回 “object”。

instanceof 運算符用來測試一個對象在其原型鏈中是否存在一個構造函數的 prototype 屬性。 語法:object instanceof constructor 參數:object(要檢測的對象.)constructor(某個構造函數) 描述:instanceof 運算符用來檢測 constructor.prototype 是否存在於參數 object 的原型鏈上。

答案是我整理后的,可能覺得我回答的並不准確,面試官又舉了一個例子給我。

6. 如果Student inherit from Person(Student類繼承Person,需是基於原型的繼承),let s = new Student('Lily'),那么s instanceof Person返回什么?

function Person (name) {
    this.name = name;
}

function Student () {
    
}

Student.prototype = Person.prototype;
Student.prototype.constructor = Student;

let s = new Student('Tom');
console.log(s instanceof Person); // 返回 true

 

答案: true

7. new和instanceof的內部機制

答案

  1. 創建一個新對象,同時繼承對象類的原型,即Person.prototype;
  2. 執行對象類的構造函數,同時該實例的屬性和方法被this所引用,即this指向新構造的實例;
  3. 如果構造函數return了一個新的“對象”,那么這個對象就會取代整個new出來的結果。如果構造函數沒有return對象,那么就會返回步驟1所創建的對象,即隱式返回this。(一般情況下構造函數不會返回任何值,不過在一些特殊情況下,如果用戶想覆蓋這個值,可以選擇返回一個普通的對象來覆蓋。)

用代碼來闡述

// let p = new Person()
let p = (function () {
    let obj = {};
    obj.__proto__ = Person.prototype;
    
    // 其他賦值語句...
    
    return obj;
})();

 

 

下面通過代碼闡述instanceof的內部機制,假設現在有 x instanceof y 一條語句,則其內部實際做了如下判斷:

while(x.__proto__!==null) {
    if(x.__proto__===y.prototype) {
        return true;
    }
    x.__proto__ = x.__proto__.proto__;
}
if(x.__proto__==null) {return false;}

 

 

x會一直沿着隱式原型鏈__proto__向上查找直到x.__proto__.__proto__......===y.prototype為止,如果找到則返回true,也就是x為y的一個實例。否則返回false,x不是y的實例。

觸類旁通

function F() {}
function O() {}

O.prototype = new F();
var obj = new O();

console.log(obj instanceof O); // true
console.log(obj instanceof F); // true
console.log(obj.__proto__ === O.prototype); // true
console.log(obj.__proto__.__proto__ === F.prototype); // true

 

 

根據new 的內部機制改寫上面代碼

function F() {}
function O() {}

var obj = (function () {
    var obj1 = {};
    obj1.__proto__ = F.prototype; // new F();
    O.prototype = obj1; // O.prototype = new F();
    obj.__proto__ = O.prototype; // new O();
    obj.__proto__ = obj1;
    return obj;
})();

 

 

結合instanceof內部機制很容易得出正確答案。

如果稍微調整一下代碼順序,結果將迥然不同

function F() {}
function O() {}

var obj = new O();
O.prototype = new F();


console.log(obj instanceof O); // false
console.log(obj instanceof F); // false
console.log(obj.__proto__ === O.prototype); // false
console.log(obj.__proto__.__proto__ === F.prototype); // false

 

 

具體原因,請讀者自行分析,如果還是有疑問,可以在評論區提出!

其實上面很多問題都是考察原型鏈相關的知識,這里給出一張必須理解的原型鏈圖,原諒我盜了一張圖。

 

 

問到這里我的腦袋已經有點漿糊了,原諒我太菜了!!

8.下面代碼輸出什么?

for(var i = 0; i < 10; i++) {
    setTimeout(() => {
        console.log(i)
    }, 0)
}

 

 

答案: 10個10

若要輸出從0到9,怎么辦?

答案: 將var改為let,或者使用閉包。

// 使用閉包
for(var i = 0; i < 10; i++) {
    (function (i) {
        setTimeout(() => {
            console.log(i)
        }, 0);
    })(i);
}

 

 

9. 剛剛我們用到了箭頭函數,說一下箭頭函數This指向問題?

答案: 默認指向在定義它時,它所處的對象,而不是執行時的對象,定義它的時候,可能環境是window(即繼承父級的this)。

如果對This還有不清楚的地方,可以參考我的另一篇文章徹底理解JavaScript中的this

10. for...in迭代和for...of有什么區別?

答案:for...in和for...of的區別

11.說一下你對generator的了解?

答案: 建議大家查看阮一峰老師的generator相關章節

12.使用過flex布局嗎?flex-grow和flex-shrink屬性有什么用?

答案: flex-grow:項目的放大比例,默認為0,即如果存在剩余空間,也不放大。flex-shrink:項目的縮小比例,默認為1,即如果空間不足,該項目將縮小。

想徹底理解flex,可以查看阮一峰老師的Flex布局教程:語法篇

13. 說一下macrotask 和 microtask?並說出下面代碼的運行結果。

console.log('a');
setTimeout(() => {
    console.log('b');
}, 0);
console.log('c');
Promise.resolve().then(() => {
    console.log('d');
})
.then(() => {
    console.log('e');
});

console.log('f');

 

 

答案: 輸出結果為 acfdeb,而關於macrotask和microtask可以繼續留意筆者后篇文章,亦可自行搜索。不過可以看一下盜的一張圖。

 

 


 

14. Http請求中的keep-alive有了解嗎。

答案:

在http早期,每個http請求都要求打開一個tpc socket連接,並且使用一次之后就斷開這個tcp連接。 使用keep-alive可以改善這種狀態,即在一次TCP連接中可以持續發送多份數據而不會斷開連接。通過使用keep-alive機制,可以減少tcp連接建立次數,也意味着可以減少TIME_WAIT狀態連接,以此提高性能和提高httpd服務器的吞吐率(更少的tcp連接意味着更少的系統內核調用,socket的accept()和close()調用)。 但是,keep-alive並不是免費的午餐,長時間的tcp連接容易導致系統資源無效占用。配置不當的keep-alive,有時比重復利用連接帶來的損失還更大。所以,正確地設置keep-alive timeout時間非常重要。

15. React中的controlled component 和 uncontrolled component區別(受控組件和不受控組件)。

答案: : 請查閱React官網受控組件非受控組件

16. 了解過react-router內部實現機制嗎?

**答案:**請看這篇文章react-router的實現原理

17.數組扁平化處理:實現一個flatten方法,使得輸入一個數組,該數組里面的元素也可以是數組,該方法會輸出一個扁平化的數組。

// Example
let givenArr = [[1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14]]]], 10];
let outputArr = [1,2,2,3,4,5,5,6,7,8,9,11,12,12,13,14,10]

// 實現flatten方法使得
flatten(givenArr)——>outputArr

 

 

年輕的我是用遞歸實現的QAQ,我的答案

function flatten(arr){
    var res = [];
    for(var i=0;i<arr.length;i++){
        if(Array.isArray(arr[i])){
            res = res.concat(flatten(arr[i]));
        }else{
            res.push(arr[i]);
        }
    }
    return res;
}

 

 

其實你還可以這樣

function flatten(arr){
    return arr.reduce(function(prev,item){
        return prev.concat(Array.isArray(item)?flatten(item):item);
    },[]);
}

 

 

還可以使用ES6拓展運算符

function flatten(arr){
    while(arr.some(item=>Array.isArray(item)){
        arr = [].concat(...arr);
    }
    return arr;
}

 

 

18.如果在17問的前提下,要做去重和排序處理又該怎么做(不用給出具體代碼)。

**答案:**最好封裝一個數組方法的類,該類包含flatten(扁平化)、sort(排序)和unique(去重)等方法。

二面就這樣過去了,懷着忐忑的心情等待結果中,文章有點長了,欲知后面的面試題,請聽下回分解!!!


作者:WaterMan
鏈接:https://juejin.im/post/5c19c1b6e51d451d1e06c163
來源:掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM