1. 程式人生 > >前端面試知識點總結

前端面試知識點總結

這篇文章是對我大四秋招以來面試的總結,裡面包含前端面試知識的方方面面,目前本人已經拿到騰訊offer,希望能對後面找工作的學習學妹們有所幫助。

騰訊面試對基礎比較看重,然後需要你有兩三個比較好的專案,一面重視面試者對前端基礎的把握,還要手寫程式碼,不過不難,二面部門的leader面,這一面比較難,面試官會對你的專案細節進行深挖,所以說專案要牛逼一點,最後還會有一道邏輯題(我沒有答上來),三面是HR面,如果你想進大公司的話,下面這些技術是肯定要掌握的:html5,css3,JavaScript,略懂一點jQuery原始碼,Node.js,express,mongoose,資料庫mongodb。大公司問的核心在於JavaScript。如果下面的知識點你都可以打上來,恭喜你拿下bat不是問題----------------- --2016-11-11寫

轉載請註明出處,碼這麼多字不容易。

一、html+css部分、

(1)css盒模型,可能會要求手寫一個佈局,這個佈局基本上用到的css是margin的負值,boxing-sizing:border-box,佈局儘量往這方面想。瀏覽器佈局的基本元素是盒,在w3c的標準模式下,width=width,但是在怪異模式下,width=border*2+padding*2+width;其中後代元素的width:100%;參照的是右邊的那個width,


(2)html5的新特性


1、標籤語義化,比如header,footer,nav,aside,article,section等,新增了很多表單元素,入email,url等,除去了center等樣式標籤,還有除去了有效能問題的frame,frameset等標籤


2、音視訊元素,video,audio的增加使得我們不需要在依賴外部的外掛就可以往網頁中加入音視訊元素。


3、新增很多api,比如獲取使用者地理位置的window.navigator.geoloaction,


4、websocket


websocket是一種協議,可以讓我們建立客戶端到伺服器端的全雙工通訊,這就意味著伺服器端可以主動推送資料到客戶端,


5、webstorage,webstorage是本地儲存,儲存在客戶端,包括localeStorage和sessionStorage,localeStorage是持久化儲存在客戶端,只要使用者不主動刪除,就不會消失,sessionStorage也是儲存在客戶端,但是他的存在時間是一個回話,一旦瀏覽器的關於該回話的頁面關閉了,sessionStorage就消失了,


6、快取


html5允許我們自己控制哪些檔案需要快取,哪些不需要,具體的做法如下:


1、首先給html新增manifest屬性,並賦值為cache.manifest
2、cache.manifest的內容為: 
         CACHE MANIFEST
         #v1.2
         CACHE :           //表示需要快取的檔案
           a.js
           b.js
       NETWORK:    //表示只在使用者線上的時候才需要的檔案,不會快取
         c.js
       FALLBACK
       /        /index.html     //表示如果找不到第一個資源就用第二個資源代替
7、web worker,web worker是執行在瀏覽器後臺的js程式,他不影響主程式的執行,是另開的一個js執行緒,可以用這個執行緒執行復雜的資料操作,然後把操作結果通過postMessage傳遞給主執行緒,這樣在進行復雜且耗時的操作時就不會阻塞主執行緒了。


(3)對html5的語義話的理解


html5的語義化指的是用正確的標籤包含正確的內容,比如nav標籤,裡面就應該包含導航條的內容,而不是用做其他的用途,標籤語義化的好處就是結構良好,便於閱讀,方便威化,也有利於爬蟲的查詢,提高搜尋率。


(4)cookie,sessionStorage,localeStorage的區別


cookie是儲存在瀏覽器端,並且隨瀏覽器的請求一起傳送到伺服器端的,它有一定的過期時間,到了過期時間自動會消失。sessionStorage和localeStorage也是儲存在客戶端的,同屬於web Storage,比cookie的儲存大小要大有8m,cookie只有4kb,localeStorage是持久化的儲存在客戶端,如果使用者不手動清除的話,不會自動消失,會一直存在,sessionStorage也是儲存在客戶端,但是它的存活時間是在一個回話期間,只要瀏覽器的回話關閉了就會自動消失。


