【週刊-1】三年大廠面試官-面試題精選及答案

前言

在阿里和騰訊工做了6年,當了3年的前端面試官,把期間我和個人同事常問的面試題和答案彙總在我 Github 的 Weekly-FE-Interview 中。但願對你們有所幫助。javascript

若是你在bat面試的時候遇到了什麼不懂的問題,歡迎給我提issue,我會把題目彙總並將面試要點和答案寫好放在週刊裏,你們一塊兒共同進步和成長,助力你們進入本身理想的企業。前端

項目地址是:github.com/airuikun/We…java

常見面試題精選

如下是十道大廠一面的時候常見的面試題,若是所有理解而且弄透,在一面或者電話面的時候基本上能中1~2題。小夥伴能夠先不急着看答案,先本身嘗試着思考一下和本身實現一下,而後再看答案。node

第 1 題:http的狀態碼中,499是什麼?如何出現499,如何排查跟解決

499對應的是 「client has closed connection」,客戶端請求等待連接已經關閉,這頗有多是由於服務器端處理的時間過長,客戶端等得「不耐煩」了。還有一種緣由是兩次提交post過快就會出現499。 解決方法:nginx

  • 前端將timeout最大等待時間設置大一些
  • nginx上配置proxy_ignore_client_abort on;

提問解答與更多解析:github.com/airuikun/We…git

第 2 題:如何遍歷一個dom樹

function traversal(node) {
    //對node的處理
    if (node && node.nodeType === 1) {
        console.log(node.tagName);
    }
    var i = 0,
        childNodes = node.childNodes,
        item;
    for (; i < childNodes.length; i++) {
        item = childNodes[i];
        if (item.nodeType === 1) {
            //遞歸先序遍歷子節點
            traversal(item);
        }
    }
}
複製代碼

提問解答與更多解析:github.com/airuikun/We…github

第 3 題:new操做符都作了什麼

四大步驟:面試

一、建立一個空對象,而且 this 變量引用該對象,// lat target = {};算法

二、繼承了函數的原型。// target.proto = func.prototype;數組

三、屬性和方法被加入到 this 引用的對象中。並執行了該函數func// func.call(target);

四、新建立的對象由 this 所引用,而且最後隱式的返回 this 。// 若是func.call(target)返回的res是個對象或者function 就返回它

function new(func) {
	lat target = {};
	target.__proto__ = func.prototype;
	let res = func.call(target);
	if (typeof(res) == "object" || typeof(res) == "function") {
		return res;
	}
	return target;
}
複製代碼

提問解答與更多解析:github.com/airuikun/We…

第 4 題:手寫代碼,簡單實現call

Function.prototype.call2 = function(context) {
    var context = context || window; //由於傳進來的context有多是null
    context.fn = this;
    var args = [];
    for (var i = 1; i < arguments.length; i++) {
        args.push("arguments[" + i + "]"); //不這麼作的話 字符串的引號會被自動去掉 變成了變量 致使報錯
    }
    args = args.join(",");

    var result = eval("context.fn(" + args + ")"); //至關於執行了context.fn(arguments[1], arguments[2]);

    delete context.fn;
    return result; //由於有可能this函數會有返回值return
}
複製代碼

提問解答與更多解析:github.com/airuikun/We…

第 5 題:手寫代碼,簡單實現apply

Function.prototype.apply2 = function(context, arr) {
    var context = context || window; //由於傳進來的context有多是null
    context.fn = this;
    var args = [];
    var params = arr || [];
    for (var i = 0; i < params.length; i++) {
        args.push("params[" + i + "]"); //不這麼作的話 字符串的引號會被自動去掉 變成了變量 致使報錯
    }
    args = args.join(",");

    var result = eval("context.fn(" + args + ")"); //至關於執行了context.fn(arguments[1], arguments[2]);

    delete context.fn;
    return result; //由於有可能this函數會有返回值return
}
複製代碼

提問解答與更多解析:github.com/airuikun/We…

第 6 題:手寫代碼,簡單實現bind

Function.prototype.bind2 = function(context) {
    var _this = this;
    var argsParent = Array.prototype.slice.call(arguments, 1);
    return function() {
        var args = argsParent.concat(Array.prototype.slice.call(arguments)); //轉化成數組
        _this.apply(context, args);
    };
}
複製代碼

