下是十道大廠一面的時候常見的面試題,如果全部理解並且弄透,在一面或者電話面的時候基本上能中1~2題。小夥伴可以先不急著看答案,先自己嘗試著思考一下和自己實現一下,然後再看答案。
第 1 題:http的狀態碼中,499是什麼?如何出現499,如何排查跟解決
499對應的是 “client has closed connection”,客戶端請求等待鏈接已經關閉,這很有可能是因為服務器端處理的時間過長,客戶端等得“不耐煩”了。還有一種原因是兩次提交post過快就會出現499。 解決方法:
前端將timeout最大等待時間設置大一些nginx上配置proxy_ignore_client_abort on;提問解答與更多解析:github.com/airuikun/We…
第 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…
第 3 題:new操作符都做了什麼
四大步驟:
1、創建一個空對象,並且 this 變量引用該對象,// lat target = {};
2、繼承了函數的原型。// target.proto = func.prototype;
3、屬性和方法被加入到 this 引用的對象中。並執行了該函數func// func.call(target);
4、新創建的對象由 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算法。握手過程的簡單描述如下:
提問解答與更多解析: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); }
作者:第一名的小蝌蚪
鏈接:https://juejin.im/post/5ca9de22e51d452b5372ed90
來源:掘金
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。