(5)多個頁面之間如何進行通訊


使用cookie,使用web worker,使用localeStorage和sessionStorage


(6)瀏覽器的渲染過程


1、首先獲取html,然後構建dom樹


2、其次根據css構建render樹,render樹中不包含定位和幾何資訊


3、最後構建佈局數,佈局是含有元素的定位和幾何資訊


(7)重構、迴流


瀏覽器的重構指的是改變每個元素外觀時所觸發的瀏覽器行為,比如顏色,背景等樣式發生了改變而進行的重新構造新外觀的過程。重構不會引發頁面的重新佈局,不一定伴隨著迴流,


迴流指的是瀏覽器為了重新渲染頁面的需要而進行的重新計算元素的幾何大小和位置的,他的開銷是非常大的,迴流可以理解為渲染樹需要重新進行計算,一般最好觸發元素的重構,避免元素的迴流;比如通過通過新增類來新增css樣式,而不是直接在DOM上設定,當需要操作某一塊元素時候,最好使其脫離文件流,這樣就不會引起迴流了,比如設定position:absolute或者fixed,或者display:none,等操作結束後在顯示。


二、JavaScript部分


(1)JavaScript的資料型別


基本資料型別:Number,String,Boolean,Undefined,Null


複雜資料型別:Object,Array,Function,RegExp,Date,Error


全域性資料型別:Math


(2)JavaScript的閉包


閉包簡單的說就是一個函式能訪問外部函式的變數,這就是閉包,比如說:




a函式中的b函式就是閉包了,b函式可以使用a函式的區域性變數,引數,最典型的閉包應該是下面這樣,將定義在函式中的函式作為返回值


function a(x){
       var tem=3;
      function b(y){
          console.log(x+y+(++tem));
     }
return b;
}
閉包的另一種作用是隔離作用域,請看下面這段程式碼


for(var i=0;i<2;i++){
      setTimeout(function(){
              console.log(i);
        },0);
}
上面這段程式碼的執行結果是2,2而不是0,1,因為等for迴圈出來後,執行setTimeout中的函式時,i的值已經變成了2,這就是沒有隔離作用域所造成的,請看下面程式碼


for(var i=0;i<2;i++){
      (function(i){
             setTimeout(function(){
              console.log(i);
        },0)
    })(i);
}
這樣就會輸出0,1,我們的立即執行函式建立了一個作用域,隔離了外界的作用域,閉包的缺點是,因為內部閉包函式可以訪問外部函式的變數,所以外部函式的變數不能被釋放,如果閉包巢狀過多,會導致記憶體佔用大,要合理使用閉包。


(3)new 操作符到底做了什麼


首先,new操作符為我們建立一個新的空物件,然後this變數指向該物件,


其次,空物件的原型執行函式的原型,


最後,改變建構函式內部的this的指向


程式碼如下:


var obj={};
obj.__proto__=fn.prototype;
fn.call(obj);
(4)改變函式內部this指標的指向函式


call和apply,假設要改變fn函式內部的this的指向,指向obj,那麼可以fn.call(obj);或者fn.apply(obj);那麼問題來了,call和apply的區別是什麼,其是call和apply的區別在於引數,他們兩個的第一個引數都是一樣的,表示呼叫該函式的物件,apply的第二個引數是陣列,是[arg1,arg2,arg3]這種形式,而call是arg1,arg2,arg3這樣的形式。還有一個bind函式,


var bar=fn.bind(obj);那麼fn中的this就指向obj物件了,bind函式返回新的函式,這個函式內的this指標指向obj物件。


(5)JavaScript的作用域和作用域鏈


JavaScript的作用域指的是變數的作用範圍,內部作用域由函式的形參,實參,區域性變數,函式構成,內部作用域和外部的作用域一層層的連結起來形成作用域鏈,當在在函式內部要訪問一個變數的時候,首先查詢自己的內部作用域有沒有這個變數,如果沒有就到這個物件的原型物件中去查詢,還是沒有的話,就到該作用域所在的作用域中找,直到到window所在的作用域,每個函式在宣告的時候就預設有一個外部作用域的存在了,比如:


var t=4;
function foo(){
       var tem=12;
      funciton bar(){
       var temo=34;
       console.log(t+" "+tem+" "+temo);
      }
}
bar找t變數的過程就是,先到自己的內部作用域中找,發現沒有找到,然後到bar所在的最近的外部變數中找,也就是foo的內部作用域,還是沒有找到,再到window的作用域中找,結果找到了


(6)JavaScript的繼承


function A(name){  this.name=name; }
A.prototype.sayName=function(){ console.log(this.name); }
function B(age){ this.age=age; }
原型繼承


B.prototype=new A("mbj");  //被B的例項共享
var foo=new B(18);
foo.age;    //18,age是本身攜帶的屬性
foo.name;   //mbj,等價於foo.__proto__.name
foo.sayName(); //mbj,等價於foo.__proto__.proto__.sayName()
foo.toString();  //"[object Object]",等價於foo.__proto__.__proto__.__proto__.toString();
這樣B通過原型繼承了A,在new B的時候,foo中有個隱藏的屬性__proto__指向建構函式的prototype物件,在這裡是A物件例項,A物件裡面也有一個隱藏的屬性__proto__,指向A建構函式的prototype物件,這個物件裡面又有一個__proto__指向Object的prototype


這種方式的缺第一個缺點是所有子類共享父類例項,如果某一個子類修改了父類,其他的子類在繼承的時候,會造成意想不到的後果。第二個缺點是在構造子類例項的時候,不能給父類傳遞引數。


建構函式繼承
function B(age,name){  this.age=age;A.call(this,name); }
var foo=new B(18,"wmy");
foo.name;     //wmy
foo.age;      //18
foo.sayName();   //undefined
採用這種方式繼承是把A中的屬性加到this上面,這樣name相當於就是B的屬性,sayName不在A的建構函式中,所以訪問不到sayName。這種方法的缺點是父類的prototype中的函式不能複用。


原型繼承+建構函式繼承


function B(age,name){  this.age=age;A.call(this,name); }
B.prototype=new A("mbj");
var foo=new B(18,"wmy");
foo.name;     //wmy
foo.age;      //18
foo.sayName();   //wmy
這樣就可以成功訪問sayName函數了,結合了上述兩種方式的優點,但是這種方式也有缺點,那就是佔用的空間更大了。


(7)JavaScript變數提升


請看下面程式碼


var bar=1;
function test(){
  console.log(bar);     //undeifned
  var bar=2; 
  console.log(bar);  //2
}
test();
為什麼在test函式中會出現上述結果呢,這就是JavaScript的變數提升了,雖然變數bar的定義在後面,不過瀏覽器在解析的時候,會把變數的定義放到最前面,上面的test函式相當於


function test(){
  var bar;
  console.log(bar);   //undefined
  bar=2; 
  console.log(bar);   //2
}
再看


var foo=function(){  console.log(1); }
function foo(){  console.log(2); }
foo();  //結果為1
同樣的,函式的定義也會到提升到最前面,上面的程式碼相當於
function foo(){  console.log(2); }
var foo;
foo=funciton(){ console.log(1); }
foo();   //1
(8)JavaScript事件模型


原始事件模型,捕獲型事件模型,冒泡事件模型,


原始事件模型就是ele.onclick=function(){}這種型別的事件模型


冒泡事件模型是指事件從事件的發生地(目標元素),一直向上傳遞,直到document,


捕獲型則恰好相反,事件是從document向下傳遞,直到事件的發生地(目標元素)


IE是隻支援冒泡事件模型的,下面是相容各個瀏覽器的事件監聽程式碼