提問解答與更多解析:github.com/airuikun/We…

第 7 題:講解一下HTTPS的工做原理

HTTPS在傳輸數據以前須要客戶端(瀏覽器)與服務端(網站)之間進行一次握手,在握手過程當中將確立雙方加密傳輸數據的密碼信息。TLS/SSL協議不只僅是一套加密傳輸的協議,更是一件通過藝術家精心設計的藝術品,TLS/SSL中使用了非對稱加密,對稱加密以及HASH算法。握手過程的簡單描述以下:

  • 瀏覽器將本身支持的一套加密規則發送給網站。

  • 網站從中選出一組加密算法與HASH算法,並將本身的身份信息以證書的形式發回給瀏覽器。證書裏面包含了網站地址,加密公鑰,以及證書的頒發機構等信息。

  • 得到網站證書以後瀏覽器要作如下工做:

    • a) 驗證證書的合法性(頒發證書的機構是否合法,證書中包含的網站地址是否與正在訪問的地址一致等),若是證書受信任,則瀏覽器欄裏面會顯示一個小鎖頭,不然會給出證書不受信的提示。

    • 若是證書受信任,或者是用戶接受了不受信的證書,瀏覽器會生成一串隨機數的密碼,並用證書中提供的公鑰加密。

    • 使用約定好的HASH計算握手消息,並使用生成的隨機數對消息進行加密,最後將以前生成的全部信息發送給網站。

  • 網站接收瀏覽器發來的數據以後要作如下的操做:

    • a) 使用本身的私鑰將信息解密取出密碼,使用密碼解密瀏覽器發來的握手消息,並驗證HASH是否與瀏覽器發來的一致。

    • b) 使用密碼加密一段握手消息,發送給瀏覽器。

  • 瀏覽器解密並計算握手消息的HASH,若是與服務端發來的HASH一致,此時握手過程結束,以後全部的通訊數據將由以前瀏覽器生成的隨機密碼並利用對稱加密算法進行加密。

提問解答與更多解析:github.com/airuikun/We…

第 8 題:講解一下https對稱加密和非對稱加密。

對稱加密: 發送方和接收方須要持有同一把密鑰,發送消息和接收消息均使用該密鑰。相對於非對稱加密,對稱加密具備更高的加解密速度,但雙方都須要事先知道密鑰,密鑰在傳輸過程當中可能會被竊取,所以安全性沒有非對稱加密高。

非對稱加密: 接收方在發送消息前須要事先生成公鑰和私鑰,而後將公鑰發送給發送方。發送放收到公鑰後,將待發送數據用公鑰加密,發送給接收方。接收到收到數據後,用私鑰解密。 在這個過程當中,公鑰負責加密,私鑰負責解密,數據在傳輸過程當中即便被截獲,攻擊者因爲沒有私鑰,所以也沒法破解。 非對稱加密算法的加解密速度低於對稱加密算法,可是安全性更高。

提問解答與更多解析:github.com/airuikun/We…

第 9 題: 簡單實現項目代碼按需加載,例如import { Button } from 'antd',打包的時候只打包button

原理很簡單,就是將

import { Select, Pagination, Button } from 'xxx-ui';
複製代碼

經過babel轉化成

import Button from `xxx-ui/src/components/ui-base/Button/Button`;
import Pagination from `xxx-ui/src/components/ui-base/Pagination/Pagination`;
import Select from `xxx-ui/src/components/ui-base/Select/Select`;
複製代碼

自定義拓展一個babel插件,代碼以下:

visitor: {
	ImportDeclaration (path, { opts }) {
	    const specifiers = path.node.specifiers;
	    const source = path.node.source;

            // 判斷傳入的配置參數是不是數組形式
	    if (Array.isArray(opts)) {
	        opts.forEach(opt => {
	            assert(opt.libraryName, 'libraryName should be provided');
	        });
	        if (!opts.find(opt => opt.libraryName === source.value)) return;
	    } else {
	        assert(opts.libraryName, 'libraryName should be provided');
	        if (opts.libraryName !== source.value) return;
	    }

	    const opt = Array.isArray(opts) ? opts.find(opt => opt.libraryName === source.value) : opts;
	    opt.camel2UnderlineComponentName = typeof opt.camel2UnderlineComponentName === 'undefined'
	        ? false
	        : opt.camel2UnderlineComponentName;
	    opt.camel2DashComponentName = typeof opt.camel2DashComponentName === 'undefined'
	        ? false
	        : opt.camel2DashComponentName;

	    if (!types.isImportDefaultSpecifier(specifiers[0]) && !types.isImportNamespaceSpecifier(specifiers[0])) {
	        // 遍歷specifiers生成轉換後的ImportDeclaration節點數組
    		const declarations = specifiers.map((specifier) => {
	            // 轉換組件名稱
                    const transformedSourceName = opt.camel2UnderlineComponentName
                	? camel2Underline(specifier.imported.name)
                	: opt.camel2DashComponentName
            		    ? camel2Dash(specifier.imported.name)
            		    : specifier.imported.name;
    		    // 利用自定義的customSourceFunc生成絕對路徑,而後建立新的ImportDeclaration節點
                    return types.ImportDeclaration([types.ImportDefaultSpecifier(specifier.local)],
                	types.StringLiteral(opt.customSourceFunc(transformedSourceName)));
                });
                // 將當前節點替換成新建的ImportDeclaration節點組
    		path.replaceWithMultiple(declarations);
    	}
    }
}
複製代碼

提問解答與更多解析:github.com/airuikun/We…

第 10 題:簡單手寫實現promise

// 簡易版本的promise 
        // 第一步: 列出三大塊 this.then resolve/reject fn(resolve,reject)
        // 第二步: this.then負責註冊全部的函數 resolve/reject負責執行全部的函數 
        // 第三步: 在resolve/reject裏面要加上setTimeout 防止還沒進行then註冊 就直接執行resolve了
        // 第四步: resolve/reject裏面要返回this 這樣就能夠鏈式調用了
        // 第五步: 三個狀態的管理 pending fulfilled rejected
     
        // *****promise的鏈式調用 在then裏面return一個promise 這樣才能then裏面加上異步函數
        // 加上了catch
        function PromiseM(fn) {
            var value = null;
            var callbacks = [];
            //加入狀態 爲了解決在Promise異步操做成功以後調用的then註冊的回調不會執行的問題
            var state = 'pending';
            var _this = this;

            //註冊全部的回調函數
            this.then = function (fulfilled, rejected) {
                //若是想鏈式promise 那就要在這邊return一個new Promise
                return new PromiseM(function (resolv, rejec) {
                    //異常處理
                    try {
                        if (state == 'pending') {
                            callbacks.push(fulfilled);
                            //實現鏈式調用
                            return;
                        }
                        if (state == 'fulfilled') {
                            var data = fulfilled(value);
                            //爲了能讓兩個promise鏈接起來
                            resolv(data);
                            return;
                        }
                        if (state == 'rejected') {
                            var data = rejected(value);
                            //爲了能讓兩個promise鏈接起來
                            resolv(data);
                            return;
                        }
                    } catch (e) {
                        _this.catch(e);
                    }
                });
            }

            //執行全部的回調函數
            function resolve(valueNew) {
                value = valueNew;
                state = 'fulfilled';
                execute();
            }

            //執行全部的回調函數
            function reject(valueNew) {
                value = valueNew;
                state = 'rejected';
                execute();
            }

            function execute() {
                //加入延時機制 防止promise裏面有同步函數 致使resolve先執行 then還沒註冊上函數
                setTimeout(function () {
                    callbacks.forEach(function (cb) {
                        value = cb(value);
                    });
                }, 0);
            }

            this.catch = function (e) {
                console.log(JSON.stringify(e));
            }

            //經典 實現異步回調
            fn(resolve, reject);
        }


複製代碼

提問解答與更多解析:github.com/airuikun/We…

結語

本人還寫了一些前端進階知識的文章,若是以爲不錯能夠點個star。

blog項目地址是:github.com/airuikun/bl…

我是小蝌蚪,騰訊高級前端工程師,跟着我一塊兒每週攻克幾個前端技術難點。但願在小夥伴前端進階的路上有所幫助,助力你們進入本身理想的企業。

相關文章
相關標籤/搜索