最近暑期實習招聘已經開始,我的目前參加了阿里的內推及騰訊和百度的實習生招聘,在此總結一下
一是備忘、總結提高,二是但願給你們一些參考
其餘面試及基礎相關能夠參考其餘博文:javascript
每位面試官的面試時間基本都在 40-80 分鐘,下面先簡要介紹各個面試流程,問題詳情見具體公司分類css
騰訊內推&校招 offer gothtml
首先騰訊分爲三面,都爲技術面:前端
複試兩個面試官,包括電話遠程 online codingvue
(我也不知道爲何幾天內三個面試官面我,只算兩個面試過程 ヾ(´A`)ノ゚)終面一位面試官java
這位應該是大 boss ,他說並非前端開發的,面試的問題也不會很深刻,主要看我的對這個領域的想法以及對常見問題在前端領域的解決思路,不按套路出牌,emmm 感受回答的不理想網絡安全的實現node
如何檢測惡意腳本
如何屏蔽
...react
騰訊二面 & online codinggit
騰訊的遠程 online coding 時間較長,大概一個多小時,不只要按要求編程,也要口述思路以及關鍵點,過程相似壓力面,面試官說完題目要求會給你思考及coding 時間,他能夠遠程看到面試者的 coding 狀態,主要考察應變能力,思惟活躍度,編碼習慣,調試能力,以及測試方法,本人在此過程當中沒有太注意測試過程,致使對於特殊狀況考慮不全面,測試樣例不完善,望小夥伴們注意 ヾ(´A`)ノ゚,不過,在口述代碼時發現也能夠本身提出來須要完善的地方。es6
coding 爲一到兩題,後續問題都是圍繞它結合實際應用進行拓展,主要考察是否能靈活運用以及類似的思路轉換,當時面試時間太長以及基礎知識較差,進制轉換,存儲那些個基礎被小學老師收回,一連串的炮轟簡直爽歪歪,我的表示此過程本身的表現較差,也要重視基礎基礎啊老鐵們 ( ̄_ ̄ )
經歷了騰訊雲的四個面試官,以及其餘部門一個面試官的醬油麪,騰訊的技術面試官廣泛語速較快,思路轉換很快,要跟上面試官的節奏,聊到本身比較熟悉的能夠多說幾句,他們也會順着你回答的內容進行深刻,也會引導面試者的回答方向,若是不太熟儘可能坦白一些,不懂裝懂很容易 gg
才接到通知另加兩輪面試委員會現場技術面,簡直爽歪歪 ヾ(´A`)ノ
騰訊校招現場
一面
面試官很 nice,基本看着簡歷問的,話題圍繞項目(項目隔得時間過久,心裏寧願粗暴的技術面),基本爲大體的瞭解,包括平時的學習習慣和關注的技術發展sass--定義function,使用rem
問是否有其餘負面做用
想到了頁面閃爍,因爲初始化時須要計算頁面尺寸,可能有縮放
如何避免:
<!-- 若是在頁面加載完成後,頁面是用js動態添加的,這個問題就不太明顯, --> doc.addEventListener('DOMContentLoaded‘', function(e) { <!-- doc.body.style.fontSize = 12 * dpr + 'px'; 淘寶處理 --> }, false);
媒體查詢
二面
面試官不是前端的,因此沒有問很深刻的問題,主要模擬實際場景考察實現思路以及先後端的方案,後端沒說出什麼,基本上只是就前端層面進行了描述,包括實現思路、須要注意的問題、以及性能和安全方面的考慮阿里內推 二面 卒
我投的是螞蟻金服的前端開發,投過簡歷硬生生排隊等了12天,還被內推人提早告知螞蟻的前端很嚴格 ( ̄_ ̄ )
阿里分爲在線測試,初試 ......
首先是在線測試
投完簡歷後官網會有相關在線測試題掛掉了。。。
baidu offer got
百度投的是核心搜索部門,但一面後估計不合適,沒有了消息,後簡歷轉到百度金融
一面
面試官語速很快,通常不給太多思考時間--------感受本身說話都打着節拍 ( ̄_ ̄ )
二面
面試官很和善,是惟一一個認真看了我博客的面試官,很榮幸,也很緊張
基本偏向基礎
但因爲沒安排好時間,面試時在戶外,聽不太清面試官的問題,在此提醒各位小夥伴提早選好面試場地,避免環境影響
三面
一樣和善的面試官,開始考察基礎知識,編譯原理,網絡協議等基礎,後面考察我的素質,後續更注重我的經歷,包括如何學習,找實習,實習中遇到的問題及如何解決,最驕傲的事情等等
關於結尾
百度 & 阿里面試結束後都有問:你以爲在面試過程當中有什麼沒問到,但本身掌握比較好的技能麼
面阿里時,頭腦發暈,回答:沒有,我感受您面的很專業,問的知識點都是比較核心的 ( ̄_ ̄ )騰訊二面教訓
我:是否有導師帶,實習的大體安排以及部門業務等
效果 差
面試官曰:
你那麼關係有沒有導師的問題,但學習中最重要的是靠本身,導師並非負責回答你全部問題的
百度經驗
我:部門是否有按期交流分享的機會;工做中是按照職位仍是業務部門劃分,如何交流;偏向頁面仍是業務邏輯
我的在自學過程當中發現前端體系太大,不知對於前端學習,您有什麼建議麼
面試官:不少前端初學者都有相似的困惑,你最好本身從頭開始作一個項目,無論是本身瞎想的仍是模仿的,在項目過程當中去發現須要學習什麼技術,在遇到問題的時候才知道去哪一個方向發展和思考,只有在項目中才能持續的學習和提升,前端知識很碎,沒有項目很難有一連串的經歷
整體
整體來講,面試中有按照面試題出的,也有直接聊的,通常也會結合實際工做中會遇到的場景以及技術中的一些坑,回答時結合本身的項目經驗會更好,大廠的面試官更側重於面試者對深層原理的理解,對於實習生來講通常面基礎,若是有深查原理的習慣,我的的可塑造性也會較高
三廠體驗對比:
協議都會問到
相對來講,百度更多基礎知識點,更多考察對更基本的知識掌握,不限於前端,還包括組成原理和編譯原理的一些知識,固然前端偏多(好比選取一個class 標籤元素有幾種方式等小細節的問題來考察,細到要把每一個表達說完整,把每一個單詞拼出來)
阿里騰訊更側重應用中的注意事項(如:IE 和其餘瀏覽器中的事件處理機制)不太揪細節
三廠都有問到算法,騰訊相對更注重對算法和邏輯,對面試者基礎知識要求較高,甚至涉及更底層的。
另兩廠對算法,數據結構的要求都是瞭解階段
如下爲面試中的一些知識點以及我的的一些補充,敲黑板啦啦啦
事件階段
通常的,事件分爲三個階段:捕獲階段、目標階段和冒泡階段。
捕獲階段(Capture Phase)
或這樣描述:
任何事件產生時,如點擊一個按鈕,將從最頂端的容器開始(通常是html的根節點)。瀏覽器會向下遍歷DOM樹直到找到觸發事件的元素,一旦瀏覽器找到該元素,事件流就進入事件目標階段
目標階段(Target Phase)
事件處理程序
DOM0 級事件處理程序
var btn5 = document.getElementById('btn5'); btn5.onclick=function(){ console.log(this.id);//btn5 };
基於 DOM0 的事件,對於同一個 dom 節點而言,只能註冊一個,後邊註冊的 同種事件 會覆蓋以前註冊的。
利用這個原理咱們能夠解除事件,btn5.onclick=null;
其中this就是綁定事件的那個元素;以這種方式添加的事件處理程序會在事件流的冒泡階段被處理;
DOM2事件經過 addEventListener
和 removeEventListener
管理
// addEventListener(eventName,handlers,boolean);removeEventListener() // 兩個方法都同樣接收三個參數,第一個是要處理的事件名,第二個是事件處理程序, // 第三個值爲false時表示在事件冒泡階段調用事件處理程序,通常建議在冒泡階段使用, // 特殊狀況纔在捕獲階段; // 注意:經過addEventListener()添加的事件處理程序只能用removeEventListener()來移除 // 而且移除時傳入的參數必須與添加時傳入的參數同樣;好比 var btn2 = document.getElementById('btn2'); var handlers = function () { console.log(this.id); }; btn2.addEventListener('click',handlers,false); btn2.removeEventListener('click',handlers.false);
ie 事件處理程序
//IE事件處理程序(IE和Opera支持) /* IE用了attachEvent(),detachEvent(),接收兩個參數,事件名稱和事件處理程序, * 經過attachEvent()添加的事件處理程序都會被添加到冒泡階段,因此平時爲了兼容更多的瀏覽器最好將事件添加到事件冒泡階段,IE8及之前只支持事件冒泡; */ var btn3 = document.getElementById('btn3'); var handlers2=function(){ console.log(this===window); // true,注意attachEvent()添加的事件處理程序運行在全局做用域; }; btn3.attachEvent('onclick',handlers2);
總結
DOM事件模型中的事件對象經常使用屬性:
IE事件模型中的事件對象經常使用屬性:
經過 readystate 屬性值判斷什麼時候方法下載完畢可用
readystate共有如下幾個值:注意上面5個值並不必定每一個事件都全包含,而且不必定是什麼順序。
Document.readyState 屬性loading / 加載
document 仍在加載。interactive / 互動
文檔已經完成加載,文檔已被解析,可是諸如圖像,樣式表和框架之類的子資源仍在加載。complete / 完成
T文檔和全部子資源已完成加載。狀態表示 load 事件即將被觸發。
當這個屬性的值變化時,document 對象上的readystatechange 事件將被觸發。
事件對象
IE
IE中事件對象是做爲全局對象window.event
存在的Firefox
Firefox中則是作爲句柄( handler )的第一個參數傳入通用
var evt = window.event || arguments[0];
事件監聽
Chrome、FireFox、Opera、Safari、IE9.0及其以上版本
js addEventListener(eventName,handler,boolean); removeEventListener() /* 兩個方法都同樣接收三個參數, * 事件名 * 事件處理程序 * boolean false時表示在事件冒泡階段調用事件處理程序,通常建議在冒泡階段使用 */
IE8.0及其如下版本
js element.attachEvent(type, handler); element.detachEvent(type, handler); /* element 要綁定事件的對象,html 節點 * type 事件類型 +'on' 如: "onclick, onmouseover" * listener 事件處理程序(只寫函數名,不帶括號) */
早期瀏覽器
obj['on' + type] = handler
阻止冒泡
event.stopPropagation
event.cancelBubble = true //IE
阻止默認事件
event.preventDefault()
event.returnValue = false //IE
// event(事件)工具集,來源:github.com/markyun markyun.Event = { // 頁面加載完成後 readyEvent: function (fn) { if (fn == null) { fn = document; } var oldonload = window.onload; if (typeof window.onload != 'function') { window.onload = fn; } else { window.onload = function () { oldonload(); fn(); }; } }, // 視能力分別使用dom0||dom2||IE方式 來綁定事件 // 參數: 操做的元素,事件名稱 ,事件處理程序 addEvent: function (element, type, handler) { if (element.addEventListener) { //事件類型、須要執行的函數、是否捕捉 element.addEventListener(type, handler, false); } else if (element.attachEvent) { element.attachEvent('on' + type, function () { handler.call(element); }); } else { element['on' + type] = handler; } }, // 移除事件 removeEvent: function (element, type, handler) { if (element.removeEnentListener) { element.removeEnentListener(type, handler, false); } else if (element.detachEvent) { element.detachEvent('on' + type, handler); } else { element['on' + type] = null; } }, // 阻止事件 (主要是事件冒泡,由於IE不支持事件捕獲) stopPropagation: function (ev) { if (ev.stopPropagation) { ev.stopPropagation(); } else { ev.cancelBubble = true; } }, // 取消事件的默認行爲 preventDefault: function (event) { if (event.preventDefault) { event.preventDefault(); } else { event.returnValue = false; } }, // 獲取事件目標 getTarget: function (event) { return event.target || event.srcElement; }, // 獲取event對象的引用,取到事件的全部信息,確保隨時能使用event; getEvent: function (e) { var ev = e || window.event; if (!ev) { var c = this.getEvent.caller; while (c) { ev = c.arguments[0]; if (ev && Event == ev.constructor) { break; } c = c.caller; } } return ev; } };
什麼叫跨域
方案
application/x-www-form-urlencoded
最多見的 POST 提交數據的方式了。瀏覽器的原生 form 表單,若是不設置 enctype 屬性,那麼最終就會以 application/x-www-form-urlencoded方式提交數據。
傳遞的key/val會通過URL轉碼,因此若是傳遞的參數存在中文或者特殊字符須要注意。
//例子 //b=曹,a=1 POST HTTP/1.1(CRLF) Host: www.example.com(CRLF) Content-Type: application/x-www-form-urlencoded(CRLF) Cache-Control: no-cache(CRLF) (CRLF) b=%E6%9B%B9&a=1(CRLF) //這裏b參數的值"曹"由於URL轉碼變成其餘的字符串了
multipart/form-data
常見的 POST 數據提交的方式。咱們使用表單上傳文件時,必須讓 form 的 enctyped 等於這個值
而且Http協議會使用boundary來分割上傳的參數
text/xml
<!-- 例子 --> POST http://www.example.com HTTP/1.1(CRLF) Content-Type: text/xml(CRLF) (CRLF) <?xml version="1.0"?> <resource> <id>123</id> <params> <name> <value>homeway</value> </name> <age> <value>22</value> </age> </params> </resource>
application/json
用來告訴服務端消息主體是序列化後的 JSON 字符串
//例子 //傳遞json POST HTTP/1.1(CRLF) Host: www.example.com(CRLF) Content-Type: application/json(CRLF) Cache-Control: no-cache(CRLF) Content-Length: 24(CRLF) (CRLF) { "a":1, "b":"hello" }
(CRLF)指 \r\n
參考: HTTP常見Content-Type比較
兩個序號和三個標誌位:
標誌位:共6個,即URG、ACK、PSH、RST、SYN、FIN等,具體含義以下:
須要注意的是:
爲何須要確認
因爲TCP鏈接時全雙工的,所以,每一個方向都必需要單獨進行關閉,這一原則是當一方完成數據發送任務後,發送一個FIN來終止這一方向的鏈接,收到一個FIN只是意味着這一方向上沒有數據流動了,即不會再收到數據了,可是在這個TCP鏈接上仍然可以發送數據,直到這一方向也發送了FIN
首先進行關閉的一方將執行主動關閉,而另外一方則執行被動關閉,上圖描述的便是如此。
爲何TIME_WAIT狀態須要通過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?
MSL是Maximum Segment Lifetime英文的縮寫,中文能夠譯爲「報文最大生存時間」,他是任何報文在網絡上存在的最長時間,超過這個時間報文將被丟棄,RFC 793中規定MSL爲2分鐘,實際應用中經常使用的是30秒,1分鐘和2分鐘等。2MSL即兩倍的MSL,TCP的TIME_WAIT狀態也稱爲2MSL等待狀態
爲何鏈接的時候是三次握手,關閉的時候倒是四次握手?
參考: TCP三次握手詳解及釋放鏈接過程
對於HTTP協議來講,加密的對象有如下兩個:
解決方案:
查明對手的證書
雖然HTTP不能確認通訊方,但SSL是能夠的。SSL不只提供了加密處理,還使用了"證書"的手段,可用於確認通訊方。證書是由值得信賴的第三方機構頒佈,可用於肯定證實服務器和客戶端是實際存在的。因此,只要能確認通訊方持有的證書,便可判斷通訊方的真實意圖。B、沒法判斷報文是否完整(報文可能已遭篡改)
HTTP協議沒法判斷報文是否被篡改,在請求或者響應發出後,在對方接收以前,即便請求或者響應遭到篡改是沒法得知的。防止篡改:
經常使用的,肯定報文完整性方法:MD五、SHA-1 等 散列值校驗方法,以及用來確認文件的數字簽名方法。可是,使用這些方法,也沒法百分百確保結果正確,由於MD5自己被修改的話,用戶是沒辦法意識到得。
POST 用戶安全登錄
在關係到用戶隱私的時候,要時刻遵循兩個原則:要想讓用戶信息安全,就必須對其進行加密,讓別人即使是拿到了安全信息,擺在眼前的也是一串亂碼,沒有半點用處
MD5是一種經常使用的加密方法,它是一種散列函數,利用MD5對用戶信息進行加密,會增長用戶信息安全性。
網上有關於MD5的第三方框架Category
利用這個第三方框架能夠實現對密碼進行MD5加密
+隨機亂碼字符防止被破解
對稱加密
非對稱加密
HTTPS簡介
HTTPS實際上是有兩部分組成:HTTP + SSL / TLS,也就是在HTTP上又加了一層處理加密信息的模塊。服務端和客戶端的信息傳輸都會經過TLS進行加密,因此傳輸的數據都是加密後的數據
SSL協議是經過非對稱密鑰機制保證雙方身份認證,並完成創建鏈接,在實際數據通訊時經過對稱密鑰機制保障數據安全性
服務器 用RSA生成公鑰和私鑰
把公鑰放在證書裏發送給客戶端,私鑰本身保存
客戶端首先向一個權威的服務器檢查證書的合法性,若是證書合法,客戶端產生一段隨機數,這個隨機數就做爲通訊的密鑰,咱們稱之爲對稱密鑰,用公鑰加密這段隨機數,而後發送到服務器
服務器用密鑰解密獲取對稱密鑰,而後,雙方就已對稱密鑰進行加密解密通訊了
HTTPS 在傳輸數據以前須要客戶端(瀏覽器)與服務端(網站)之間進行一次握手,在握手過程當中將確立雙方加密傳輸數據的密碼信息。TLS/SSL 協議不只僅是一套加密傳輸的協議,更是一件通過藝術家精心設計的藝術品,TLS/SSL 中使用了非對稱加密,對稱加密以及 HASH 算法。握手過程的具體描述以下:
瀏覽器得到網站證書以後瀏覽器要作如下工做:
a) 驗證證書的合法性(頒發證書的機構是否合法,證書中包含的網站地址是否與正在訪問的地址一致等),若是證書受信任,則瀏覽器欄裏面會顯示一個小鎖頭,不然會給出證書不受信的提示。
b) 若是證書受信任,或者是用戶接受了不受信的證書,瀏覽器會生成一串隨機數的密碼,並用證書中提供的公鑰加密。
c) 使用約定好的HASH算法計算握手消息,並使用生成的隨機數對消息進行加密,最後將以前生成的全部信息發送給網站。網站接收瀏覽器發來的數據以後要作如下的操做:
a) 使用本身的私鑰將信息解密取出密碼,使用密碼解密瀏覽器發來的握手消息,並驗證HASH是否與瀏覽器發來的一致。
b) 使用密碼加密一段握手消息,發送給瀏覽器。瀏覽器解密並計算握手消息的HASH,若是與服務端發來的HASH一致,此時握手過程結束,以後全部的通訊數據將由以前瀏覽器生成的隨機密碼並利用對稱加密算法進行加密。
參考:圖解HTTPS
重要的數據,要加密
好比用戶名密碼(若是簡單的md5,是能夠暴力破解),常見的是 md5(不可逆),aes(可逆),自由組合,還能夠加一些特殊字符
舉例:username = aes(username), pwd = MD5(pwd + username)
非重要數據,要簽名
簽名的目的是爲了防止篡改,好比 http://www.xxx.com/getnews?id=1
,獲取id爲1的新聞,若是不簽名那麼經過id=2,就能夠獲取2的內容等等。怎樣簽名呢?
一般使用sign,好比原連接請求的時候加一個 sign 參數,sign=md5(id=1),服務器接受到請求,驗證sign是否等於 md5(id=1) ,若是等於說明正常請求。
這會有個弊端,假如規則被發現,那麼就會被僞造,因此適當複雜一些,仍是可以提升安全性的。
登陸態怎麼作
http是無狀態的,也就是服務器無法本身判斷兩個請求是否有聯繫,那麼登陸以後,之後的接口怎麼斷定是否登陸呢
簡單的作法,在數據庫中存一個token字段(名字隨意),當用戶調用登錄接口成功的時候,就將該字段設一個值,(好比aes(過時時間)),同時返回給前端,之後每次前端請求帶上該值,服務器首先校驗是否過時,其次校驗是否正確,不經過就讓其登錄。(redis 作這個很方便哦,key有過時時間)
一種特殊的存儲過程,存儲過程通常經過定義的名字直接調用,而觸發器是經過增、刪、改進行觸發執行的。會在事件發生時自動強制執行
觸發器是一種特殊的存儲過程,主要是經過事件來觸發而被執行的。它能夠強化約束,來維護數據的完整性和一致性,能夠跟蹤數據庫內的操做從而不容許未經許可的更新和變化。能夠聯級運算。如,某表上的觸發器上包含對另外一個表的數據操做,而該操做又會致使該表觸發器被觸發。
事務
就是被綁定在一塊兒做爲一個邏輯工做單元的SQL語句分組,若是任何一個語句操做失敗那麼整個操做就被失敗,之後操做就會回滾到操做前狀態,或者是上有個節點。
爲了確保要麼執行,要麼不執行,就能夠使用事務。要將一組語句做爲事務考慮,就須要經過ACID測試,即原子性,一致性,隔離性和持久性。鎖:
在全部的DBMS中,鎖是實現事務的關鍵,鎖能夠保證事務的完整性和併發性。與現實生活中鎖同樣,它能夠使某些數據的擁有者,在某段時間內不能使用某些數據或數據結構。固然鎖還分級別的。共享鎖(只讀不寫)、排他鎖(可讀可寫)
設計原則
單體是一個用來劃分命名空間並將一批相關的屬性和方法組織在一塊兒的對象,若是他能夠被實例化,那麼他只能被實例化一次
// 對象字面量 var Singleton = { attr1: 1, attr2: 2, method1: function(){ return this.attr1; }, method2: function(){ return this.attr2; } }; // 上面的全部成員變量都是經過Singleton來訪問的,可是它並非單體模式; // 由於單體模式還有一個更重要的特色,就是能夠僅被實例化一次,上面的只是不能被實例化的一個類,所以不是單體模式;對象字面量是用來建立單體模式的方法之一; /*要實現一個單體模式的話,咱們無非就是使用一個變量來標識該類是否被實例化 若是未被實例化的話,那麼咱們能夠實例化一次,不然的話,直接返回已經被實例化的對象 */ // 單體模式 var Singleton = function(name){ this.name = name; this.instance = null; }; Singleton.prototype.getName = function(){ return this.name; } // 獲取實例對象 function getInstance(name) { if(!this.instance) { this.instance = new Singleton(name); } return this.instance; } // 測試單體模式的實例 var a = getInstance("aa"); var b = getInstance("bb"); console.log(a === b) // true console.log(a.getName()) // aa console.log(b.getName()) // aa
應用案例
彈窗
傳統建立:好比我點擊一個元素須要建立一個div,我點擊第二個元素又會建立一次div,咱們頻繁的點擊某某元素,他們會頻繁的建立div的元素,雖然當咱們點擊關閉的時候能夠移除彈出代碼,可是呢咱們頻繁的建立和刪除並很差,特別對於性能會有很大的影響,對DOM頻繁的操做會引發重繪等,從而影響性能;所以這是很是很差的習慣;咱們如今能夠使用單體模式來實現彈窗效果,咱們只實例化一次就能夠
編寫通用的單體模式
咱們使用一個參數fn傳遞進去,若是有result這個實例的話,直接返回,不然的話,當前的getInstance函數調用fn這個函數,是this指針指向與這個fn這個函數;以後返回被保存在result裏面;如今咱們能夠傳遞一個函數進去,無論他是建立div也好,仍是建立iframe也好,總之若是是這種的話,均可以使用getInstance來獲取他們的實例對象;
// 建立div var createWindow = function(){ var div = document.createElement("div"); div.innerHTML = "我是彈窗內容"; div.style.display = 'none'; document.body.appendChild(div); return div; }; // 建立iframe var createIframe = function(){ var iframe = document.createElement("iframe"); document.body.appendChild(iframe); return iframe; }; // 獲取實例的封裝代碼 var getInstance = function(fn) { var result; return function(){ return result || (result = fn.call(this,arguments)); } }; // 測試建立div var createSingleDiv = getInstance(createWindow); document.getElementById("Id").onclick = function(){ var win = createSingleDiv(); win.style.display = "block"; }; // 測試建立iframe var createSingleIframe = getInstance(createIframe); document.getElementById("Id").onclick = function(){ var win = createSingleIframe(); win.src = "http://cnblogs.com"; };
客戶類和工廠類分開。消費者任什麼時候候須要某種產品,只需向工廠請求便可。消費者無須修改就能夠接納新產品。
工廠模式是爲了解決多個相似對象聲明的問題;也就是爲了解決實列化對象產生重複的問題。
function CreatePerson(name,age,sex) { var obj = new Object(); obj.name = name; obj.age = age; obj.sex = sex; obj.sayName = function(){ return this.name; } return obj; } var p1 = new CreatePerson("longen",'28','男'); var p2 = new CreatePerson("tugenhua",'27','女');
模塊模式的思路是爲單體模式添加私有變量和私有方法可以減小全局變量的使用
prototype + constructor
裝飾者(decorator)模式可以在不改變對象自身的基礎上,在程序運行期間給對像動態的添加職責(方法或屬性)。
與繼承相比,裝飾者是一種更輕便靈活的作法。
能夠動態的給某個對象添加額外的職責,而不會影響從這個類中派生的其它對象。
// ES7裝飾器 function isAnimal(target) { target.isAnimal = true return target } // 裝飾器 @isAnimal class Cat { // ... } console.log(Cat.isAnimal) // true // 做用於類屬性的裝飾器: function readonly(target, name, descriptor) { discriptor.writable = false return discriptor } class Cat { @readonly say() { console.log("meow ~") } } var kitty = new Cat() kitty.say = function() { console.log("woof !") } kitty.say() // meow ~
發佈---訂閱模式又叫觀察者模式,它定義了對象間的一種一對多的關係,讓多個觀察者對象同時監聽某一個主題對象,當一個對象發生改變時,全部依賴於它的對象都將獲得通知
發佈訂閱模式的流程以下:
【實現事件模型】
即寫一個類或是一個模塊,有兩個函數,一個bind一個trigger,分別實現綁定事件和觸發事件,核心需求就是能夠對某一個事件名稱綁定多個事件響應函數,而後觸發這個事件名稱時,依次按綁定順序觸發相應的響應函數。
大體實現思路就是建立一個類或是匿名函數,在bind和trigger函數外層做用域建立一個字典對象,用於存儲註冊的事件及響應函數列表,bind時,若是字典沒有則建立一個,key是事件名稱,value是數組,裏面放着當前註冊的響應函數,若是字段中有,那麼就直接push到數組便可。trigger時調出來依次觸發事件響應函數便可
var Event = (function(){ var list = {}, listen, trigger, remove; listen = function(key,fn){ if(!list[key]) { list[key] = []; } list[key].push(fn); }; trigger = function(){ var key = Array.prototype.shift.call(arguments), fns = list[key]; if(!fns || fns.length === 0) { return false; } for(var i = 0, fn; fn = fns[i++];) { fn.apply(this,arguments); } }; remove = function(key,fn){ var fns = list[key]; if(!fns) { return false; } if(!fn) { fns && (fns.length = 0); }else { for(var i = fns.length - 1; i >= 0; i--){ var _fn = fns[i]; if(_fn === fn) { fns.splice(i,1); } } } }; return { listen: listen, trigger: trigger, remove: remove } })(); // 測試代碼以下: Event.listen("color",function(size) { console.log("尺碼爲:"+size); // 打印出尺碼爲42 }); Event.trigger("color",42);
代理是一個對象,它能夠用來控制對本體對象的訪問,它與本體對象實現了一樣的接口,代理對象會把全部的調用方法傳遞給本體對象的
本地對象注重的去執行頁面上的代碼,代理則控制本地對象什麼時候被實例化,什麼時候被使用
優勢:
// 先申明一個奶茶妹對象 var TeaAndMilkGirl = function(name) { this.name = name; }; // 這是京東ceo先生 var Ceo = function(girl) { this.girl = girl; // 送結婚禮物 給奶茶妹 this.sendMarriageRing = function(ring) { console.log("Hi " + this.girl.name + ", ceo送你一個禮物:" + ring); } }; // 京東ceo的經紀人是代理,來代替送 var ProxyObj = function(girl){ this.girl = girl; // 經紀人代理送禮物給奶茶妹 this.sendGift = function(gift) { // 代理模式負責本體對象實例化 (new Ceo(this.girl)).sendMarriageRing(gift); } }; // 初始化 var proxy = new ProxyObj(new TeaAndMilkGirl("奶茶妹")); proxy.sendGift("結婚戒"); // Hi 奶茶妹, ceo送你一個禮物:結婚戒
理解使用虛擬代理實現圖片的預加載
在網頁開發中,圖片的預加載是一種比較經常使用的技術,若是直接給img標籤節點設置src屬性的話,若是圖片比較大的話,或者網速相對比較慢的話,那麼在圖片未加載完以前,圖片會有一段時間是空白的場景,這樣對於用戶體驗來說並很差,那麼這個時候咱們能夠在圖片未加載完以前咱們能夠使用一個loading加載圖片來做爲一個佔位符,來提示用戶該圖片正在加載,等圖片加載完後咱們能夠對該圖片直接進行賦值便可;下面咱們先不用代理模式來實現圖片的預加載的狀況下代碼以下:
// 不使用代理的預加載圖片函數以下 var myImage = (function(){ var imgNode = document.createElement("img"); document.body.appendChild(imgNode); var img = new Image(); img.onload = function(){ imgNode.src = this.src; }; return { setSrc: function(src) { imgNode.src = "http://img.lanrentuku.com/img/allimg/1212/5-121204193Q9-50.gif"; img.src = src; } } })(); // 調用方式 myImage.setSrc("https://img.alicdn.com/tps/i4/TB1b_neLXXXXXcoXFXXc8PZ9XXX-130-200.png");
//利用代理模式來編寫預加載圖片 var myImage = (function(){ var imgNode = document.createElement("img"); document.body.appendChild(imgNode); return { setSrc: function(src) { imgNode.src = src; } } })(); // 代理模式 var ProxyImage = (function(){ var img = new Image(); img.onload = function(){ myImage.setSrc(this.src); }; return { setSrc: function(src) { myImage.setSrc("http://img.lanrentuku.com/img/allimg/1212/5-121204193Q9-50.gif"); img.src = src; } } })(); // 調用方式 ProxyImage.setSrc("https://img.alicdn.com/tps/i4/TB1b_neLXXXXXcoXFXXc8PZ9XXX-130-200.png");
這種懶加載方法不用代理模式也是能夠實現的,只是用代理模式。咱們可讓 myImage 只作一件事,只負責將實際圖片加入到頁面中,而loading圖片交給ProxyImage去作。從而下降代碼的耦合度。由於當我不想用loading的時候,能夠直接調用myImage 方法。也便是說假如我門不須要代理對象的話,直接能夠換成本體對象調用該方法便可
對比
優勢
js 實現兩個超大數相加
基礎:
2^63 - 1
Math.pow(2, 53) - 1
js //js 最大和最小安全值 Number.MAX_SAFE_INTEGER //9007199254740991 Number.MIN_SAFE_INTEGER //-9007199254740991
var largeNumberAdd = function(num1, num2) { var arr1 = num1.split(''), arr2 = num2.split(''), tem = '', num3 = 0, result = [] var longDiff = arr1.length - arr2.length if (longDiff > 0) { for (let i = 0; i < longDiff; i++) { arr2.unshift('0') } }else if (longDiff < 0) { for (let i = 0; i < Math.abs(longDiff); i++) { arr1.unshift('0') } } for (let i = arr1.length - 1; i >= 0; i--) { tem = parseInt(arr1[i]) + parseInt(arr2[i]) + num3 // check if tem > 10 if (tem >= 10) { num3 = 1 result.push((tem + '')[1]) }else { num3 = 0 result.push(tem) } } return result.reverse().join('') } // console.log(largeNumberAdd('11111','11111')) console.log(largeNumberAdd('00000000000000000000011111','333331999')) console.log(11111+333331999) // console.log(largeNumberAdd('3333333333333333333333333333333311111111111111111111111111111111111111','333333333333333331111111111111111111111111111166666666666666'))
js 每秒鐘的計算量
js 如何解析後臺返回的超大數據
前提:
js 用浮點數表示全部64位數字,全部達到 2^53 的能夠被精確表示,更大的數字都會被裁剪,——如何表示64位數字
雖然js 可以解析進制數字表示64位數字,但底層的數字表示不支持 64 位
在瀏覽器中執行如下代碼
<html> <head> <script language="javascript"> function showPrecisionLimits() { document.getElementById("r50").innerHTML = 0x0004000000000001 - 0x0004000000000000; document.getElementById("r51").innerHTML = 0x0008000000000001 - 0x0008000000000000; document.getElementById("r52").innerHTML = 0x0010000000000001 - 0x0010000000000000; document.getElementById("r53").innerHTML = 0x0020000000000001 - 0x0020000000000000; document.getElementById("r54").innerHTML = 0x0040000000000001 - 0x0040000000000000; } </script> </head> <body onload="showPrecisionLimits()"> <p>(2^50+1) - (2^50) = <span id="r50"></span></p> <p>(2^51+1) - (2^51) = <span id="r51"></span></p> <p>(2^52+1) - (2^52) = <span id="r52"></span></p> <p>(2^53+1) - (2^53) = <span id="r53"></span></p> <p>(2^54+1) - (2^54) = <span id="r54"></span></p> </body> </html>
在Firefox,Chrome和IE瀏覽器中,能夠看到,若是可以存儲64位數字,則如下減法結果皆爲1。而結果相反,能夠看到2 ^ 53 + 1和2 ^ 53 間的差別丟失
js (2 ^ 50 + 1) - (2 ^ 50)= 1 (2 ^ 51 + 1) - (2 ^ 51)= 1 (2 ^ 52 + 1) - (2 ^ 52)= 1 (2 ^ 53 + 1) - (2 ^ 53)= 0 (2 ^ 54 + 1) - (2 ^ 54)= 0
位運算
所以,咱們能夠選擇用兩個 32 位的數字表示 64 位整數,而後進行按位與
var a = [ 0x0000ffff, 0xffff0000 ]; var b = [ 0x00ffff00, 0x00ffff00 ]; var c = [ a[0] & b[0], a[1] & b[1] ]; document.body.innerHTML = c[0].toString(16) + ":" + c[1].toString(16); //結果 ff00:ff0000
前端網絡安全的實現
如何檢測惡意腳本
如何屏蔽
一面
二面
IP地址讓網絡上的兩個節點之間能夠創建點對點的鏈接
端口號則爲端到端的鏈接提供了可能 (程序間通信的接口)
IP協議是由TCP、UDP、ARP、ICMP等一系列子協議組成的。其中
TCP和UDP協議
主要用來作傳輸數據使用的
在TCP和UDP協議中,都有端口號的概念存在
端口號的做用
主要是區分服務類別和在同一時間進行多個會話服務類別
舉例來講,有主機A須要對外提供FTP和WWW兩種服務,若是沒有端口號存在的話,這兩種服務是沒法區分的。
實際上,當網絡上某主機B須要訪問A的FTP服務時,就要指定目的端口號爲21;根據一個給定的元素生成一個css 選擇器,函數名爲genCssSelector ,
點擊某元素彈出該元素及其父元素,相似 querySelector
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>Document</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <script language="javaScript"> // your code here var genCssSelector = function (e) { e = e || window.event var tar = e.target || e.srcElement var objArr = [] while (tar) { if (tar.id) { objArr.push('#' + tar.id) console.log('id') return objArr.reverse().join(' ') // 考慮 id 的惟一性,若是有 id,則中止查找 }else if (tar.className) { objArr.push('.' + tar.className.split(' ')[0]) // 考慮若是有多個 class }else { objArr.push(tar.nodeName.toLowerCase()) } tar = tar.parentNode } objArr.pop() return objArr.reverse().join(' ') } document.addEventListener('click', function (e) { //點擊li時,返回:html body #page .content.main .refer ul li console.log(genCssSelector(e)); }) </script> </head> <body> <div id="page"> <div class="main" id="main"> <div class="reference refer"> <ul> <li></li> <li></li> 23333 </ul> </div> </div> </div> </body> </html>
JS獲取DOM元素的方法(8種)
getElementById
getElementsByName
getElementsByTagName
getElementsByClassName
document.documentElement
document.body
querySelector
querySelectorAll
獲取一組元素
獲取子元素
dom.childNodes
返回一個nodeList(元素的全部子元素)
nodeValue屬性
得到和改變文本節點的值獲取父、兄
parentNode
nextSibling
previousSbiling
建立元素
createDocumentFragment
createElement
createTextNode
建立一個文本節點
增刪改元素
appendChild
removeChild
replaceChild
insertBefore
直接調用eval
var json = '{"a":"1", "b":2}'; var obj = eval("(" + json + ")"); // obj 就是 json 反序列化以後獲得的對象
原理
JSON 脫胎於 JS,同時也是 JS 的子集,因此可以直接交給 eval 運行
加上圓括號的目的是迫使eval函數在處理JavaScript代碼的時候強制將括號內的表達式(expression)轉化爲對象,而不是做爲語句(statement)來執行
例如對象字面量{},如若不加外層的括號,那麼eval會將大括號識別爲JavaScript代碼塊的開始和結束標記,那麼{}將會被認爲是執行了一句空語句
缺點
XSS 漏洞
如:參數 json 並不是真正的 JSON 數據,而是可執行的 JS 代碼對參數 json 作校驗,只有真正符合 JSON 格式,才能調用 eval
```js
// 1. 用 4 個正則表達式分爲兩個階段解決(包容ie 和safari 的regexp 引擎)
// 2. 將 json 反斜槓替換爲 '@' (non-json字符)
// 3. 用 ']' 替換全部簡單標記
// 4. 刪除全部跟隨冒號,逗號或文本開始的方括號
// 5. 若是隻剩下 '] , { }' 則是安全的
var rx_one = /^[],:{}\s]$/;
var rx_two = /\(?:["\/bfnrt]|u[0-9a-fA-F]{4})/g;
var rx_three = /"[^"\\\n\r]"|true|false|null|-?\d+(?:.\d)?(?:[eE][+-]?\d+)?/g;
var rx_four = /(?:^|:|,)(?:\s[)+/g;
if (
rx_one.test(
json
.replace(rx_two, "@")
.replace(rx_three, "]")
.replace(rx_four, "")
)
) {
var obj = eval("(" +json + ")");
}
```
第一種 eval 的方法,至關於一古腦兒把 JSON 字符串塞進去。
其實咱們還能夠手動逐個字符地掃描,而後進行判斷,這就是第二種方法:遞歸
// 所謂遞歸,就是重複調用value 函數 value = function () { // Parse a JSON value. It could be an object, an array, a string, a number, // or a word. white(); // 根據當前字符是什麼,咱們便能推導出後面應該接的是什麼類型 switch (ch) { case "{": return object(); case "[": return array(); case "\"": return string(); case "-": return number(); default: return (ch >= "0" && ch <= "9") ? number() : word(); } }; // 調用核心的 next 函數,逐個讀取字符 var next = function (c) { // If a c parameter is provided, verify that it matches the current character. if (c && c !== ch) { error("Expected '" + c + "' instead of '" + ch + "'"); } // Get the next character. When there are no more characters, // return the empty string. ch = text.charAt(at); at += 1; return ch; };
false true null
進行匹配,不匹配返回錯誤以 {"a":"1", "b":2}
爲例
程序大體邏輯是:啓動 → 首次調用 value() → 發現是 { → 原來是對象,走 object() → 經過 string() 獲得 key 值爲 "a" → 讀取到冒號,哦,後面多是對象、數組、布爾值等等,具體是什麼,還得再次調用 value() 才知道 → ……
xml 解析
close tag
使用一個 nodeStack 棧,在 opentag 時推入節點,close tag 時檢查當前節點是否和棧尾節點是否匹配,匹配則推出末尾節點comment
setState 不保證同步
setState()
不會馬上改變 this.state
,而是建立一個即將處理的 state 轉變。在調用該方法以後訪問 this.state
可能會返回現有的值。使用回調函數
setState 方法接收一個 function 做爲回調函數。這個回掉函數會在 setState 完成之後直接調用,這樣就能夠獲取最新的 state
js this.setState({ selection: value }, this.fireOnSelect)
setTimeout
在 setState 使用 setTimeout 來讓 setState 先完成之後再執行裏面內容
js this.setState({ selection: value }); setTimeout(this.fireOnSelect, 0);
shouldComponentUpdate
解決
setState()
將老是觸發一次重繪,除非在 shouldComponentUpdate()
中實現了條件渲染邏輯和渲染無關的狀態儘可能不要放在 state 中來管理
一般 state 中只來管理和渲染有關的狀態 ,從而保證 setState 改變的狀態都是和渲染有關的狀態。這樣子就能夠避免沒必要要的重複渲染。其餘和渲染無關的狀態,能夠直接以屬性的形式保存在組件中,在須要的時候調用和改變,不會形成渲染。
不能頗有效的管理全部的組件狀態
一面
jsonp cors
css
js & jq
vue
操做系統
計算機網絡
數據結構
二面
如何作一個 css 選擇器
見本文 阿里-在線編程給定一組dom 節點,和一個css樣式表,找出不含有樣式的dom
面試官很耐心的解釋了,仍是沒聽明白題目居中問題
沒有詳細問,我分了兩個方面分別回答get & post
回答了大多數應聘者的 「標準答案」, 但經面試官指點,頓悟,大概這就叫高手吧
三面
數字的存儲
無符號與有符號二進制存儲
理解有符號數和無符號數負數閒聊了一下,關於保研等等,總共 四十分鐘
原理:增大父框的實際寬度後,使用CSS3屬性box-sizing進行佈局的輔助。
用法:先將父框設置爲 margin-left: -*px
,再設置子框 float: left、width: 25%、padding-left、box-sizing: border-box
.parent{ margin-left: -20px; } .column{ float: left; width: 25%; padding-left: 20px; box-sizing: border-box; /*包含padding區域 w+g*/ }
原理:經過增長一個父框的修正框,增大其寬度,並將父框轉換爲 table,將子框轉換爲 tabel-cell 進行佈局。
用法:先將父框的修正框設置爲 margin-left: -*px
,再設置父框 display: table、width:100%、table-layout: fixed
,設置子框 display: table-cell、padding-left
.parent-fix{ margin-left: -20px; } .parent{ display: table; width:100%; table-layout: fixed; } .column{ display: table-cell; padding-left: 20px; }
原理:經過設置CSS3佈局利器flex中的flex屬性以達到等分佈局。
用法:將父框設置爲display: flex,再設置子框flex: 1,最後設置子框與子框的間距margin-left。
// 直接獲取---須要高版本瀏覽器支持 document.querySelectorAll("div.aa") // 相似屬性選擇器的寫法 document.querySelectorAll("div[class='aa']") // 補充一下還能夠not選擇器 document.querySelectorAll(".aa:not(ul)") document.getElementsByClassName('cls') // jq $('.className')
js 單線程:
用途決定,操做 DOM
任務隊列
排隊緣由:計算量大的同步執行,IO設備(輸入輸出設備)很慢(好比Ajax操做從網絡讀取數據)異步。
異步任務指的是,不進入主線程、而進入"任務隊列"(task queue)的任務,只有"任務隊列"通知主線程,某個異步任務能夠執行了,該任務纔會進入主線程執行
"任務隊列"中的事件,除了IO設備的事件之外,還包括一些用戶產生的事件(好比鼠標點擊、頁面滾動等等)。只要指定過回調函數,這些事件發生時就會進入"任務隊列",等待主線程讀取。
全部同步任務都在主線程上執行,造成一個執行棧(execution context stack)。
主線程以外,還存在一個"任務隊列"(task queue)。只要異步任務有了運行結果,就在"任務隊列"之中放置一個事件。
一旦"執行棧"中的全部同步任務執行完畢,系統就會讀取"任務隊列",看看裏面有哪些事件。那些對應的異步任務,因而結束等待狀態,進入執行棧,開始執行。
主線程不斷重複上面的第三步。
只要主線程空了,就去檢查異步的任務隊列,若是異步事件觸發,則將其加到主線程的執行棧
深刻了解定時器
零延遲 setTimeout(func, 0)
調用setTimeout()以後,該方法會返回一直數值ID,表示超時調用。這個超時調用ID是計劃執行代碼的惟一標識符,能夠經過它來取消超時調用
超時調用的代碼都是在全局做用域中執行的,所以函數中this的值在非嚴格模式下指向window對象,嚴格模式下是undefined。
Event Loop
異步與event loop沒有太直接的關係,準確的來說event loop 只是實現異步的一種機制
主任務 ——> micro task ——> 渲染視圖 ——> macro task
主線程從"任務隊列"中讀取事件,這個過程是循環不斷的,因此整個的這種運行機制又稱爲Event Loop(事件循環)
Javascript 中的事件循環是以任務爲單位的,將不少個待執行的任務串聯在一塊兒就造成了隊列 Task Queue,不少的隊列前後按順序執行任務就造成了 Event Loop
一個事件循環(EventLoop)中會有一個正在執行的任務(Task),而這個任務就是從 macrotask 隊列中來的。
當這個 macrotask 執行結束後,全部可用的 microtask 將會在同一個事件循環中執行
當這些 microtask 執行結束後還能繼續添加 microtask 一直到真個 microtask 隊列執行結束。
一個事件循環(event loop)會有一個或多個任務隊列(task queue)
task queue 就是 macrotask queue當一個 task 被放入隊列 queue(macro或micro) 那這個 task 就能夠被當即執行了
Micro Task
當咱們想以同步的方式來處理異步任務時候就用 microtask(好比咱們須要直接在某段代碼後就去執行某個任務,就像Promise同樣)
Macro Task
任務隊列中,在每一次事件循環中,從 macrotask 隊列開始執行,macrotask只會提取一個執行,而microtask會一直提取,直到microsoft隊列爲空爲止。
也就是說若是某個microtask任務被推入到執行中,那麼當主線程任務執行完成後,會循環調用該隊列任務中的下一個任務來執行,直到該任務隊列到最後一個任務爲止。而事件循環每次只會入棧一個macrotask,主線程執行完成該任務後又會檢查microtasks 隊列並完成裏面的全部任務後再執行macrotask的任務。
執行過程以下:
爲啥要用 microtask?
// 驗證 (function () { const $test = document.getElementById('test') let counter = 0 function func1() { $test.innerText = ++counter alert('func1') } function func2() { $test.innerText = ++counter alert('func2') } function func3() { $test.innerText = ++counter alert('func3') } function func4() { $test.innerText = ++counter alert('func4') } (function () { // main task func1() // macro task setTimeout(() => { func2() // micro task Promise.resolve().then(func4) }, 0); // macro task setTimeout(func1, 0); // micro task Promise.resolve().then(func3) // main task func4() })() // alert func1 // alert func4 // alert func3 // UI update ---> counter = 3 // alert func2 // alert func4 // UI update ---> counter = 5 // alert func1 // UI update ---> counter = 6 })()
fetch
返回一個Promise對象, 根據 Promise Api 的特性, fetch能夠方便地使用then方法將各個處理邏輯串起來
mode
// fetch能夠設置不一樣的模式使得請求有效 fetch(url, {mode: 'cors'});
Jsonp
SSE(server-sent-events)
單向通道(服務器 -> 瀏覽器)
ES 6之前:
ES 6:
ES 7:
回調函數
通常是須要在一個耗時操做以後執行某個操做時能夠使用回調函數
問題:
在回調函數以外沒法捕獲到回調函數中的異常
var fs = require('fs'); try{ fs.readFile('not_exist_file', 'utf8', function(err, data){ console.log(data); }); } catch(e){ console.log("error caught: " + e); }
嘗試讀取一個不存在的文件,這固然會引起異常,可是最外層的try/catch語句卻沒法捕獲這個異常。這是異步代碼的執行機制致使的
爲何異步代碼回調函數中的異常沒法被最外層的try/catch語句捕獲?
異步調用通常分爲兩個階段,提交請求和處理結果,這兩個階段之間有事件循環的調用,它們屬於兩個不一樣的事件循環(tick),彼此沒有關聯。
異步調用通常以傳入callback的方式來指定異步操做完成後要執行的動做。而異步調用本體和callback屬於不一樣的事件循環。
try/catch語句只能捕獲當次事件循環的異常,對callback無能爲力。
事件監聽(訂閱-發佈)
典型的邏輯分離方式,對代碼解耦頗有用處
把不變的部分封裝在組件內部,供外部調用,須要自定義的部分暴露在外部處理。
從某種意義上說,事件的設計就是組件的接口設計。
//發佈和訂閱事件 var events = require('events'); var emitter = new events.EventEmitter(); emitter.on('event1', function(message){ console.log(message); }); emitter.emit('event1', "message for you");
Promise 對象
用同步操做的流程寫法來表達異步操做,避免了層層嵌套的異步回調
Promise.prototype.then()
//原生Primose順序嵌套回調示例 var fs = require('fs') var read = function (filename){ var promise = new Promise(function(resolve, reject){ fs.readFile(filename, 'utf8', function(err, data){ if (err){ reject(err); } resolve(data); }) }); return promise; } read('./text1.txt') .then(function(data){ console.log(data); return read('./text2.txt'); // 返回了一個新的Promise實例 }) .then(function(data){ console.log(data); });Promise構造函數的參數是一個函數,在這個函數中咱們寫異步操做的代碼
調用read函數時,實際上返回的是一個Promise對象,經過在這個Promise對象上調用then方法並傳入resolve方法和reject方法來指定異步操做成功和失敗後的操做。
Promise.prototype.catch()
用於指定發生錯誤時的回調函數
read('./text1.txt') .then(function(data){ console.log(data); return read('not_exist_file'); }) .then(function(data){ console.log(data); }) .catch(function(err){ console.log("error caught: " + err); }) .then(function(data){ console.log("completed"); })
使用Promise對象的catch方法能夠捕獲異步調用鏈中callback的異常
Promise對象的catch方法返回的也是一個Promise對象,所以,在catch方法後還能夠繼續寫異步調用方法
Promise.all()
var p = Promise.all([p1,p2,p3]);
只要p一、p二、p3之中有一個被rejected,p的狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調函數。
```js
var promises = [1, 2].map(function(fileno){
return read('./text' + fileno + '.txt');
});
Promise.race()
var p = Promise.race([p1,p2,p3]);
Promise.resolve()
var p = Promise.resolve('Hello'); p.then(function (s){ console.log(s) });
Promise.reject()
Promise.reject
方法的參數reason,會被傳遞給實例的回調函數。var p = Promise.reject('出錯了'); p.then(null, function (s){ console.log(s) });
整個Generator函數就是一個封裝的異步任務,或者說是異步任務的容器。異步操做須要暫停的地方,都用yield語句註明。
function* gen(x){ var y = yield x + 2; return y; } var g = gen(1); var r1 = g.next(); // { value: 3, done: false } console.log(r1); var r2 = g.next() // { value: undefined, done: true } console.log(r2);
**Generator函數的函數名前面有一個"*"**
ES 7中的async和await
區別:
當我滿心充滿着自信和喜悅時,彷彿看到了面試官眉頭一皺,So?
aspect | GET | POST |
---|---|---|
瀏覽器回退 | 無影響 | 回退會再次提交請求 |
地址標記 | 產生的 URL 地址能夠被 Bookmark | 提交地址不被標記 |
cache | 該請求會被瀏覽器主動 cache | 該請求不會被緩存 |
編碼 | 只能進行url編碼 | 支持多種編碼方式 |
參數保留 | 請求參數會被完整保留在瀏覽器歷史記錄裏 | POST中的參數不會被保留 |
長度限制 | 有(瀏覽器限制,IE-2083個字符) | 無(限制做用的是服務器的處理程序的處理能力) |
參數類型 | 只接受ASCII字符 | 沒有限制 |
參數傳遞 | 經過URL傳遞 | 放在Request body中 |
字符 | 表示 | 補充 |
---|---|---|
二進制 | 0/1 | 八個二進制位能夠組合出256種狀態,這被稱爲一個字節(byte) |
八進制 | 0~7 | |
十進制 | 0~9 | |
十六禁止 | 0~9 A~F |
編碼 | 特徵 | 補充 |
---|---|---|
二十一進制碼(BCD碼) | 保留了十進制數的權,而數字則用二進制數碼0和1的組合來表示 | 在須要高精度的計算中BCD編碼比較經常使用(瞭解) |
ASCII碼 | 美國信息交換標準委員會制定的7位字符編碼,用7位二進制碼錶示一個字符,第8 位用於肯定附加的128 個特殊符號字符、外來語字母和圖形符號 | |
GB2312 | 爲了保存非英文,使用127號以後的空位保存新的字母(一個8位的字節能夠組合256種狀態,ASCII只編到127號),一直編到最後一位255,並且不一樣國家表示的符號也不同,也能夠說GB2312是對ASCII的中文擴展 | 不夠用,後來只要求只要第一個字節是大於127就固定表示這是一個漢字的開始,稱之爲GBK編碼 |
GB18030 / DBCS | 編碼中又增長了幾千個新的少數民族的字,GBK擴展成了GB18030統稱它們叫作DBCS | |
Unicode | ISO(國際標準化組織)廢棄了全部地區性編碼方案,作了一套包括了地球上全部文化、符號以及字母的編碼;ISO規定:必須用兩個字節,16位來統一表示全部的字符,不管是半角的英文字母,仍是全角的漢字,它們都是統一的一個字符!也就是兩個字節 | |
UTF-8 | UTF-8 互聯網上使用最廣的一種 Unicode 的實現方式,每次以8個位爲單位傳輸數據;UTF-16就是每次 16 個位 | UTF-8 最大的一個特色,就是它是一種變長的編碼方式,Unicode一箇中文字符佔 2 個字節,而UTF-8一箇中文字符佔3個字節,UTF-8是Unicode的實現方式之一 |
進制轉換
------十進制轉其餘------- var a = 24; a.toString(2);//11000 a.toString(8);//30 a.toString(16);//18 ------其餘轉十進制------- var b=11000,c=30,d=18; console.log(parseInt(b, 2)); // 二進制轉十進制 console.log(parseInt(c, 8)); // 八進制轉十進制 console.log(parseInt(d, 16));// 十六進制轉十進制
前端編碼問題
在使用nodeJS編寫前端工具時,對文本文件的操做比較多,這就涉及到了文件的編碼問題,經常使用的文本編碼有UTF8和GBK兩種,而且UTF8文件還可能帶有BOM(字節順序標記),在讀取不一樣編碼的文本文件時,須要將文件內容轉換爲JS使用的UTF8編碼字符串後才能正常處理
移除 BOM
BOM用於標記一個文本文件使用Unicode編碼,其自己是一個Unicode字符("\uFEFF"),位於文本文件頭部以告訴其餘編輯器以utf8來顯示字符
可是在網頁上並不須要添加BOM頭識別,由於網頁上能夠使用 head頭 指定charset=utf8告訴瀏覽器用utf8來解釋.可是你用window自動的編輯器,編輯,而後有顯示在網頁上這樣就會顯示出0xEF 0xBB 0xBF這3個字符。這樣網頁上就須要去除0xEF 0xBB 0xBFjs 去除
// 能夠經過文件頭的幾個字節來判斷文件是否包含BOM以及使用哪一種Unicode,若是讀取文件的時候不去掉BOM // 假如咱們將幾個JS文件合併成一個,若是文件中含有BOM字符,就會致使語法錯誤 // 因此咱們用 nodeJS讀取文件是通常先去掉BOM var bin = fs.readFileSync(pathname);//經過node 中fs模塊同步讀文件內容 //判斷文件頭的字節 if (bin[0] === 0xEF && bin[1] === 0xBB && bin[2] === 0xBF) { bin = bin.slice(3); }
GBK 轉 UTF8
NodeJS支持在讀取文本文件時,或者在Buffer轉換爲字符串時指定文本編碼,但GBK編碼不在NodeJS自身支持範圍內,通常咱們藉助iconv-lite這個三方包來轉換編碼,首先使用npm下載這個第三方包,讀取GBK文件函數以下:
var iconv = require('iconv-lite'); function readGBKText(pathname) { var myFs = fs.readFileSync(pathname); return iconv.decode(myFs, 'gbk'); }
經常使用的線性結構有:線性表,棧,隊列,循環隊列,數組
線性表中包括順序表、鏈表等,其中:
其餘
**若有不足,歡迎交流,祝各位看官 offer 拿到手軟 O(∩_∩)O**
個人博客即將搬運同步至騰訊雲+社區,邀請你們一同入駐:https://cloud.tencent.com/developer/support-plan