EventUtil={
  addListener:function(target,type,handler){
    if(target.addEventListener){
        target.addEventListener(type,handler);
    }else if(target.attachEvent){
        target.attach("on"+type,function(){
              handler.call(target);  //讓handler中的this指向目標元素
        });
    }else{
        target["on"+type]=handler;
    }
  },
 removeListener:function(target,type,handler){   
      if(target.removeEventListener){    
        target.removeEventListener(type,handler);          
     }else if(target.detachEvent){
        target.detachEvent("on"+type,handler);
     }else{
        target["on"+type]=null;
     }
  },
 getEvent:function(e){      //獲取事件物件
     var evt=window.event||e;
     return evt;
 },
 getTarget:function(e){      //獲得目標物件
     var evt=EventUtil.getEvent(e);
     var target;
     if(evt.target){ target=evt.target;}
     else {target=evt.srcElement;}
     return target;
 },
 stopPropagation:function(e){  //停止冒泡
     var evt=EventUtil.getEvent(e);
     if(evt.stopPropagation) {evt.stopPropagation();}
     else {evt.cancelBubble=true;}
 },
 preventDefault:function(e){   //阻值預設行為的發生
     var evt=EventUtil.getEvent(e);
     if(evt.preventDefault){ evt.preventDefault(); }
     else {e.returnValue=false;}
 }
}
(9)記憶體洩漏


記憶體洩漏指的是瀏覽器不能正常的回收記憶體的現象


(10)瀏覽器的垃圾回收機制


垃圾收集器必須跟蹤哪個變數有用哪個變數沒用,對於不再有用的變數打上標記,以備將來收回其佔用的記憶體,記憶體洩露和瀏覽器實現的垃圾回收機制息息相關, 而瀏覽器實現標識無用變數的策略主要有下兩個方法:


第一,引用計數法


跟蹤記錄每個值被引用的次數。當宣告一個變數並將引用型別的值賦給該變數時,則這個值的引用次數就是1。如果同一個值又被賦給另一個變數,則該值的引用次 數加1.相反,如果包含對這個值引用的變數又取得另外一個值,則這個值的引用次數減1.當這個值的引用次數變成0時,則說明沒有辦法訪問這個值了,因此就 可以將其佔用的記憶體空間回收回來。


如: var a = {};     //物件{}的引用計數為1
     b = a;          //物件{}的引用計數為 1+1 
     a = null;       //物件{}的引用計數為2-1
所以這時物件{}不會被回收;


IE 6, 7 對DOM物件進行引用計數回收, 這樣簡單的垃圾回收機制,非常容易出現迴圈引用問題導致記憶體不能被回收, 進行導致記憶體洩露等問題,一般不用引用計數法。


第二,標記清除法


到2008年為止,IE,Firefox,Opera,Chrome和Safari的javascript實現使用的都是標記清除式的垃圾收集策略(或類似的策略),只不過垃圾收集的時間間隔互有不同。


標記清除的演算法分為兩個階段,標記(mark)和清除(sweep). 第一階段從引用根節點開始標記所有被引用的物件,第二階段遍歷整個堆,把未標記的物件清除。


(11)同源策略


同源策略是瀏覽器有一個很重要的概念。所謂同源是指,域名,協議,埠相同。不同源的客戶端指令碼(javascript、ActionScript)在沒明確授權的情況下,不能讀寫對方的資源。簡單的來說,瀏覽器允許包含在頁面A的指令碼訪問第二個頁面B的資料資源,這一切是建立在A和B頁面是同源的基礎上。


(12)跨域的幾種方式


jsonp(利用script標籤的跨域能力)跨域、websocket(html5的新特性,是一種新協議)跨域、設定代理伺服器(由伺服器替我們向不同源的伺服器請求資料)、CORS(跨源資源共享,cross origin resource sharing)、iframe跨域、postMessage(包含iframe的頁面向iframe傳遞訊息)


(13)非同步和同步


同步指下一個程式的執行需要等到上一個程式執行完畢,也就是得出結果後下一個才能執行,


非同步指的是上一個程式指向後,下一個程式不用等到上一個程式出結果就能執行,等上一個出結果了呼叫回撥函式處理結果就好。


