數(shù)據(jù)結(jié)構(gòu)與算法
棧和隊列的區(qū)別
網(wǎng)絡基礎
HTTP 無狀態(tài)怎么理解
可以從REST的角度來理解這個問題。我們知道REST風格是無狀態(tài)的。而REST是基于HTTP協(xié)議的,所以REST的無狀態(tài)基本就可以解釋HTTP的無狀態(tài)。
TCP三次握手與四次揮手
三次握手
為了準確無誤地將數(shù)據(jù)送到目標處,TCP采用三次握手策略,過程中使用了TCP的標志:SYN和ACK.
三次握手
Client --> 置SYN標志 序列號 = J,確認號 = 0 ----> Server
Client <-- 置SYN標志 置ACK標志 序列號 = K, 確認號 = J + 1 <-- Server
Clinet --> 置ACK標志 序列號 = J + 1,確認號 = K + 1 --> Server
四次揮手
Client -> 發(fā)送FIN 序列號 = J,確認號 = 0 --> Server
Server -> 發(fā)送ACK 確認號 = J + 1
Server -> 發(fā)送FIN 序列號 = K, 確認號 = 0 -> Client
Client -> 發(fā)送ACK 確認號 = K+1
HTTPS
HTTPS是在HTTP與TCP之間添加一個安全協(xié)議層(SSL或TSL).
網(wǎng)絡請求中往往中間需要很多服務器或者路由器的轉(zhuǎn)發(fā),中間的節(jié)點都可能篡改信息,而如果使用HTTPS,密鑰在請求客戶端和終點站才有,所以相對于HTTP會更安全,就是因為HTTPs利用SSL/TSL協(xié)議傳輸,它包含證書等安全信息,保證了傳輸過程的安全性。
前端其他問題
前端工程價值
- 解放前后端互相在開發(fā)進度上的依賴問題,前后端可以同時進行
- 為簡化用戶使用,提高交互體驗/用戶體驗
- 解決瀏覽器兼容問題
- 提高瀏覽速度(性能)
- 跨平臺應用的支持
- 展現(xiàn)數(shù)據(jù),數(shù)據(jù)處理
- 降低后端壓力
瀏覽器緩存技術
** Etag **
當發(fā)送一個服務器的請求時,瀏覽器會首先進行緩存過期的判斷,瀏覽器根據(jù)緩存過期的時間判斷緩存文件是否過期。
- 若沒有過期,則不向服務器發(fā)送請求,直接使用緩存中的結(jié)果
Session Cookie LocalStorage
全局環(huán)境與局部環(huán)境
JS對象 BOM DOM
瀏覽器的基本組成與頁面渲染原理
為什么不能頻繁操作DOM
重排與重繪
前端模塊化
https://segmentfault.com/p/1210000007731421?from=singlemessage&isappinstalled=1
CommonJs規(guī)范 - NodeJs實現(xiàn) 同步
分支 異步
AMD RequireJs
CMD SeaJs
UMD 前后端整合
ES6 - I import export
前端優(yōu)化
前端兼容性
漸進增強和優(yōu)雅降級
** 漸進增強 ** :針對低版本瀏覽器進行構(gòu)建頁面,保證最基本的功能,然后再針對高級瀏覽器進行效果、交互等改進和追加功能達到更好的用戶體驗。
** 優(yōu)雅降級 ** :一開始就構(gòu)建完整的功能,然后再針對低版本瀏覽器進行兼容。
前端安全性
常見的幾種安全攻擊
SQL 注入
XSS
CSRF
前端工具
模塊打包工具
** Webpack **
- 模塊打包工具
- 管理依賴模塊間依賴,生成優(yōu)化并且合并后的靜態(tài)資源文件
- 編譯輸出靜態(tài)文件,將代碼分割成不同的chunk,實現(xiàn)按需加載,降低初始化時間
- 所有文件都是模塊, html, js, css, 圖片等
- 模塊加載器, 支持串聯(lián)操作
- 以commonJs的形式書寫,但對AMD/CMD的支持也比較全面,方便舊項目進行代碼遷移
HTML5
Webworker
Js中的多線程實現(xiàn)
Websocket
SVG
Canvas
CSS
position的值, relative和absolute分別是相對于誰進行定位的?
盒模型
IE盒模型與其他瀏覽器的盒模型
CSS選擇器的優(yōu)先級
JavaScript
ES6
Js運行機制
- Javascript 是單線程
Javascript 的單線程與它的用途有關 - 任務隊列
任務可分為兩種,一種是同步任務,一種是異步任務。
** 同步任務 :在主線程上排隊執(zhí)行的任務,只有前一個任務執(zhí)行完畢后,才能執(zhí)行后一個任務;
** 異步任務 :不進入主線程,而進入任務隊列(task queue)的任務,只有任務隊列通知主線程,某個異步任務要以執(zhí)行了,該任務才會進入主線程執(zhí)行。
** 異步任務運行機制如下:
Paste_Image.png
1)所有同步任務都在主線程上執(zhí)行,形成一個執(zhí)行棧(execution context stack)。
2)主線程之外,還存在一個"任務隊列"(task queue)。只要異步任務有了運行結(jié)果,就在"任務隊列"之中放置一個事件。
3)一旦"執(zhí)行棧"中的所有同步任務執(zhí)行完畢,系統(tǒng)就會讀取"任務隊列",看看里面有哪些事件。那些對應的異步任務,于是結(jié)束等待狀態(tài),進入執(zhí)行棧,開始執(zhí)行。
4)主線程不斷重復上面的第三步。
** 只要主線程空了,就會去讀取"任務隊列",這就是JavaScript的運行機制。這個過程會不斷重復。
- 事件和任務隊列
** 任務隊列 **
- 是一個事件的隊列,也可以理解成是消息隊列。主線程讀取任務隊列就是讀取里面有哪些事件。
- 任務隊列里面不止有IO設備的事件,也有用戶操作產(chǎn)生的事件。只要指定過回調(diào)函數(shù),這些事件發(fā)生時就會進入任務隊列中,等待主線程讀取。主線程執(zhí)行異步任務,就是執(zhí)行對應的回調(diào)函數(shù)。
-
主線程會首先檢查執(zhí)行時間,某些事件只有到了規(guī)定的時間,才能返回主線程。如setTimeout().
** Event Loop **
主線程從事件隊列中讀取事件的過程是不斷循環(huán)的,所以整個的運行機制就是一個Event Loop,也叫事件循環(huán)。
Paste_Image.png - 定時器
除了放置異步任務的事件,"任務隊列"還可以放置定時事件,即指定某些代碼在多少時間之后執(zhí)行。這叫做"定時器"(timer)功能,也就是定時執(zhí)行的代碼。
setTimeout()
setInterval()
HTML5標準規(guī)定了setTimeout()的第二個參數(shù)的最小值(最短間隔),不得低于4毫秒,如果低于這個值,就會自動增加。在此之前,老版本的瀏覽器都將最短間隔設為10毫秒。另外,對于那些DOM的變動(尤其是涉及頁面重新渲染的部分),通常不會立即執(zhí)行,而是每16毫秒執(zhí)行一次。這時使用requestAnimationFrame()的效果要好于setTimeout()。
需要注意的是,setTimeout()只是將事件插入了"任務隊列",必須等到當前代碼(執(zhí)行棧)執(zhí)行完,主線程才會去執(zhí)行它指定的回調(diào)函數(shù)。要是當前代碼耗時很長,有可能要等很久,所以并沒有辦法保證,回調(diào)函數(shù)一定會在setTimeout()指定的時間執(zhí)行。
Js事件模型
參考:https://segmentfault.com/a/1190000006934031?from=singlemessage&isappinstalled=1
DOM事件探秘
- ** 發(fā)布訂閱模式(觀察者模式)**
Javascript的事件模型基于發(fā)布請閱模式,可以讓多個觀察者對象同時監(jiān)聽某一個主題對象,這個主題對象的狀態(tài)變化會通知所有的訂閱者,使得它們能夠做出反應。
以下是用js實現(xiàn)的一個發(fā)布訂閱模式
var events = (function () {
var topics = {};
return {
publish: function (topic, info) {
console.log("publish a topic:" + topic);
if (topics.hasOwnProperty(topic)) {
topics[topic].forEach(function(handler) {
handler(info ? info : {});
});
}
},
subscribe: function(topic, handler) {
console.log("subscribe an topic" + topic);
if (!topics.hasOwnProperty(topic)) {
topics[topic] = [];
}
topics[topic].push(handler);
},
remove: function(topic, handler) {
if (!topics.hasOwnProperty(topics)) {
return;
}
var handlerIndex = -1;
topics[topic].forEach(function (element, index) {
if (element === handler) {
handlerIndex = index;
}
});
if (handlerIndex >= 0) {
topics[topic].splice(handlerIndex, 1);
}
}
};
})();
var handler = function (info) {
console.log(info);
}
events.subscribe("hello", handler);
events.publish("hello", "hello world");
- ** 事件與事件流 **
事件是與瀏覽器或文檔交互的瞬間,如點擊按鈕,填寫表格等,它是JS與HTML之間交互的橋梁。DOM是樹形結(jié)構(gòu),如果同時給父子節(jié)點都綁定事件時,當觸發(fā)子節(jié)點的時候,這兩個事件的發(fā)生順序如何決定?這就涉及到事件流的概念,它描述的是頁面中接受事件的順序。
事件流有兩種:
** 事件冒泡(Event Capturing): ** 是一種從下往上的傳播方式。事件最開始由最具體的元素(文檔中嵌套層次最深的那個節(jié)點接受, 也就是DOM最低層的子節(jié)點), 然后逐漸向上傳播到最不具體的那個節(jié)點,也就是DOM中最高層的父節(jié)點。
** 事件捕獲(Event Bubbling): **與事件冒泡相反。事件最開始由不太具體的節(jié)點最早接受事件, 而最具體的節(jié)點最后接受事件。 - ** 事件模型 **
** DOM 0級模型 **
HTML代碼中直接綁定:
<input type="button" onclick="fun()">
通過JS代碼指定屬性值:
var btn = document.getElementById('.btn');btn.onclick = fun;
移除監(jiān)聽函數(shù):
btn.onclick = null;
這種方式所有瀏覽器都兼容,但是邏輯與顯示并沒有分離。
** IE事件模型 **
IE事件模型共有兩個過程:
事件處理階段(target phase)。事件到達目標元素, 觸發(fā)目標元素的監(jiān)聽函數(shù)。
事件冒泡階段(bubbling phase)。事件從目標元素冒泡到document, 依次檢查經(jīng)過的節(jié)點是否綁定了事件監(jiān)聽函數(shù),如果有則執(zhí)行。
事件綁定監(jiān)聽函數(shù)的方式如下:
attachEvent(eventType, handler)
事件移除監(jiān)聽函數(shù)的方式如下:
detachEvent(eventType, handler)
參數(shù)說明:
eventType指定事件類型(注意加on)
handler是事件處理函數(shù)
Example:
var btn = document.getElementById('.btn');
btn.attachEvent(‘onclick’, showMessage);
btn.detachEvent(‘onclick’, showMessage);
** DOM 2級模型 **
屬于W3C標準模型,現(xiàn)代瀏覽器(除IE6-8之外的瀏覽器)都支持該模型。在該事件模型中,一次事件共有三個過程:
事件捕獲階段(capturing phase)。事件從document一直向下傳播到目標元素, 依次檢查經(jīng)過的節(jié)點是否綁定了事件監(jiān)聽函數(shù),如果有則執(zhí)行。
事件處理階段(target phase)。事件到達目標元素, 觸發(fā)目標元素的監(jiān)聽函數(shù)。
事件冒泡階段(bubbling phase)。事件從目標元素冒泡到document, 依次檢查經(jīng)過的節(jié)點是否綁定了事件監(jiān)聽函數(shù),如果有則執(zhí)行。
事件綁定監(jiān)聽函數(shù)的方式如下:
addEventListener(eventType, handler, useCapture)
事件移除監(jiān)聽函數(shù)的方式如下:
removeEventListener(eventType, handler, useCapture)
Example:
var btn = document.getElementById('.btn');
btn.addEventListener(‘click’, showMessage, false);
btn.removeEventListener(‘click’, showMessage, false);
參數(shù)說明:
eventType指定事件類型(不要加on)
handler是事件處理函數(shù)
useCapture是一個boolean用于指定是否在捕獲階段進行處理,一般設置為false與IE瀏覽器保持一致。
DOM事件模型中的事件對象常用屬性:
- type用于獲取事件類型
- target獲取事件目標
- stopPropagation()阻止事件冒泡
- preventDefault()阻止事件默認行為
IE事件模型中的事件對象常用屬性: - type用于獲取事件類型
- srcElement獲取事件目標
- cancelBubble阻止事件冒泡
- returnValue阻止事件默認行為
Javascript垃圾回收機制
** 標記清除 ** -> 最常見的垃圾回收方式
這是JavaScript最常見的垃圾回收方式,當變量進入執(zhí)行環(huán)境的時候,比如函數(shù)中聲明一個變量,垃圾回收器將其標記為“進入環(huán)境”,當變量離開環(huán)境的時候(函數(shù)執(zhí)行結(jié)束)將其標記為“離開環(huán)境”。垃圾回收器會在運行的時候給存儲在內(nèi)存中的所有變量加上標記,然后去掉環(huán)境中的變量以及被環(huán)境中變量所引用的變量(閉包),在這些完成之后仍存在標記的就是要刪除的變量了
** 引用計數(shù) ** -> 會出現(xiàn)因為循環(huán)引用而出現(xiàn)的無法回收而導致的內(nèi)存泄漏
參考: http://www.itdecent.cn/p/80ed3805edc3
創(chuàng)建對象的幾種方式
- ** 使用{}
var bar = {
color: "blue"
};
- ** 使用new關鍵字 **
var bar = new Object();
bar.color = "blue";
- ** 使用構(gòu)造函數(shù) **
var Fun = function (color) {
this.color = color;
}
var bar = new Fun();
面向?qū)ο笈c繼承的幾種方式
** 原型編程泛型基本規(guī)則 **
- 所有的數(shù)據(jù)都是對象
- 要得到一個對象,不是通過 實例化類,而是找到一個對象作為原型并克隆它
- 對象會記住它的原型
- 如果對象本身無法響應某個請求,它會把這個請求委托給它自己的原型
** 實現(xiàn)方式 **
http://www.jb51.net/article/81766.htm
解決跨域問題
Jsonp
Cors
Document.domain
Document.name
HTML5 postMessage
AJAX
創(chuàng)建過程
(1)創(chuàng)建XMLHttpRequest對象,也就是創(chuàng)建一個異步調(diào)用對象.
(2)創(chuàng)建一個新的HTTP請求,并指定該HTTP請求的方法、URL及驗證信息.
(3)設置響應HTTP請求狀態(tài)變化的函數(shù).
(4)發(fā)送HTTP請求.
(5)獲取異步調(diào)用返回的數(shù)據(jù).(6)使用JavaScript和DOM實現(xiàn)局部刷新.
參考:https://segmentfault.com/a/1190000004322487
說說你對作用域鏈的理解
作用域鏈的作用是保證執(zhí)行環(huán)境里有權訪問的變量和函數(shù)是有序的,作用域鏈的變量只能向上訪問,變量訪問到window對象即被終止,作用域鏈向下訪問變量是不被允許的。
閉包
實現(xiàn)延遲打印1-5
for (var i = 0; i < 5; i++) {
(function (i) {
setTimeout(function () {
console.log(i)
}, i * 1000)
})(i);
}
for (var i = 0; i < 5; i++) {
setTimeout(function (i) {
return function() { console.log(i); };
}(i), i * 1000)
}
[1,2,3,4,5,6].forEach(i => {
setTimeout(function () {
console.log(i)
}, i * 1000);
});
嚴格模式 (use strict)
- 非嚴格模式下有些錯誤會在運行時被悄悄地忽略掉,而在嚴格模式下,這些錯誤會被拋出來,從而方便debug,通常來說,這是一種很好的實踐。
- 防止給未聲明的變量賦值
- 非嚴格模式下如果引用的this是null或者undefined的話會自動將this指向global對象,這種情況會造成一些比較難發(fā)現(xiàn)且頭疼的bug。而在嚴格模式下,則會拋出錯誤。
- 防止在一個對象內(nèi)重復定義屬性。
- 安全使用eval()
- delete操作符
如何判讀一個變量是個整數(shù) (實現(xiàn) isInteger(x))
在ES6中,Number.isInteger() 可以用來判斷是否為整數(shù)。
在ES6之前的版本中這個問題則比較復雜,因為numberic的值通常是作為一個浮點數(shù)來存儲的,只能用比較取巧的方式來實現(xiàn)這樣的判斷邏輯。
function isInteger(x) { return (x^0) === x; }
function isInteger(x) { return Math.round(x) === x; }
function isInteger(x) {
return (typeof x === "number") && (x % 1 === 0;;
}
此外也可以使用parseInt來實現(xiàn)
function isInteger(x) { return parseInt(x, 10) === x;}
數(shù)組操作 (split, reverse, push, slice, concat)
What will the code below output to the console and why?
var arr1 = "john".split('');
var arr2 = arr1.reverse();
var arr3 = "jones".split('');
arr2.push(arr3);
console.log("array 1: length=" + arr1.length + " last=" + arr1.slice(-1));
console.log("array 2: length=" + arr2.length + " last=" + arr2.slice(-1));
JavaScript 設計模式
Angular
雙向綁定如何實現(xiàn)
臟檢查機制
React
虛擬DOM 實現(xiàn)機制
JQuery
Jquery 綁定事件的方法
target.on("click");
target.click(function() {
});
target.live("click", function () {
});
target.bind("click", function () {
});
#### Jquery的鏈式操作如何實現(xiàn)
# 正則表達式
****
#### 語法
> https://msdn.microsoft.com/zh-cn/library/ae5bf541(VS.80).aspx
#### 驗證身份證
> ```
var reg=/^[1-9]{1}[0-9]{14}$|^[1-9]{1}[0-9]{16}([0-9]|[xX])$/;
面試題
更多面試題: https://www.toptal.com/javascript/interview-questions
鼠標點擊頁面中的任意標簽,alert標簽名稱 (兼容性)
<script type="text/javascript" >
document.onClick() = function(event) {
var e = event || window.event;
var src = event.target || event.srcElement;
alert(src.tagName.toLowercase());
}
</script>
異步加載js方案,不少于兩種
** 同步加載 **
就是我們平時使用的最多的方式,在頁面中使用script標簽
這種模式也叫阻塞模式,會阻止瀏覽器的后續(xù)處理,停止后續(xù)的解析,只有當加載完成,才能進行下一步的操作,所以默認同步執(zhí)行才是比較安全的。但是這種方式會造成頁面的阻塞,所以一般建議把<script>標簽放在<body>結(jié)尾,這樣盡可能減少頁面阻塞。
** 異步加載 **
異步加載 又叫非阻塞加載,瀏覽器在下載執(zhí)行js的同時,還會繼續(xù)進行后續(xù)頁面的處理。主要有以下幾中方式:
- ** Script Dom Element **
(function() {
var scriptEle = document.createElement("script");
scriptEle.type = "text/javascript";
scriptEle.async = true;
scriptEle.src="http://xxx/jquery.js";
var x = document.getElementByTagName("head")[0];
x.insertBefore(scriptEle, x.firstChild);
})();
google的使用方式
(function(){;
var ga = document.createElement('script');
ga.type = 'text/javascript';
ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();
缺點: 執(zhí)行完成之前會阻止onLoad事件的觸發(fā),而現(xiàn)在很多頁面的代碼都會在onLoad的時候做一些額外的渲染動作,所以還是會阻塞部分頁面的初始化的處理。
- ** onload時的異步加載 **
;(function () {
if (window.attachEvent) {
window.attachEvent('load', asyncLoad)
} else {
window.addEventListener('load', asyncLoad)
}
var asyncLoad = function () {
var scriptEle = document.createElement('script')
scriptEle.type = 'text/javascript'
scriptEle.async = true
scriptEle.src = 'http://xxx/jquery.js'
var x = document.getElementByTagName('head')[0]
x.insertBefore(scriptEle, x.firstChild)
}
})()
注:DOMContentLoaded與load區(qū)別
前者是在document 已經(jīng)解析完成,頁面中的dom元素可用,但是頁面中的圖片,視頻,音頻等資源還未加載完,作用同jquery的ready. 后者的區(qū)別在于頁面中所有資源包括js都加載完成。
- ** 其他方法**
** XHR Injection **
通過XMLHttpRequest來獲取javascript,然后創(chuàng)建一個script元素插入到DOM結(jié)構(gòu)中。ajax請求成功后設置script.text為請求成功后返回的responseText
var getXmlHttp = function () {
var obj
if (window.XMLHttpRequest)
obj = new XMLHttpRequest()
else
obj = new ActiveXObject('Microsoft.XMLHTTP')
return obj
}
var xhr = getXmlHttp()
xhr.open('GET', 'http://xxx.com/jquery.js', true)
xhr.send()
xhr.onReadyStateChange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var script = document.createElement('script')
script.text = xhr.response.text
document.getElementsByTagName('head')[0].appendChild(script)
}
}
** XHR Eval **
與XHR Injection對responseText的執(zhí)行方式不同,直接把responseText放在eval()函數(shù)里面執(zhí)行。
** Script In IFrame **
在父窗口插入一個iframe元素,然后再iframe中執(zhí)行加載JS的操作。
var insertJS = function(){alert(2)};
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
var doc = iframe.contentWindow.document;//獲取iframe中的window要用contentWindow屬性。
doc.open();
doc.write("<script>var insertJS = function(){};<\/script><body onload='insertJS()'></body>");
doc.close();
- ** HTML5新屬性:async和defer屬性 **
** defer屬性 **:IE4.0就出現(xiàn)。defer屬聲明腳本中將不會有document.write和dom修改。瀏覽器會并行下載其他有defer屬性的script。而不會阻塞頁面后續(xù)處理。注:所有的defer腳本必須保證按順序執(zhí)行的。
<script type="text/javascript" defer></script>
** async屬性 **:HTML5新屬性。腳本將在下載后盡快執(zhí)行,作用同defer,但是不能保證腳本按順序執(zhí)行。他們將在onload事件之前完成。
<script type="text/javascript" defer></script>
Firefox 3.6、Opera 10.5、IE 9和最新的Chrome和Safari都支持async屬性。可以同時使用async和defer,這樣IE 4之后的所有IE都支持異步加載。
沒有async屬性,script將立即獲?。ㄏ螺d)并執(zhí)行,期間阻塞了瀏覽器的后續(xù)處理。如果有async屬性,那么script將被異步下載并執(zhí)行,同時瀏覽器繼續(xù)后續(xù)的處理。
** 總結(jié) **: 對于支持HTML5的瀏覽器,實現(xiàn)JS的異步加載只需要在script元素中加上async屬性,為了兼容老版本的IE還需加上defer屬性;對于不支持HTML5的瀏覽器(IE可以用defer實現(xiàn)),可以采用以上幾種方法實現(xiàn)。原理基本上都是向DOM中寫入script或者通過eval函數(shù)執(zhí)行JS代碼,你可以把它放在匿名函數(shù)中執(zhí)行,也可以在onload中執(zhí)行,也可以通過XHR注入實現(xiàn),也可以創(chuàng)建一個iframe元素,然后在iframe中執(zhí)行插入JS代碼。
設計一種方案,確保頁面中所有js加載完全
function loadScript (url, callback) {
var script = document.createElement('script')
script.type = 'text/javascript'
if (script.readyState) {
script.onreadystatechange = function () {
if (script.readyState == 'loaded' || script.readyState == 'complete') {
script.onreadystatechange = null
callback()
}
}
} else {
script.onload = function () {
callback()
}
}
script.src = url
document.getElementsByName('head')[0].appendChild(script)
}

