美团前端二面必会面试题(附答案)
判斷數組的方式有哪些
- 通過Object.prototype.toString.call()做判斷
- 通過原型鏈做判斷
- 通過ES6的Array.isArray()做判斷
- 通過instanceof做判斷
- 通過Array.prototype.isPrototypeOf
前端進階面試題詳細解答
Vue的父子組件生命周期鉤子函數執行順序?
<!-- 加載渲染過程 --><!-- 父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created ->子beforeMount -> 子mounted -> 父mounted --><!-- 子組件更新過程 --><!-- 父beforeUpdate -> 子beforeUpdate -> 子updaed -> 父updated --><!-- 父組件跟新過程 --><!-- 父beforeUpdate -> 父updated --><!-- 銷毀過程 --><!-- 父beforeDestroy -> 子beforeDestroy -> 子destroyed ->父destroyed -->== 操作符的強制類型轉換規則?
對于 == 來說,如果對比雙方的類型不一樣,就會進行類型轉換。假如對比 x 和 y 是否相同,就會進行如下判斷流程:
寫代碼:實現函數能夠深度克隆基本類型
淺克隆:
function shallowClone(obj) {let cloneObj = {};for (let i in obj) {cloneObj[i] = obj[i];}return cloneObj; }深克隆:
- 考慮基礎類型
- 引用類型
- RegExp、Date、函數 不是 JSON 安全的
- 會丟失 constructor,所有的構造函數都指向 Object
- 破解循環引用
如何避免回流與重繪?
減少回流與重繪的措施:
- 操作DOM時,盡量在低層級的DOM節點進行操作
- 不要使用table布局, 一個小的改動可能會使整個table進行重新布局
- 使用CSS的表達式
- 不要頻繁操作元素的樣式,對于靜態頁面,可以修改類名,而不是樣式。
- 使用absolute或者fixed,使元素脫離文檔流,這樣他們發生變化就不會影響其他元素
- 避免頻繁操作DOM,可以創建一個文檔片段documentFragment,在它上面應用所有DOM操作,最后再把它添加到文檔中
- 將元素先設置display: none,操作結束后再把它顯示出來。因為在display屬性為none的元素上進行的DOM操作不會引發回流和重繪。
- 將DOM的多個讀操作(或者寫操作)放在一起,而不是讀寫操作穿插著寫。這得益于瀏覽器的渲染隊列機制。
瀏覽器針對頁面的回流與重繪,進行了自身的優化——渲染隊列
瀏覽器會將所有的回流、重繪的操作放在一個隊列中,當隊列中的操作到了一定的數量或者到了一定的時間間隔,瀏覽器就會對隊列進行批處理。這樣就會讓多次的回流、重繪變成一次回流重繪。
上面,將多個讀操作(或者寫操作)放在一起,就會等所有的讀操作進入隊列之后執行,這樣,原本應該是觸發多次回流,變成了只觸發一次回流。
webpack配置入口出口
module.exports={//入口文件的配置項entry:{},//出口文件的配置項output:{},//模塊:例如解讀CSS,圖片如何轉換,壓縮module:{},//插件,用于生產模版和各項功能plugins:[],//配置webpack開發服務功能devServer:{} } 簡單描述了一下這幾個屬性是干什么的。 描述一下npm run dev / npm run build執行的是哪些文件 通過配置proxyTable來達到開發環境跨域的問題,然后又可以擴展和他聊聊跨域的產生,如何跨域 最后可以在聊聊webpack的優化,例如babel-loader的優化,gzip壓縮等等URL有哪些組成部分
一個完整的URL包括以下幾部分:
- 協議部分:該URL的協議部分為“http:”,這代表網頁使用的是HTTP協議。在Internet中可以使用多種協議,如HTTP,FTP等等本例中使用的是HTTP協議。在"HTTP"后面的“//”為分隔符;
- 域名部分
- 端口部分:跟在域名后面的是端口,域名和端口之間使用“:”作為分隔符。端口不是一個URL必須的部分,如果省略端口部分,將采用默認端口(HTTP協議默認端口是80,HTTPS協議默認端口是443);
- 虛擬目錄部分:從域名后的第一個“/”開始到最后一個“/”為止,是虛擬目錄部分。虛擬目錄也不是一個URL必須的部分。本例中的虛擬目錄是“/news/”;
- 文件名部分:從域名后的最后一個“/”開始到“?”為止,是文件名部分,如果沒有“?”,則是從域名后的最后一個“/”開始到“#”為止,是文件部分,如果沒有“?”和“#”,那么從域名后的最后一個“/”開始到結束,都是文件名部分。本例中的文件名是“index.asp”。文件名部分也不是一個URL必須的部分,如果省略該部分,則使用默認的文件名;
- 錨部分:從“#”開始到最后,都是錨部分。本例中的錨部分是“name”。錨部分也不是一個URL必須的部分;
- 參數部分:從“?”開始到“#”為止之間的部分為參數部分,又稱搜索部分、查詢部分。本例中的參數部分為“boardID=5&ID=24618&page=1”。參數可以允許有多個參數,參數與參數之間用“&”作為分隔符。
說一下你對盒模型的理解?
CSS3中的盒模型有以下兩種:標準盒模型、IE盒模型 盒模型都是由四個部分組成的,分別是margin、border、padding和content 標準盒模型和IE盒模型的區別在于設置width和height時, 所對應的范圍不同 1、標準盒模型的width和height屬性的范圍只包含了content 2、IE盒模型的width和height屬性的范圍包含了border、padding和content 可以通過修改元素的box-sizing屬性來改變元素的盒模型; 1、box-sizing:content-box表示標準盒模型(默認值) 2、box-sizing:border-box表示IE盒模型(怪異盒模型)AJAX
題目描述:利用 XMLHttpRequest 手寫 AJAX 實現
實現代碼如下:
const getJSON = function (url) {return new Promise((resolve, reject) => {const xhr = new XMLHttpRequest();xhr.open("GET", url, false);xhr.setRequestHeader("Content-Type", "application/json");xhr.onreadystatechange = function () {if (xhr.readyState !== 4) return;if (xhr.status === 200 || xhr.status === 304) {resolve(xhr.responseText);} else {reject(new Error(xhr.responseText));}};xhr.send();}); };::before 和 :after 的雙冒號和單冒號有什么區別?
(1)冒號(:)用于CSS3偽類,雙冒號(::)用于CSS3偽元素。
(2)::before就是以一個子元素的存在,定義在元素主體內容之前的一個偽元素。并不存在于dom之中,只存在在頁面之中。
注意: :before 和 :after 這兩個偽元素,是在CSS2.1里新出現的。起初,偽元素的前綴使用的是單冒號語法,但隨著Web的進化,在CSS3的規范里,偽元素的語法被修改成使用雙冒號,成為::before、::after。
代碼輸出問題
function Parent() {this.a = 1;this.b = [1, 2, this.a];this.c = { demo: 5 };this.show = function () {console.log(this.a , this.b , this.c.demo );} }function Child() {this.a = 2;this.change = function () {this.b.push(this.a);this.a = this.b.length;this.c.demo = this.a++;} }Child.prototype = new Parent(); var parent = new Parent(); var child1 = new Child(); var child2 = new Child(); child1.a = 11; child2.a = 12; parent.show(); child1.show(); child2.show(); child1.change(); child2.change(); parent.show(); child1.show(); child2.show();輸出結果:
parent.show(); // 1 [1,2,1] 5child1.show(); // 11 [1,2,1] 5 child2.show(); // 12 [1,2,1] 5parent.show(); // 1 [1,2,1] 5child1.show(); // 5 [1,2,1,11,12] 5child2.show(); // 6 [1,2,1,11,12] 5這道題目值得神帝,他涉及到的知識點很多,例如this的指向、原型、原型鏈、類的繼承、數據類型等。
解析:
- this.b.push(this.a),由于this的動態指向特性,this.b會指向Child.prototype上的b數組,this.a會指向child1的a屬性,所以Child.prototype.b變成了**[1,2,1,11]**;
- this.a = this.b.length,這條語句中this.a和this.b的指向與上一句一致,故結果為child1.a變為4;
- this.c.demo = this.a++,由于child1自身屬性并沒有c這個屬性,所以此處的this.c會指向Child.prototype.c,this.a值為4,為原始類型,故賦值操作時會直接賦值,Child.prototype.c.demo的結果為4,而this.a隨后自增為5(4 + 1 = 5)。
- this.b.push(this.a),由于this的動態指向特性,this.b會指向Child.prototype上的b數組,this.a會指向child2的a屬性,所以Child.prototype.b變成了**[1,2,1,11,12]**;
- this.a = this.b.length,這條語句中this.a和this.b的指向與上一句一致,故結果為child2.a變為5;
- this.c.demo = this.a++,由于child2自身屬性并沒有c這個屬性,所以此處的this.c會指向Child.prototype.c,故執行結果為Child.prototype.c.demo的值變為child2.a的值5,而child2.a最終自增為6(5 + 1 = 6)。
代碼輸出結果
function runAsync(x) {const p = new Promise(r =>setTimeout(() => r(x, console.log(x)), 1000));return p; } function runReject(x) {const p = new Promise((res, rej) =>setTimeout(() => rej(`Error: ${x}`, console.log(x)), 1000 * x));return p; } Promise.race([runReject(0), runAsync(1), runAsync(2), runAsync(3)]).then(res => console.log("result: ", res)).catch(err => console.log(err));輸出結果如下:
0 Error: 0 1 2 3可以看到在catch捕獲到第一個錯誤之后,后面的代碼還不執行,不過不會再被捕獲了。
注意:all和race傳入的數組中如果有會拋出異常的異步任務,那么只有最先拋出的錯誤會被捕獲,并且是被then的第二個參數或者后面的catch捕獲;但并不會影響數組中其它的異步任務的執行。
let、const、var的區別
(1)塊級作用域: 塊作用域由 { }包括,let和const具有塊級作用域,var不存在塊級作用域。塊級作用域解決了ES5中的兩個問題:
- 內層變量可能覆蓋外層變量
- 用來計數的循環變量泄露為全局變量
(2)變量提升: var存在變量提升,let和const不存在變量提升,即在變量只能在聲明之后使用,否在會報錯。
(3)給全局添加屬性: 瀏覽器的全局對象是window,Node的全局對象是global。var聲明的變量為全局變量,并且會將該變量添加為全局對象的屬性,但是let和const不會。
(4)重復聲明: var聲明變量時,可以重復聲明變量,后聲明的同名變量會覆蓋之前聲明的遍歷。const和let不允許重復聲明變量。
(5)暫時性死區: 在使用let、const命令聲明變量之前,該變量都是不可用的。這在語法上,稱為暫時性死區。使用var聲明的變量不存在暫時性死區。
(6)初始值設置: 在變量聲明時,var 和 let 可以不用設置初始值。而const聲明變量必須設置初始值。
(7)指針指向: let和const都是ES6新增的用于創建變量的語法。 let創建的變量是可以更改指針指向(可以重新賦值)。但const聲明的變量是不允許改變指針的指向。
| 是否有塊級作用域 | × | ?? | ?? |
| 是否存在變量提升 | ?? | × | × |
| 是否添加全局屬性 | ?? | × | × |
| 能否重復聲明變量 | ?? | × | × |
| 是否存在暫時性死區 | × | ?? | ?? |
| 是否必須設置初始值 | × | × | ?? |
| 能否改變指針指向 | ?? | ?? | × |
Cookie、LocalStorage、SessionStorage區別
瀏覽器端常用的存儲技術是 cookie 、localStorage 和 sessionStorage。
- cookie: 其實最開始是服務器端用于記錄用戶狀態的一種方式,由服務器設置,在客戶端存儲,然后每次發起同源請求時,發送給服務器端。cookie 最多能存儲 4 k 數據,它的生存時間由 expires 屬性指定,并且 cookie 只能被同源的頁面訪問共享。
- sessionStorage: html5 提供的一種瀏覽器本地存儲的方法,它借鑒了服務器端 session 的概念,代表的是一次會話中所保存的數據。它一般能夠存儲 5M 或者更大的數據,它在當前窗口關閉后就失效了,并且 sessionStorage 只能被同一個窗口的同源頁面所訪問共享。
- localStorage: html5 提供的一種瀏覽器本地存儲的方法,它一般也能夠存儲 5M 或者更大的數據。它和 sessionStorage 不同的是,除非手動刪除它,否則它不會失效,并且 localStorage 也只能被同源頁面所訪問共享。
上面幾種方式都是存儲少量數據的時候的存儲方式,當需要在本地存儲大量數據的時候,我們可以使用瀏覽器的 indexDB 這是瀏覽器提供的一種本地的數據庫存儲機制。它不是關系型數據庫,它內部采用對象倉庫的形式存儲數據,它更接近 NoSQL 數據庫。
TCP和UDP的使用場景
- TCP應用場景: 效率要求相對低,但對準確性要求相對高的場景。因為傳輸中需要對數據確認、重發、排序等操作,相比之下效率沒有UDP高。例如:文件傳輸(準確高要求高、但是速度可以相對慢)、接受郵件、遠程登錄。
- UDP應用場景: 效率要求相對高,對準確性要求相對低的場景。例如:QQ聊天、在線視頻、網絡語音電話(即時通訊,速度要求高,但是出現偶爾斷續不是太大問題,并且此處完全不可以使用重發機制)、廣播通信(廣播、多播)。
對瀏覽器內核的理解
瀏覽器內核主要分成兩部分:
- 渲染引擎的職責就是渲染,即在瀏覽器窗口中顯示所請求的內容。默認情況下,渲染引擎可以顯示 html、xml 文檔及圖片,它也可以借助插件顯示其他類型數據,例如使用 PDF 閱讀器插件,可以顯示 PDF 格式。
- JS 引擎:解析和執行 javascript 來實現網頁的動態效果。
最開始渲染引擎和 JS 引擎并沒有區分的很明確,后來 JS 引擎越來越獨立,內核就傾向于只指渲染引擎。
new操作符的實現原理
new操作符的執行過程:
(1)首先創建了一個新的空對象
(2)設置原型,將對象的原型設置為函數的 prototype 對象。
(3)讓函數的 this 指向這個對象,執行構造函數的代碼(為這個新對象添加屬性)
(4)判斷函數的返回值類型,如果是值類型,返回創建的對象。如果是引用類型,就返回這個引用類型的對象。
具體實現:
function objectFactory() {let newObject = null;let constructor = Array.prototype.shift.call(arguments);let result = null;// 判斷參數是否是一個函數if (typeof constructor !== "function") {console.error("type error");return;}// 新建一個空對象,對象的原型為構造函數的 prototype 對象newObject = Object.create(constructor.prototype);// 將 this 指向新建對象,并執行函數result = constructor.apply(newObject, arguments);// 判斷返回對象let flag = result && (typeof result === "object" || typeof result === "function");// 判斷返回結果return flag ? result : newObject; } // 使用方法 objectFactory(構造函數, 初始化參數);對JSON的理解
JSON 是一種基于文本的輕量級的數據交換格式。它可以被任何的編程語言讀取和作為數據格式來傳遞。
在項目開發中,使用 JSON 作為前后端數據交換的方式。在前端通過將一個符合 JSON 格式的數據結構序列化為
JSON 字符串,然后將它傳遞到后端,后端通過 JSON 格式的字符串解析后生成對應的數據結構,以此來實現前后端數據的一個傳遞。
因為 JSON 的語法是基于 js 的,因此很容易將 JSON 和 js 中的對象弄混,但是應該注意的是 JSON 和 js 中的對象不是一回事,JSON 中對象格式更加嚴格,比如說在 JSON 中屬性值不能為函數,不能出現 NaN 這樣的屬性值等,因此大多數的 js 對象是不符合 JSON 對象的格式的。
在 js 中提供了兩個函數來實現 js 數據結構和 JSON 格式的轉換處理,
- JSON.stringify 函數,通過傳入一個符合 JSON 格式的數據結構,將其轉換為一個 JSON 字符串。如果傳入的數據結構不符合 JSON 格式,那么在序列化的時候會對這些值進行對應的特殊處理,使其符合規范。在前端向后端發送數據時,可以調用這個函數將數據對象轉化為 JSON 格式的字符串。
- JSON.parse() 函數,這個函數用來將 JSON 格式的字符串轉換為一個 js 數據結構,如果傳入的字符串不是標準的 JSON 格式的字符串的話,將會拋出錯誤。當從后端接收到 JSON 格式的字符串時,可以通過這個方法來將其解析為一個 js 數據結構,以此來進行數據的訪問。
實現有并行限制的 Promise 調度器
題目描述:JS 實現一個帶并發限制的異步調度器 Scheduler,保證同時運行的任務最多有兩個
addTask(1000,"1");addTask(500,"2");addTask(300,"3");addTask(400,"4");的輸出順序是:2 3 1 4整個的完整執行流程:一開始1、2兩個任務開始執行 500ms時,2任務執行完畢,輸出2,任務3開始執行 800ms時,3任務執行完畢,輸出3,任務4開始執行 1000ms時,1任務執行完畢,輸出1,此時只剩下4任務在執行 1200ms時,4任務執行完畢,輸出4實現代碼如下:
class Scheduler {constructor(limit) {this.queue = [];this.maxCount = limit;this.runCounts = 0;}add(time, order) {const promiseCreator = () => {return new Promise((resolve, reject) => {setTimeout(() => {console.log(order);resolve();}, time);});};this.queue.push(promiseCreator);}taskStart() {for (let i = 0; i < this.maxCount; i++) {this.request();}}request() {if (!this.queue || !this.queue.length || this.runCounts >= this.maxCount) {return;}this.runCounts++;this.queue.shift()().then(() => {this.runCounts--;this.request();});} } const scheduler = new Scheduler(2); const addTask = (time, order) => {scheduler.add(time, order); }; addTask(1000, "1"); addTask(500, "2"); addTask(300, "3"); addTask(400, "4"); scheduler.taskStart();TCP/IP五層協議
TCP/IP五層協議和OSI的七層協議對應關系如下:
- 應用層 (application layer):直接為應用進程提供服務。應用層協議定義的是應用進程間通訊和交互的規則,不同的應用有著不同的應用層協議,如 HTTP協議(萬維網服務)、FTP協議(文件傳輸)、SMTP協議(電子郵件)、DNS(域名查詢)等。
- 傳輸層 (transport layer):有時也譯為運輸層,它負責為兩臺主機中的進程提供通信服務。該層主要有以下兩種協議:
- 傳輸控制協議 (Transmission Control Protocol,TCP):提供面向連接的、可靠的數據傳輸服務,數據傳輸的基本單位是報文段(segment);
- 用戶數據報協議 (User Datagram Protocol,UDP):提供無連接的、盡最大努力的數據傳輸服務,但不保證數據傳輸的可靠性,數據傳輸的基本單位是用戶數據報。
- 網絡層 (internet layer):有時也譯為網際層,它負責為兩臺主機提供通信服務,并通過選擇合適的路由將數據傳遞到目標主機。
- 數據鏈路層 (data link layer):負責將網絡層交下來的 IP 數據報封裝成幀,并在鏈路的兩個相鄰節點間傳送幀,每一幀都包含數據和必要的控制信息(如同步信息、地址信息、差錯控制等)。
- 物理層 (physical Layer):確保數據可以在各種物理媒介上進行傳輸,為數據的傳輸提供可靠的環境。
從上圖中可以看出,TCP/IP模型比OSI模型更加簡潔,它把應用層/表示層/會話層全部整合為了應用層。
在每一層都工作著不同的設備,比如我們常用的交換機就工作在數據鏈路層的,一般的路由器是工作在網絡層的。 在每一層實現的協議也各不同,即每一層的服務也不同,下圖列出了每層主要的傳輸協議:
同樣,TCP/IP五層協議的通信方式也是對等通信:
總結
以上是生活随笔為你收集整理的美团前端二面必会面试题(附答案)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux命令大全(在线手册)
- 下一篇: shell用for循环编辑显示形状格式(