(14)JavaScript的值型別和引用型別


JavaScript有兩種型別的資料,值型別和引用型別,一般的數字,字串,布林值都是值型別,存放在棧中,而物件,函式,陣列等是引用型別,存放在堆中,對引用型別的複製其實是引用複製,相當於複製著地址,物件並沒有真正的複製。


var a=5;var b=a;a=null;    //那麼b是5
var a={},var b=a;b.name="mbj";
console.log(a.name);   //mbj,因為a,b指向同一個物件
a=null;console.log(typeof b);  //object,a=null,只是a不再指向該物件,但是這個物件還是在堆中確確實實的存在,b依然指向它。
(15)優化下面程式碼


var str="我喜歡我可愛的女朋友,";
str=str+"她叫喵喵,";
str=str+"她時而可愛,時而認真,";
str=str+"她那天真的笑聲可以讓人忘掉一切煩惱。";
console.log(str);
這裡的優化主要是對加號操作符的優化,因為加號在JavaScript中非常耗時和耗記憶體,需要經過以下六步:


1、首先開闢一塊臨時空間,儲存字串,
2、然後在開闢一塊空間
3、把str中的字串複製到剛剛開闢的空間
4、在把需要連線的字串複製到str後面
5、str指向這塊空間
6、回收str原來的空間和臨時空間
優化的方法是使用陣列的push方法,陣列是連續的儲存空間,可以省下很多步


var res=[];
var str="我喜歡我可愛的女朋友,";
res.push(str);
res.push("她叫喵喵,");
res.push("她時而可愛,時而認真,");
res.push("她那天真的笑聲可以讓人忘掉一切煩惱。");
console.log(res.join(""));    
(16)封裝cookie的新增,刪除,查詢方法


cookie是儲存在瀏覽器端的,可以用於儲存sessionID,也可以用於自動登陸,記住密碼等,但是在瀏覽器端並沒有官方的操作cookie的方法,下面我們來封裝一下:


