前端面試概念收集器
前端面試三部曲
本文分為 概念,原生Javascript,css知識點,http協議,網絡安全,性能優化。
概念
Commonjs 在Nodejs服務端上運行,無法在瀏覽器端運行。為了滿足瀏覽器端模塊化的要求,才有了AMD和CMD。
AMD (Asynchronous Module Definition)是 RequireJS 在推廣過程中對模塊定義的規范化產出。對于依賴的模塊,AMD 是提前執行。AMD 推崇依賴前置,把依賴參數以數組形式保存在前半部分。使用規則如下:
define(id?, dependencies?, factory);
CMD (Common Module Definition)是 Seajs 在推廣過程中對模塊定義的規范化產出。 CMD 是延遲執行,CMD 推崇依賴就近,使用規則如下:
define(function(require, exports, module) {
// 模塊代碼
});
Require.js 和Sea.js都是模塊加載器,兩者的主要區別如下:
- 定位有差異。RequireJS 想成為瀏覽器端的模塊加載器,同時也想成為 Rhino / Node 等環境的模塊加載器。Sea.js 則專注于 Web 瀏覽器端,同時通過 Node 擴展的方式可以很方便跑在 Node 環境中。
- 遵循的規范不同。RequireJS 遵循 AMD(異步模塊定義)規范,Sea.js 遵循 CMD (通用模塊定義)規范。規范的不同,導致了兩者 API 不同。Sea.js 更貼近 CommonJS Modules/1.1 和 Node Modules 規范。
- 推廣理念有差異。RequireJS 在嘗試讓第三方類庫修改自身來支持 RequireJS,目前只有少數社區采納。Sea.js 不強推,采用自主封裝的方式來“海納百川”,目前已有較成熟的封裝策略。
- 對開發調試的支持有差異。Sea.js 非常關注代碼的開發調試,有 nocache、debug 等用于調試的插件。RequireJS 無這方面的明顯支持。
-
插件機制不同。RequireJS 采取的是在源碼中預留接口的形式,插件類型比較單一。Sea.js 采取的是通用事件機制,插件類型更豐富。
來自CMD 模塊定義規范
UMD (Universal Module Definition),AMD,CommonJS規范是兩種不一致的規范,雖然他們應用的場景也不太一致,但是人們仍然是期望有一種統一的規范來支持這兩種規范,對兩種情況進行判斷,兼容兩個規范。
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node, CommonJS-like
module.exports = factory(require('jquery'));
} else {
// Browser globals (root is window)
root.returnExports = factory(root.jQuery);
}
}(this, function ($) {
// methods
function myFunc(){};
// exposed public method
return myFunc;
}));
原生Javascript
在做項目或者產品的過程當中,可能你對框架和庫的使用非常多,往往忽視了基礎知識。當然,大公司不僅僅希望你是一個api調用工程師,所以對基礎知識的考察越來越重要。隨著瀏覽器的兼容性越來越好,原生js的重要性也日益明顯。
原生函數
Array
- every() 檢測數組所有元素是否都符合指定條件,只要有一個不滿足則false。
- some() 檢測數組元素中是否有元素符合指定條件,只要有一個滿足則true
- concat() 連接兩個或更多的數組,并返回結果。
- join() 把數組的所有元素放入一個字符串。元素通過指定的分隔符進行分隔。
- pop() 刪除并返回數組的最后一個元素
- push() 向數組的末尾添加一個或更多元素,并返回新的長度。
- reverse() 顛倒數組中元素的順序。
- shift() 刪除并返回數組的第一個元素
- slice() 從某個已有的數組返回選定的元素
- sort() 對數組的元素進行排序
- splice() 刪除元素,并向數組添加新元素。
Math
- abs(x) 返回數的絕對值。
- acos(x) 返回數的反余弦值。
- asin(x) 返回數的反正弦值。
- atan(x) 以介于 -PI/2 與 PI/2 弧度之間的數值來返回 x 的反正切值。
- atan2(y,x) 返回從 x 軸到點 (x,y) 的角度(介于 -PI/2 與 PI/2 弧度之間)。
- ceil(x) 對數進行上舍入。
- cos(x) 返回數的余弦。
- exp(x) 返回 e 的指數。
- floor(x) 對數進行下舍入。
- log(x) 返回數的自然對數(底為e)。
- max(x,y) 返回 x 和 y 中的最高值。
- min(x,y) 返回 x 和 y 中的最低值。
- pow(x,y) 返回 x 的 y 次冪。
- random()返回 0 ~ 1 之間的隨機數。
- round(x) 把數四舍五入為最接近的整數。
- sin(x) 返回數的正弦。
- sqrt(x) 返回數的平方根。
- tan(x) 返回角的正切。
String
- anchor() 創建 HTML 錨。
- big()用大號字體顯示字符串。
- blink() 顯示閃動字符串。
- bold() 使用粗體顯示字符串。
- charAt() 返回在指定位置的字符。
- charCodeAt() 返回在指定的位置的字符的 Unicode 編碼。
- concat() 連接字符串。
- fixed() 以打字機文本顯示字符串。
- fontcolor() 使用指定的顏色來顯示字符串。
- fontsize() 使用指定的尺寸來顯示字符串。
- fromCharCode()從字符編碼創建一個字符串。
- indexOf() 檢索字符串。
- italics() 使用斜體顯示字符串。
- lastIndexOf() 從后向前搜索字符串。
- link() 將字符串顯示為鏈接。
- localeCompare() 用本地特定的順序來比較兩個字符串。
- match()找到一個或多個正則表達式的匹配。
- replace() 替換與正則表達式匹配的子串。
- search() 檢索與正則表達式相匹配的值。
- slice()提取字符串的片斷,并在新的字符串中返回被提取的部分。
- small() 使用小字號來顯示字符串。
- split() 把字符串分割為字符串數組。
- strike() 使用刪除線來顯示字符串。
- sub() 把字符串顯示為下標。
- substr() 從起始索引號提取字符串中指定數目的字符。
- substring() 提取字符串中兩個指定的索引號之間的字符。
- sup() 把字符串顯示為上標。
原生Javascript求數組最小值和最大值
Math.min.apply(null, array)
Math.max.apply(null, array)
原生Dom操作
- 刪除 removeChild 只刪除下一級
- 移動 appendChild 捕獲一個dom插入
- 復制 cloneNode true 深克隆 false 淺克隆
- 插入 appendChild 新建一個dom插入
- 替換 replaceChild
- 前插后插 insertBefore 后插需要用nextSibling找到下一個節點
查找
- getElementsByTagName() 通過標簽名稱
- getElementsByName() 通過元素的Name屬性的值
- getElementById() 通過元素Id,唯一性
重繪重排
當DOM的變化影響了元素的幾何屬性(寬或高),瀏覽器需要重新計算元素的幾何屬性,同樣其他元素的幾何屬性和位置也會因此受到影響。瀏覽器會使渲染樹中受到影響的部分失效,并重新構造渲染樹。這個過程稱為重排。完成重排后,瀏覽器會重新繪制受影響的部分到屏幕,該過程稱為重繪,參考高性能JavaScript DOM編程以及重排與重繪。
事件流(捕獲冒泡),參考JavaScript的事件機制
從document開始,到document結束。事件流分為三個階段:
- 事件捕獲階段
- 處于目標階段
- 事件冒泡階段
事件流分為兩類:捕獲型事件和冒泡型事件。
- 捕獲型事件
從根元素向下傳播,從body開始往每一個div。方法是addEventListener
。(true:捕獲,false:冒泡,默認:false)
- 冒泡型事件
由當前dom向上傳播,從div到body。方法是onclick事件
。
委派代理 參考JavaScript事件代理和委托(Delegation)
var delegate = function(client, clientMethod) {
return function() {
return clientMethod.apply(client, arguments);
}
}
var ClassA = function() {
var _color = "red";
return {
getColor: function() {
console.log("Color: " + _color);
},
setColor: function(color) {
_color = color;
}
};
};
var a = new ClassA();
a.getColor();
a.setColor("green");
a.getColor();
console.log("執行代理!");
var d = delegate(a, a.setColor);
d("blue");
console.log("執行完畢!");
a.getColor();
兼容性寫法
ie下的兼容性問題,js舉例,(轉載)IE8+兼容經驗小結。
IE6能識別下劃線"_"和星號"\ * ",IE7能識別星號" * ",但不能識別下劃線"_",IE6~IE10都認識"\9",但firefox前述三個都不能認識。
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
動畫方面,加速度,重力模擬實現
正則,基本用法和相關函數作用
必須要死記硬背的事\d
數字,即“digit”,\w
字母,即“word”,\s
空格或tab,即“space”。\D
是非數字字符,\S
是非空白字符,/W
是非單詞字符。
{3}
是指有3個這樣的字符,{2,3}
至少出現2次但不超過3次,{2,}
至少出現2次。?
指零個或一個,+
指是一個或多個。*
是任意個也可以沒有。
定義的方法是
new RegExp(pattern,attributes);
其中,參數pattern是一個字符串,指定了正則表達式的模式;參數attributes是一個可選的參數,包含屬性 g,i,m,分別使用與全局匹配,不區分大小寫匹配,多行匹配。
也可以是/pattern/
直接定義。方法包含:
- test() 用于檢索字符串的指定值。
- exec() 返回找到的值,一般是數組。
- compile() 用于改變RegExp()
OOP
如果你需要補救Javascript面向對象這一方面,先看廖雪峰老師的Javascript原型繼承,以及廖雪峰老師的Javascript面向對象編程(二):構造函數的繼承。你必須掌握好一個概念就是原型鏈 。
類繼承方法
類的繼承有4種方法。比較完美的方法是聲明一個空對象,作為中間prototype,參考brandonxiang/example-mocha/demo5。
私有變量
GlobalScope和LocalScope是指面向對象中的共有或私有變量函數,全局變量的搜索較慢,減少document的訪問。私有變量和公有變量是Javascript基礎開發的一個重要環節。下面是一個簡單的例子,name
是公用變量,它是this
的一個屬性。age
是一個私有變量,但是它能被對應的公有方法調用。
function Person(props){
this.name ='brandon';
var age = '26';
this.setAge = function(_age){
age = _age;
}
this.getAge = function(){
return age;
}
}
變量提升和函數提示和作用域
一道容易做錯的JavaScript面試題很好地講述了這個問題。
如果你還是不懂。我舉幾個簡單的例子,來自你不知道的Javascript。
變量提升
a=2;
var a;
console.log(a);
結果輸出為2。由于var a;
變量提升,提升到代碼的頂端,而它不會改變數值。代碼怎變成了:
var a;
a=2;
console.log(a);
如果題目情況是下面這樣。
console.log(a);
var a = 2;
結果輸出是undefined。只有var a;
才會提升。a=2;
并不會提升。
函數提升
foo(); //3
function foo(){
console.log(1);
}
var foo = function(){
console.log(2);
}
foo(); //2
function foo(){
console.log(3);
}
定義為function會直接引起函數提升,提升到文件最上端,第一次foo()
輸出2。而且后一個會將前一個覆蓋。var foo = function(){}
不會被提升。在后面的函數調用會覆蓋,第二次foo()
輸出2。
作用域
- 若apply或者call直接作用于對象,this屬性必須是該對象
- 方法被提取或者出現
(a=a)()
或(a,a)()
奇葩的調用一般都是上級或者window - 沒有var的情況,直接找上級對象
- 箭頭函數需特別注意
閉包
內存泄漏的原因和場景
- 頻繁操作iframe
- 動態創建DOM
- 事件綁定
- Ext框架本身
h5里一些新增api的了解H5的新特性及部分API詳解
cookie,localstorage和sessionstorage
cookie與localstorage區別
- cookie的大小是受限的
- 請求一個新的頁面的時候cookie都會被發送過去
- cookie指定作用域,不可以跨域調用
- cookie是http規范的一部分,localstorage在本地“存儲”數據
- localstorage是html5的新特性,所以舊瀏覽器不一定兼容
localstorage與sessionstorage區別
存儲在 localStorage 里面的數據沒有過期時間(expiration time),而存儲在 sessionStorage 里面的數據會在瀏覽器會話(browsing session)結束時被清除,即瀏覽器關閉時。
瀏覽器的對象模型
- window
- document
- history
- location
- screen
詳情參考 《Javascript高級編程》的BOM一章。
CSS知識點
塊元素
div center h1 hr table ul ol
內聯元素
span a font img strong sub
模型盒
offsetwidth = width + border + padding
clientwidth = width + padding
doctype
html 5 的doctype寫法 <!DOCTYPE html>
haslayout
hack寫法參考 史上最全的CSS hack方式一覽
link和@import的區別
link是XHTML標簽,除了加載CSS外,還可以定義RSS等其他事務;@import屬于CSS范疇,只能加載CSS。
link引用CSS時,在頁面載入時同時加載;@import需要頁面網頁完全載入以后加載。
link是XHTML標簽,無兼容問題;@import是在CSS2.1提出的,低版本的瀏覽器不支持。
link支持使用Javascript控制DOM去改變樣式;而@import不支持。
網絡安全
XSS
XSS(Cross Site Scripting),是一種注入攻擊。沒有過濾掉<script>以及其他敏感關鍵詞的忽視,針對對方的cookie和用戶緩存信息進行攻擊。
CRSF
原理
CSRF(Cross-site request forgery)跨域請求偽造,又叫one click attack或session riding。
它們之間的區別在于:XSS利用站點內的信任用戶。而CSRF是通過偽裝來自受信任用戶的請求來利用受信任的網站。這種方式雖然不是很流行,但是卻難以防范,其危害也不比其他安全漏洞小。
下面是CSRF的常見特性:
- 依靠用戶標識危害網站
- 利用網站對用戶標識的信任
- 欺騙用戶的瀏覽器發送HTTP請求給目標站點
- 另外可以通過IMG標簽會觸發一個GET請求,可以利用它來實現CSRF攻擊。
防范措施
- 服務端進行CSRF防御,在表單當中增加偽隨機數。
- 驗證碼
- One-Time Tokens
- 持久化的授權方法切換成瞬間的授權方法。
- 雙提交cookie
http協議
報文格式
報文格式分為請求報文和響應報文。
請求報文
請求報文又分為4個部分。
- request-line 請求方法get,post,head,put,delete等
- headers 請求頭部由關鍵字/值對組成,每行一對,關鍵字和值用英文冒號“:”分隔
- blank line 最后一個請求頭之后是一個空行,發送回車符和換行符,通知服務器以下不再有請求頭。
- request-body 請求數據不在GET方法中使用,而是在POST方法中使用。與請求數據相關的最常使用的請求頭是Content-Type和Content-Length。
響應報文
響應報文報文又分為4個部分。
- <status-line>狀態行
- 1xx:指示信息--表示請求已接收,繼續處理。
- 2xx:成功--表示請求已被成功接收、理解、接受。
- 3xx:重定向--要完成請求必須進行更進一步的操作。
- 4xx:客戶端錯誤--請求有語法錯誤或請求無法實現。
- 5xx:服務器端錯誤--服務器未能實現合法的請求。
- 200 OK:客戶端請求成功。
- 400 Bad Request:客戶端請求有語法錯誤,不能被服務器所理解。
- 401 Unauthorized:請求未經授權,這個狀態代碼必須和WWW-Authenticate報頭域一起使用。
- 403 Forbidden:服務器收到請求,但是拒絕提供服務。
- 404 Not Found:請求資源不存在,舉個例子:輸入了錯誤的URL。
- 500 Internal Server Error:服務器發生不可預期的錯誤。
- 503 Server Unavailable:服務器當前不能處理客戶端的請求,一段時間后可能恢復正常,舉個例子:HTTP/1.1 200 OK(CRLF)。
- <headers>消息報頭
- <blank line>
- [<response-body>] 響應正文
get與post區別
get
要求服務器請求URL定位的資源放在響應報文的數據部分,回送客戶端。請求參數和對應的值之間跟在URL后面。利用一個問號(?)代表著url的結束和請求參數的開始。傳遞參數長度受到限制。長度限制1024個字符。
缺點
- 不適合傳送私密數據
- 數據量大不適合使用get方式
post
請求行中不包含數據字符串,這些數據保存在請求內容中,各數據之間用&分割開。post也能完成get請求。
關于HTTP請求GET和POST的區別
1.GET提交,請求的數據會附在URL之后(就是把數據放置在HTTP協議頭<request-line>中),以?分割URL和傳輸數據,多個參數用&連接;例如:login.action?name=hyddd&password=idontknow&verify=%E4%BD%A0 %E5%A5%BD
。如果數據是英文字母/數字,原樣發送,如果是空格,轉換為+,如果是中文/其他字符,則直接把字符串用BASE64加密,得出如: %E4%BD%A0%E5%A5%BD,其中%XX中的XX為該符號以16進制表示的ASCII。
POST提交:把提交的數據放置在是HTTP包的包體<request-body>中。上文示例中紅色字體標明的就是實際的傳輸數據
因此,GET提交的數據會在地址欄中顯示出來,而POST提交,地址欄不會改變
2.傳輸數據的大小:
首先聲明,HTTP協議沒有對傳輸的數據大小進行限制,HTTP協議規范也沒有對URL長度進行限制。 而在實際開發中存在的限制主要有:
GET:特定瀏覽器和服務器對URL長度有限制,例如IE對URL長度的限制是2083字節(2K+35)。對于其他瀏覽器,如Netscape、FireFox等,理論上沒有長度限制,其限制取決于操作系統的支持。
因此對于GET提交時,傳輸數據就會受到URL長度的限制。
POST:由于不是通過URL傳值,理論上數據不受限。但實際各個WEB服務器會規定對post提交數據大小進行限制,Apache、IIS6都有各自的配置。
3.安全性:
POST的安全性要比GET的安全性高。注意:這里所說的安全性和上面GET提到的“安全”不是同個概念。上面“安全”的含義僅僅是不作數據修改,而這里安全的含義是真正的Security的含義,比如:通過GET提交數據,用戶名和密碼將明文出現在URL上,因為(1)登錄頁面有可能被瀏覽器緩存, (2)其他人查看瀏覽器的歷史紀錄,那么別人就可以拿到你的賬號和密碼了。
優化性能
結合移動開發規范概述,我的總結:
- 圖片使用CSS Sprites 或 DataURI
- 壓縮靜態資源(HTML/CSS/JS/Image)
- 外鏈 CSS 中避免 @import 引入
- 初始請求資源數 < 4
- 數據離線化,考慮將數據緩存在 localStorage
- 考慮內嵌小型的靜態資源內容
- 初始請求資源gzip后總體積<50kb
- 避免打包大型類庫
- 確保接入層已開啟Gzip壓縮(考慮提升Gzip級別,使用CPU開銷換取加載時間)
- 盡量使用CSS3代替圖片
spa優化
- 初始首屏之外的靜態資源(JS/CSS)延遲加載
- 初始首屏之外的圖片資源按需加載(判斷可視區域)
- 單頁面應用(SPA)考慮延遲加載非首屏業務模塊
- 開啟Keep-Alive鏈路復用
運行性能優化, 達到操作足夠流暢
- 避免 iOS 300+ms 點擊延時問題
- 緩存 DOM 選擇與計算
- 避免觸發頁面重繪的操作
- Debounce連續觸發的事件(scroll / resize / touchmove等),避免高頻繁觸發執行
- 盡可能使用事件代理,避免批量綁定事件
- 使用CSS3動畫代替JS動畫
- 避免在低端機上使用大量CSS3漸變陰影效果,可考慮降級效果來提升流暢度
- HTML結構層級保持足夠簡單
- 盡能少的使用CSS高級選擇器與通配選擇器
參考
Javascript面試題
前端的知識更新太快,此文持續更新
感想
我面試大大小小很多公司,有這么一點感想。面試其實是一個雙向的過程,面試官在面試我,檢驗著我的能力。但是,同時,也是我在面試著面試官。面試官的問題是否專業,是否基礎,直接反映出公司對應部門對員工的要求。有些面試官不太懂為啥我會默默的觀察著整個辦公室的一種工作氛圍,有時工作氛圍說明很多問題。其中包括工作人員的態度,流動性,實習生的比例。這些種種因素都會影響你的就業選擇,也希望各位讀者能夠認真擇業,不只是為了一份工資。
各位GIS開發工程師可能也會考慮往前端全棧的方向發展,可以參考一位同行的博客----前端面試筆記。