做者:汪汪
連接:https://www.zhihu.com/question/41466747/answer/132562725
來源:知乎
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。javascript
1、html+css部分、css
(1)css盒模型,可能會要求手寫一個佈局,這個佈局基本上用到的css是margin的負值,boxing-sizing:border-box,佈局儘可能往這方面想。瀏覽器佈局的基本元素是盒,在w3c的標準模式下,width=width,可是在怪異模式下,width=border*2+padding*2+width;其中後代元素的width:100%;參照的是右邊的那個width,html
(2)html5的新特性前端
1、標籤語義化,好比header,footer,nav,aside,article,section等,新增了不少表單元素,入email,url等,除去了center等樣式標籤,還有除去了有性能問題的frame,frameset等標籤html5
2、音視頻元素,video,audio的增長使得咱們不須要在依賴外部的插件就能夠往網頁中加入音視頻元素。java
3、新增不少api,好比獲取用戶地理位置的window.navigator.geoloaction,webpack
4、websocketweb
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,等操做結束後在顯示。
2、JavaScript部分
(1)JavaScript的數據類型
基本數據類型:Number,String,Boolean,Undefined,Null
複雜數據類型:Object,Array,Function,RegExp,Date,Error
全局數據類型:Math
(2)JavaScript的閉包
閉包簡單的說就是一個函數能訪問外部函數的變量,這就是閉包,好比說:
function a(x){
var tem=3;
function b(y){
console.log(x+y+(++tem));
}
}
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函數的區別,這幾個函數就採用了事件委託機制。
3、其餘部分
(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攻擊及防護,CSRF攻擊
(3)CommonJs,AMD,CMD規範
對於前端模塊化來講,這三個規範是必需要了解的,詳情請看個人這篇文章CommonJS,AMD,CMD
(4)談談對前端模塊化的理解
前端模塊話就是把複雜的文件分紅一個個獨立的模塊,好比js文件,分紅獨立的模塊以後有利於代碼的重用和維護,可是這樣又會引來模塊與模塊之間的依賴問題,因此就有了CommonJS、AMD、CMD規範,最後出現了webpack,webpack就是前端模塊話的一種解決方案,基本上大公司都會使用webpack,想要詳細的學習webpack的話請看webpack簡明使用教程
(5)優雅降級和漸進加強
優雅降級指的是一開始就構建功能無缺的網站,而後在慢慢兼容低版本的瀏覽器,使得各個瀏覽器之間的差別不要太大。
漸進加強是指在基本功能獲得知足的狀況下,對支持新特性的瀏覽器使用新特性,帶給用戶更換的體驗。
優雅降級和漸進加強的出發點不一樣,前者是慢慢向下兼容,是向後看,後着是慢慢向上,加強功能,是向前看。
(6)前端優化(提升網頁的加載速度)
1、使用css sprites,能夠有效的減小http請求數
2、使用緩存
3、壓縮js,css文件,減少文件體積
4、使用cdn,減少服務器負擔
5、懶加載圖片
6、預加載css,js文件
7、避免dom結構的深層次嵌套
8、給DOM元素添加樣式時,把樣式放到類中,直接給元素添加類,減小重構,迴流