CookieUtil={
    addCookie:function(key,value,options){
        var str=key+"="+escape(value);
        if(options.expires){
           var curr=new Date();   //options.expires的單位是小時
           curr.setTime(curr.getTime()+options.expires*3600*1000);
           options.expires=curr.toGMTString();
        }
        for(var k in options){   //有可能指定了cookie的path,cookie的domain
           str+=";"+k+"="+options[k];
        }
        document.cookie=str;
    },
    queryCookie:function(key){
      var cookies=document.cookie;
     //獲得瀏覽器端儲存的cookie,格式是key=value;key=value;key=value
      cookies+=";";
      var start=cookies.indexOf(key);
      if(start<=-1){ return null; }  //說明不存在該cookie
      var end=cookies.indexOf(";",start);
      var value=cookies.slice(start+key.length+1,end);
      return unescape(value);
    },
    deleteCookie:function(key){
      var value=CookieUtil.queryCookie(key);
      if(value===null){return false;}
      CookieUtil.addCookie(key,value,{expires:0});//把過期時間設定為0,瀏覽器會馬上自動幫我們刪除cookie
    }

(17)事件委託機制


事件委託指的是,不再事件的發生地設立監聽函式,而是在事件發生地的父元素或者祖先元素設定監聽器函式,這樣可以大大提高效能,因為可以減少繫結事件的元素,比如:


<ul>
 <li></li>
 <li></li>
 <li></li>
</ul>
要給li元素繫結click事件,使用事件委託機制的話,就只需要給ul繫結click事件就行了,這樣就不需要給每個li'繫結click事件,減小記憶體佔用,提高效率,有興趣的童鞋可以去看看jQuery的live,bind,on,delegate函式的區別,這幾個函式就採用了事件委託機制。


三、其他部分


(1)http狀態碼


http狀態碼是表示伺服器對請求的響應狀態,主要分為以下幾個部分


1**:這類響應是臨時響應,只包含狀態行和某些可選的響應頭資訊,並以空行結束


2**:表示請求成功,


3**:表示重定向


4**:表示客戶端錯誤


5**:表示伺服器端錯誤


100(continue),客戶端應當繼續傳送請求。這個臨時響應是用來通知客戶端它的部分請求已經被伺服器接收


200(OK),表示請求成功,請求所希望的響應頭或資料體將隨此響應返回。


202(Accepted),伺服器已接受請求,但尚未處理。


204(No-Content),伺服器成功處理了請求,但不需要返回任何實體內容


205(Reset-Content),伺服器成功處理了請求,且沒有返回任何內容。但是與204響應不同,返回此狀態碼的響應要求請求者重置文件檢視。該響應主要是被用於接受使用者輸入後,立即重置表單,以便使用者能夠輕鬆地開始另一次輸入。


206(Partial-Content),伺服器已經成功處理了部分 GET 請求。


301(Moved-Permanently),永久性重定向


302(Moved-Temporarily),暫時性重定向


304(Not-Modified),瀏覽器端快取的資源依然有效


400(Bad-Reques),請求有誤,當前請求無法被伺服器理解。


401(Unauthorized),當前請求需要使用者驗證。


403(Forbidden),伺服器已經理解請求,但是拒絕執行它。


404(Not-Found),請求的資源沒有被找到


500(Interval Server Error),伺服器內部錯誤


502(Bad GateWay),網關出錯


503(Service Unavailable),由於臨時的伺服器維護或者過載,伺服器當前無法處理請求。


504(Gateway Timeout),作為閘道器或者代理工作的伺服器嘗試執行請求時,未能及時從上游伺服器(URI標識出的伺服器,例如HTTP、FTP、LDAP)或者輔助伺服器(例如DNS)收到響應。


(2)xss,csrf的概念以及防範方法


大公司如bat在面試的時候,web安全問題是必問的問題,所以一定要懂,要徹底理解xss和csrf的概念和防範方式,最好在專案中有用到對這兩種攻擊的防範,這樣會給你的面試加很多分。由xss和csrf涉及的東西比較多,我就不具體給出了,詳情請看XSS攻擊:http://blog.csdn.net/ghsau/article/details/17027893,CSRF攻擊:http://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html


(3)CommonJs,AMD,CMD規範


對於前端模組化來說,這三個規範是必須要了解的,詳情請看我的這篇文章https://zhuanlan.zhihu.com/p/22954387
(4)談談對前端模組化的理解


前端模組話就是把複雜的檔案分成一個個獨立的模組,比如js檔案,分成獨立的模組之後有利於程式碼的重用和維護,但是這樣又會引來模組與模組之間的依賴問題,所以就有了CommonJS、AMD、CMD規範,最後出現了webpack,webpack就是前端模組話的一種解決方案,基本上大公司都會使用webpack,想要詳細的學習webpack的話請看https://zhuanlan.zhihu.com/p/23538138


(5)優雅降級和漸進增強


優雅降級指的是一開始就構建功能完好的網站,然後在慢慢相容低版本的瀏覽器,使得各個瀏覽器之間的差異不要太大。


漸進增強是指在基本功能得到滿足的情況下,對支援新特性的瀏覽器使用新特性,帶給使用者更換的體驗。


優雅降級和漸進增強的出發點不同,前者是慢慢向下相容,是向後看,後著是慢慢向上,增強功能,是向前看。


(6)前端優化(提高網頁的載入速度)


1、使用css sprites,可以有效的減少http請求數


2、使用快取


3、壓縮js,css檔案,減小檔案體積


4、使用cdn,減小伺服器負擔


5、懶載入圖片


6、預載入css,js檔案


7、避免dom結構的深層次巢狀


8、給DOM元素新增樣式時,把樣式放到類中,直接給元素新增類,減少重構,迴流


更多詳細的前端優化請看前端優化:http://www.tuicool.com/articles/J3uyaa


四、前端學習文章推薦


知乎上面有人推薦了很多前端學習網站,具體資訊請看


https://www.zhihu.com/question/19651401/answer/46211739