javaScript
-
理解MVVM等框架熬芜,手寫偽代碼愿棋。
-
ES6新特性隧膘,說說class
-
從編譯角度談?wù)勛兞刻嵘?/h3>
-
對象的類型
-
繼承中的toString
每一個引用類型會重寫toString方法芬膝。
所以如果要輸出對象的類型绒尊,需要使用Object.prototype.toString方法够傍。
將他call到需要輸出的對象上甫菠。
基本類型6個
boolean、string冕屯、null寂诱、undefined、number安聘、symbol
引用類型1個
object
-
判斷類型
1痰洒、instanceof
內(nèi)部使用原型鏈的方式進(jìn)行比較。
所以必須是引用類型浴韭,不可以是基本類型丘喻。
但是!念颈!如果使用new創(chuàng)建的string為對象(引用類型)
2泉粉、typeof
只能對基本類型進(jìn)行判斷,對引用類型(Array、RegExp)返回object
3嗡靡、constructor
str.constructor == String //true
arr.constructor == Array //true
4跺撼、toString
Object.prototype.toString.call(arr) //"[object Array]"
Object.prototype.toString.call(str) //"[object String]"
5、原型鏈比較proto
str.__proto__ == String.prototype //true
arr.__proto__ == Array.prototype //true
-
繼承
不要修改對象的__proto__
屬性讨彼,修改這個屬性會同時修改構(gòu)造函數(shù)的prototype
的對應(yīng)的參數(shù)歉井,然后會修改所有派生的其他對象。
在javaScript編譯過程中哈误,分為兩個階段哩至,預(yù)編譯階段和執(zhí)行賦值階段,在預(yù)編譯階段黑滴,js編譯器會查找代碼中的var關(guān)鍵字和函數(shù)聲明憨募,并將他們在頂部聲明并賦值為undfine紧索。執(zhí)行賦值階段在進(jìn)行賦值袁辈。
Webpack
-
webpack是什么?運行流程珠漂?熱更新原理晚缩?
webpack是一個打包模塊化javaScript的工具,在webpack里一切文件皆為模塊媳危,通過loader轉(zhuǎn)換文件荞彼,通過plugin注入鉤子,最后輸出由多個模塊組合成的文件待笑,webpack專注構(gòu)建模塊化項目鸣皂。webpack可以看作是模塊打包機:他做的事情是,分析你的項目結(jié)構(gòu)暮蹂,找到j(luò)avaScript模塊以及其它的一些瀏覽器不能直接運行的拓展語言(Scss寞缝,TypeScript),并將其打包(通過loader)為合適的格式(css仰泻,ES5荆陆,javaScript)以供瀏覽器使用。
-
0x02 webpack運行流程
1集侯、初始化參數(shù):從配置文件以及shell命令行獲取參數(shù)被啼,并整合成輸入?yún)?shù)。
2棠枉、開始編譯:將上一步的參數(shù)初始化compiler對象浓体,加載所有配置的插件plugin,執(zhí)行run方法開始編譯辈讶。
3命浴、尋找入口文件:通過配置文件的entry來找到所有的入口文件。
4荞估、進(jìn)行模塊的編譯:從入口文件出發(fā)咳促,將所有依賴的模塊通過loader進(jìn)行編譯稚新,之后遞歸遍歷所有引用的模塊,編譯輸出跪腹。
5褂删、完成模塊編譯:在經(jīng)過第4步以后,得到了每個模塊最終的翻譯內(nèi)容以及它們的依賴關(guān)系冲茸。
6屯阀、輸出資源:根據(jù)入口文件和模塊的依賴關(guān)系,組裝成一個一個包含多個模塊的chunk轴术,再把每個chunk轉(zhuǎn)換成一個單獨的文件加入到輸出列表难衰,這步是可以修改輸出文件的最后機會。
7逗栽、輸出完成盖袭,在確定好輸出內(nèi)容以后,根據(jù)配置確定輸出的路徑和文件名彼宠,再把文件內(nèi)容寫入到文件系統(tǒng)鳄虱。
在以上過程中,webpack在特定時間會廣播特定事件凭峡,plugin可以監(jiān)聽感興趣的事件拙已,并通過webpackAPI修改運行結(jié)果。
-
0x03 loader和plugin的編寫思路以及功能特點:
Loader像是一個翻譯官摧冀,把讀到的原文件內(nèi)容轉(zhuǎn)譯成新的文件內(nèi)容倍踪,并且每個loader通過鏈?zhǔn)讲僮鳎瑢⒃募徊揭徊椒g成想要的樣子索昂。
編寫loader要遵循單一原則建车,每個loader只做一種轉(zhuǎn)義功能。每個loader拿到的是原文件內(nèi)容(source)楼镐,可以通過返回值的方式將處理后的內(nèi)容輸出癞志,也可以調(diào)用this.callback()方法,將內(nèi)容返回給webpack框产。還可以通過this.async()生成一個callback函數(shù)凄杯,再用這個callback將處理后的內(nèi)容輸出出去。此外webpack還為開發(fā)者準(zhǔn)備了開發(fā)loader的工具函數(shù)集--------loader-utils秉宿。
相對于loader而言戒突,plugin的編寫就靈活了許多,webpack運行的生命周期中會廣播出很多事件描睦,plugin可以監(jiān)聽這些事件膊存,在合適的時機通過webpack提供的API改變輸出結(jié)果。
-
0x04 webpack的熱更新是如何做到的?說明其原理隔崎?
webpack的熱更新又稱熱替換(Hot Module Replacement)今艺,縮寫為HMR。這個機制可以做到不用刷新瀏覽器而將新更變的模塊替換舊的模塊爵卒。
1虚缎、第一步,在webpack的watch模式下钓株,文件系統(tǒng)的某一個文件發(fā)生變化以后实牡,webpack監(jiān)聽到文件變化,根據(jù)配置文件對模塊重新打包編譯轴合,并將打包后的代碼通過簡單的javaScript對象保存在內(nèi)存中创坞。
2、第二步受葛,webpack-dev-server和webpack之間的接口交互题涨,在這一步,主要是dev-server的中間件webpack-dev-middleware和webpack之間的交互奔坟,webpack-dev-middleware調(diào)用webpack暴露的API對代碼進(jìn)行監(jiān)控携栋,并且告訴webpack搭盾,將代碼打包到內(nèi)存中咳秉。
3、第三步鸯隅,webpack-dev-server對文件變化的監(jiān)控澜建,當(dāng)我們的配置文件中devServer.watchContentBase為true的時候,server會監(jiān)聽這些配置文件夾中靜態(tài)文件的變化蝌以,變化后會通知瀏覽器對應(yīng)用進(jìn)行l(wèi)ive reload炕舵。是刷新瀏覽器,和HMR是兩個概念跟畅。
4咽筋、第四步,webpack-dev-server通過sockjs(sebpack-dev-server的依賴)在瀏覽器和服務(wù)器之間建立一個websocket長連接徊件,將webpack編譯打包的各個階段的狀態(tài)信息告知瀏覽器端奸攻,同時也包括第三步中server監(jiān)聽靜態(tài)文件變化的信息。瀏覽器根據(jù)這些信息進(jìn)行不同的操作虱痕。當(dāng)然睹耐,服務(wù)端傳遞的最主要的信息還是新模塊的hash值,后面的步驟根據(jù)這個hash值來進(jìn)行模塊的熱替換部翘。
5硝训、webpack-dev-server/client端并不能夠請求更新的代碼,也不會執(zhí)行熱更新模塊操作,而是把這些工作交給webpack窖梁,webpack/hot/dev-server的工作就是根據(jù)webpack-dev-server/client傳給他的信息以及dev-server的配置決定是刷新瀏覽器還是進(jìn)行熱更新赘风,如果僅僅是刷新瀏覽器,就沒有后面的步驟了纵刘。
6贝次、HotModuleReplacement.runtime是客戶端HMR的中樞,它接受上一步傳遞給他的新模塊的hash值彰导,他通過JsonpTemplate.runtime向server端發(fā)送ajax請求蛔翅,服務(wù)端返回一個json,該json包含了所有要更新的模塊的hash值位谋,獲取到更新列表后山析,該模塊再次通過jsonp請求,獲取到最新的模塊代碼掏父,這就是上圖的7笋轨、8、9步驟赊淑。
7爵政、而第十步是決定HMR成功與否的關(guān)鍵步驟,在該步驟中陶缺,HotMoudulePlugin將會對新舊模塊進(jìn)行對比钾挟,決定是否更新模塊,再決定更新模塊后饱岸,檢查模塊之間的依賴關(guān)系掺出,更新模塊的同時更新模塊間的依賴引用。
8苫费、最后一步汤锨,當(dāng)HMR失敗后,回退到live reload操作百框,也就是刷新瀏覽器獲取最新打包代碼闲礼。
0x05 手寫promise
function MyPromise(executor) {
let that = this;
this.state = 'pending'
this.value = undefined
this.reason =undefined
this.onFulfilledFunc = [];
this.onRejectedFunc = [];
executor(resolve, reject)
function resolve(value){
if(that.state == 'pending'){
that.value = value;
that.onFulfilledFunc.forEach(fn => fn(value))
that.state = 'resolved'
}
}
function reject(reason){
if(that.state == 'pending'){
that.reason = reason;
that.onRejectedFunc.forEach(fn => fn(reason))
that.state = 'rejected'
}
}
}
MyPromise.prototype.then = function(onFulfilled, onRejected) {
if(this.state == 'resolved'){
if(typeof onFulfilled === 'function'){
onFulfilled(this.value)
}
}
if(this.state == 'rejected'){
if(typeof onRejected === 'function'){
onRejected(this.reason)
}
}
if(this.state === 'pending'){
if(typeof onFulfilled === 'function'){
this.onFulfilledFunc.push(onFulfilled)
}
if(typeof onRejected === 'function'){
this.onRejectedFunc.push(onRejected)
}
}
}
let a = new MyPromise((resolve, reject) => {
setTimeout(()=>{
resolve('assssd')//
}, 1)
})
a.then(res => {
console.log(res)
})
0x06 手寫jsonp
(function(window, document){
"use strict"
var jsonp = function(url, data, callback){
//data 為json對象
//將data轉(zhuǎn)化為dataStr
let dataStr = '?'
for (const key in data) {
dataStr += key + '=' + data[ley] + '&'
}
//定義jsonp的callback名字,需要包含隨機數(shù)字
let cbFuncName = 'my_json_cb_' + Math.random().toString().replace('.', '');
dataStr += 'callBack='+cbFuncName;
//創(chuàng)建jsonp script節(jié)點
let script = document.createElement('script');
//修改jsonp script節(jié)點的url
script.src = url + dataStr
//全局jsonp函數(shù)
window[cbFuncName] = function(data) {
//執(zhí)行callback
callback(data)
//執(zhí)行完畢刪除script節(jié)點
document.body.removeChild(script)
}
//加入script節(jié)點進(jìn)行請求
document.body.appendChild(script)
//將jsonp掛載到window上面
window.$jsonp = jsonp
}
})(window, document)
0x07 手寫new
//new
function _new(){
let newObj = {};
let Constructor = Array.prototype.shift.call(arguments);
newObj.__proto__ = Constructor.prototype;
Constructor.apply(newObj, arguments);
return newObj
}
0x08 手寫bind/call/apply
//call
/**
* @param this
* @param ...arg
*/
Function.prototype.myCall = function(obj){
let object = obj || window;
let args = [...arguments].slice(1);
object.func = this;//綁定函數(shù)
let result = object.func(...args);
delete object.func;
return result
}
//bind
Function.prototype.myBind = function(obj){
let that = this;
const object = obj;
let args = [...arguments].slice(1);
return function(){
let newArgs = [...arguments];
return that.apply(object, args.concat(newArgs))
}
}
0x09 手寫雙向綁定
<body>
<div></div>
<p></p>
<div style="border-top: 10px solid rgba(0, 0, 0, 0);border-right: 10px solid rgba(0, 0, 0, 0.5);border-left: 10px solid rgba(0, 0, 0, 0);border-bottom: 10px solid rgba(0, 0, 0, 1);background: rgba(0, 0, 0, 0);width: 10px;height: 10px;"></div>
<input type="text" id="txt">
<script>
console.log(Math.round(4, 2))
var obj = {}
Object.defineProperty(obj, 'txt', {
get: function() {
return obj
},
set: function(newValue){
document.body.getElementsByTagName('div')[0].innerHTML = newValue
}
})
document.addEventListener('keyup', (e) => {
obj.txt = e.target.value
})
</script>
</body>
算法
- 二叉樹
javaScript前序遍歷
// 先序遍歷:中铐维,左柬泽,右
const TreeNode = {
val: 1,
left: {
val: 2,
left: {
val: 4,
},
right: {
val: 5
}
},
right: {
val: 3,
left: {
val: 6,
},
right: {
val: 7
}
}
};
// 遞歸方式的先序遍歷方法
var preOrderRecur = function(root){
var list = [];
var preOrder = function(root){
if(root === undefined){
return root;
}
list.push(root.val)
preOrder(root.left);
preOrder(root.right);
}
preOrder(root);
return list;
};
// 非遞歸方式的先序遍歷方法
var preOrder = function(TreeNode){
var list = [];
let stack = [TreeNode];
while(stack.length !== 0){
const cur = stack.pop();
const right = cur.right;
const left = cur.left;
list.push(cur.val);
if(right){
stack.push(right);
}
if(left){
stack.push(left);
}
}
return list;
}
var list = preOrderRecur(TreeNode);
console.log('遞歸前序遍歷', list);
var listUnRecur = preOrder(TreeNode);
console.log('非遞歸前序遍歷', listUnRecur);
// [1, 2, 4, 5, 3, 6, 7]
- 鏈表環(huán)
- 冒泡算法都有哪些?優(yōu)勢與區(qū)別方椎?
- 時間復(fù)雜度是什么聂抢?如何計算時間復(fù)雜度?
node
- 異步
- 調(diào)試
html css
- ie模式和標(biāo)準(zhǔn)模式的盒模型
vue和react的區(qū)別
react setState如何優(yōu)化
shouldComponentUpdate(nextProps, nextState) {
return nextState.someData !== this.state.someData
}
http2頭部壓縮
http2頭部壓縮采用HPACK頭部壓縮棠众,使用霍夫曼編碼琳疏。
宏任務(wù)有决、微任務(wù)、event-loop
宏任務(wù)空盼、微任務(wù)书幕、event-loop
宏任務(wù):setInterval、setTimeout揽趾、setImmediate台汇、IO、requestAnimationFrame
微任務(wù):promise篱瞎、nextTick苟呐、async/await(本質(zhì)上是promise)、mutationObserver
event-loop:實在宏任務(wù)完成后進(jìn)行微任務(wù)檢查俐筋。
- 注意:宏任務(wù)中requestAnimationFarme要先于setTimeout執(zhí)行牵素。
- setTimeout和setImmediate同級。
- setTimeout為何不準(zhǔn)確澄者?如何讓setTimeout更準(zhǔn)確笆呆?
setTimeout不準(zhǔn)確是因為代碼運行需要時間。
在setTimeout內(nèi)部計算代碼運行的時間粱挡,然后減去赠幕。
http1.0 http1.1 http2.0 http和https區(qū)別
https://www.cnblogs.com/heluan/p/8620312.html
HTTP1.0和HTTP1.1的一些區(qū)別
緩存處理,在HTTP1.0中主要使用header里的If-Modified-Since,Expires來做為緩存判斷的標(biāo)準(zhǔn)询筏,HTTP1.1則引入了更多的緩存控制策略例如Entity tag榕堰,If-Unmodified-Since, If-Match, If-None-Match等更多可供選擇的緩存頭來控制緩存策略。
帶寬優(yōu)化及網(wǎng)絡(luò)連接的使用屈留,HTTP1.0中局冰,存在一些浪費帶寬的現(xiàn)象,例如客戶端只是需要某個對象的一部分灌危,而服務(wù)器卻將整個對象送過來了,并且不支持?jǐn)帱c續(xù)傳功能碳胳,HTTP1.1則在請求頭引入了range頭域勇蝙,它允許只請求資源的某個部分,即返回碼是206(Partial Content)挨约,這樣就方便了開發(fā)者自由的選擇以便于充分利用帶寬和連接味混。
錯誤通知的管理,在HTTP1.1中新增了24個錯誤狀態(tài)響應(yīng)碼诫惭,如409(Conflict)表示請求的資源與資源的當(dāng)前狀態(tài)發(fā)生沖突翁锡;410(Gone)表示服務(wù)器上的某個資源被永久性的刪除。
Host頭處理夕土,在HTTP1.0中認(rèn)為每臺服務(wù)器都綁定一個唯一的IP地址馆衔,因此瘟判,請求消息中的URL并沒有傳遞主機名(hostname)。但隨著虛擬主機技術(shù)的發(fā)展角溃,在一臺物理服務(wù)器上可以存在多個虛擬主機(Multi-homed Web Servers)拷获,并且它們共享一個IP地址。HTTP1.1的請求消息和響應(yīng)消息都應(yīng)支持Host頭域减细,且請求消息中如果沒有Host頭域會報告一個錯誤(400 Bad Request)匆瓜。
長連接,HTTP 1.1支持長連接(PersistentConnection)和請求的流水線(Pipelining)處理未蝌,在一個TCP連接上可以傳送多個HTTP請求和響應(yīng)驮吱,減少了建立和關(guān)閉連接的消耗和延遲,在HTTP1.1中默認(rèn)開啟Connection: keep-alive萧吠,一定程度上彌補了HTTP1.0每次請求都要創(chuàng)建連接的缺點糠馆。
HTTP2.0的一些優(yōu)勢
新的二進(jìn)制格式(Binary Format),HTTP1.x的解析是基于文本怎憋∮致担基于文本協(xié)議的格式解析存在天然缺陷,文本的表現(xiàn)形式有多樣性绊袋,要做到健壯性考慮的場景必然很多毕匀,二進(jìn)制則不同,只認(rèn)0和1的組合癌别≡聿恚基于這種考慮HTTP2.0的協(xié)議解析決定采用二進(jìn)制格式,實現(xiàn)方便且健壯展姐。
多路復(fù)用(MultiPlexing)躁垛,即連接共享,即每一個request都是是用作連接共享機制的圾笨。一個request對應(yīng)一個id教馆,這樣一個連接上可以有多個request,每個連接的request可以隨機的混雜在一起擂达,接收方可以根據(jù)request的 id將request再歸屬到各自不同的服務(wù)端請求里面土铺。
header壓縮,如上文中所言板鬓,對前面提到過HTTP1.x的header帶有大量信息悲敷,而且每次都要重復(fù)發(fā)送,HTTP2.0使用encoder來減少需要傳輸?shù)膆eader大小俭令,通訊雙方各自cache一份header fields表后德,既避免了重復(fù)header的傳輸,又減小了需要傳輸?shù)拇笮 ?/p>
服務(wù)端推送(server push)抄腔,同SPDY一樣瓢湃,HTTP2.0也具有server push功能理张。
HTTP和HTTPS的一些區(qū)別
HTTPS協(xié)議需要到CA申請證書,一般免費證書很少箱季,需要交費涯穷。
HTTP協(xié)議運行在TCP之上,所有傳輸?shù)膬?nèi)容都是明文藏雏,HTTPS運行在SSL/TLS之上拷况,SSL/TLS運行在TCP之上,所有傳輸?shù)膬?nèi)容都經(jīng)過加密的掘殴。
HTTP和HTTPS使用的是完全不同的連接方式男公,用的端口也不一樣千所,前者是80隙畜,后者是443吮播。
HTTPS可以有效的防止運營商劫持,解決了防劫持的一個大問題病瞳。
async await 實現(xiàn)原理 generator + yield + promise
http://www.reibang.com/p/862ab6d1a2f6
主要是通過generator+yield+promise實現(xiàn)
原型鏈圖
let和var
var
和let
均有變量遮蔽@抗尽!套菜。
var
沒有塊級作用域亲善,但是let
有塊級作用域!逗柴!蛹头。
map和parseInt問題
[1,2,2,3].map(parseInt)
//(4) [1, NaN, NaN, NaN]
因為parseInt
第二個參數(shù)為將要轉(zhuǎn)換的數(shù)字進(jìn)制類型。
2進(jìn)制沒有3這個數(shù)字戏溺,
3進(jìn)制沒有4這個數(shù)字渣蜗,
以此類推,所有顯示NaN
reduce實現(xiàn)map
Array.prototype._map = function(fn) {
return this.reduce((result, item) => [...result, fn(item)], [])
}
Array.prototype._filter = function(fn) {
return this.reduce((result, item) => fn(item) ? [...result, item] : result, [])
}
稀疏數(shù)組
1 in [0,,2,3,4]
//false
1 in [0,2,2,3,4]
//true
BFC
多個標(biāo)簽頁間進(jìn)行通訊
- worker
通過postMessage和事件監(jiān)聽
//worker
// sharedWorker所要用到的js文件旷祸,不必打包到項目中耕拷,直接放到服務(wù)器即可
let data = ''
onconnect = function (e) {
let port = e.ports[0]
port.onmessage = function (e) {
if (e.data === 'get') {
port.postMessage(data)
}
else { data = e.data }
}
}
// 這段代碼是必須的斑胜,打開頁面后注冊SharedWorker,顯示指定worker.port.start()方法建立與worker間的連接
if (typeof Worker === "undefined") {
alert('當(dāng)前瀏覽器不支持webworker')
} else {
let worker = new SharedWorker('worker.js')
worker.port.addEventListener('message', (e) => {
console.log('來自worker的數(shù)據(jù):', e.data)
}, false)
worker.port.start()
window.worker = worker
}
// 獲取和發(fā)送消息都是調(diào)用postMessage方法辫诅,我這里約定的是傳遞'get'表示獲取數(shù)據(jù)炕矮。
window.worker.port.postMessage('get')
window.worker.port.postMessage('發(fā)送信息給worker')
//頁面A發(fā)送數(shù)據(jù)給worker档痪,然后打開頁面B腐螟,調(diào)用window.worker.port.postMessage('get')乐纸,即可收到頁面A發(fā)送給worker的數(shù)據(jù)摇予。
- websocket
- 輪詢
- 同域cookie
- localStorage
最大數(shù)字
javaScript最大數(shù)字
判斷整數(shù)
xxx % 1 === 0
1+-'1'+1 = 1
七層協(xié)議
- 物理層
第一層汽绢,物理電路連接,網(wǎng)絡(luò)通信數(shù)據(jù)傳輸介質(zhì)侧戴,由電纜和設(shè)備構(gòu)成宁昭。 - 數(shù)據(jù)鏈路層
第二層,傳輸以‘幀’為單位的數(shù)據(jù)包酗宋,采用差錯控制與流量控制积仗,使得有差錯的物理線路變成無差錯的數(shù)據(jù)鏈路”静基于MAC地址實現(xiàn),SWITCH交換機稀颁。 - 網(wǎng)絡(luò)層
第三層楣黍,為數(shù)據(jù)節(jié)點之間傳輸創(chuàng)建邏輯鏈路,通過路由選擇算法為子網(wǎng)選擇合適的路徑租漂,實現(xiàn)網(wǎng)絡(luò)擁塞控制阶女,網(wǎng)絡(luò)互連。基于IP,實現(xiàn)router路由器抛蚤。 - 傳輸層
第四層,提供可靠的端對端服務(wù),處理數(shù)據(jù)包錯誤,數(shù)據(jù)次序,以及一些其他的關(guān)鍵問題,向高層屏蔽下層細(xì)節(jié),是非常關(guān)鍵的一層。
TCP/IP,UDP等協(xié)議在此層赢乓。 - 會話層
第五層躺屁,負(fù)責(zé)維護(hù)兩個節(jié)點的傳輸連接试吁,確保點到點不中斷,管理數(shù)據(jù)交換楼咳。 - 表示層
第六層熄捍,處理兩個通信系統(tǒng)中交換信息的表示方式,主要包括數(shù)據(jù)格式的變換母怜,數(shù)據(jù)的加密解密余耽,數(shù)據(jù)的壓縮與恢復(fù)。 - 應(yīng)用層
最高層苹熏,為軟件提供很多服務(wù)碟贾,比如文件服務(wù)器,數(shù)據(jù)庫服務(wù)轨域,電子郵件與其他網(wǎng)絡(luò)軟件服務(wù)袱耽。(HTTP、POP干发、STMP朱巨、FTP) - Promise catch
內(nèi)部采用try...catch實現(xiàn)的,只能catch同步操作
curry
function curry(fn){
//第一個參數(shù)是基礎(chǔ)執(zhí)行方法枉长,slice切除
var args=Array.prototype.slice.call(arguments,1);
//直接返回匿名函數(shù)
return function(){
//slice新參數(shù)以便能調(diào)用concat
var innerArgs=Array.prototype.slice.call(arguments);
//將配置的參數(shù)和新傳入的參數(shù)合并
var finalArgs=args.concat(innerArgs);
return fn.apply(null,finalArgs);
};
}
//ES6
var curry = fn => (...left) => (...right) => fn(...left, ...right)
reduce
Array.prototype.customReduce = function(fn , prev) {
for(let i = 0; i<this.length; i++) {
if (typeof prev === 'undefined') {
// prev不存在
prev = fn(this[i], this[i+1], i+1, this);
i++;
} else {
prev = fn(prev, this[i], i, this);
}
}
return prev;
}
- 使用reduce實現(xiàn)map
Array.prototype._map = function(fn, callbackThis) {
// 最終返回的新數(shù)組
let res = [];
// 定義回調(diào)函數(shù)的執(zhí)行環(huán)境
// call第一個參數(shù)傳入null冀续,則 this指向全局對象,同 map的規(guī)則
let CBThis = callbackThis || null;
this.reduce((brfore, after, idx, arr) => {
// 傳入map回調(diào)函數(shù)擁有的參數(shù)
// 把每一項的執(zhí)行結(jié)果push進(jìn)res中
res.push(fn.call(CBThis, after, idx, arr));
}, null);
return res;
};
首頁白屏必峰?
當(dāng)前很多無線頁面都使用前端模板進(jìn)行數(shù)據(jù)渲染洪唐,那么在糟糕的網(wǎng)速情況下,一進(jìn)去頁面吼蚁,看到的不是白屏就是 loading凭需,這成為白屏問題。
此問題發(fā)生的原因基本可以歸結(jié)為網(wǎng)速跟靜態(tài)資源
1肝匆、css文件加載需要一些時間粒蜈,在加載的過程中頁面是空白的。 解決:可以考慮將css代碼前置和內(nèi)聯(lián)术唬。
2薪伏、首屏無實際的數(shù)據(jù)內(nèi)容,等待異步加載數(shù)據(jù)再渲染頁面導(dǎo)致白屏粗仓。 解決:在首屏直接同步渲染html嫁怀,后續(xù)的滾屏等再采用異步請求數(shù)據(jù)和渲染html。
3借浊、首屏內(nèi)聯(lián)js的執(zhí)行會阻塞頁面的渲染塘淑。 解決:盡量不在首屏html代碼中放置內(nèi)聯(lián)腳本。(來自翔歌)
解決方案
根本原因是客戶端渲染的無力蚂斤,因此最簡單的方法是在服務(wù)器端存捺,使用模板引擎渲染所有頁面。同時
1減少文件加載體積,如html壓縮捌治,js壓縮
2加快js執(zhí)行速度 比如常見的無限滾動的頁面岗钩,可以使用js先渲染一個屏幕范圍內(nèi)的東西
3提供一些友好的交互,比如提供一些假的滾動條
4使用本地存儲處理靜態(tài)文件肖油。
json不能傳輸?shù)母袷?/h1>
DOM節(jié)點兼吓、文件表單等不能轉(zhuǎn)化為文本的信息。
前端性能指標(biāo)
白屏?xí)r間
首屏?xí)r間
用戶可操作時間
頁面總下載時間
inline-block
- 設(shè)置letter-spacing: -3px;
- 設(shè)置font-size: 0px;
- 設(shè)置font-size:0px森枪;會有什么問題视搏?
如果inline-block里面沒有內(nèi)容的話,垂直方向會有間隙县袱,需要設(shè)置:
{
font-size: 0px;
vertical-align: bottom;
}
偽類和偽元素
- 偽類是選擇器浑娜,輔助CSS選擇器選不到的元素
比如
:first-child
:hover
:focus - 偽元素是添加的額外的css容器
如
::before
::after
xss和csrf
參考文章XSS
參考文章CSRF
XSS:通過任何手段,在目標(biāo)網(wǎng)站上留下一段腳本式散,當(dāng)受害者執(zhí)行時記錄cookie等信息筋遭。
CSRF:通過目標(biāo)網(wǎng)站植入表單等腳本,誘導(dǎo)用戶執(zhí)行杂数。借用cookie宛畦,但是不記錄。
display屬性
align屬性
text-align屬性
vertical-align屬性
數(shù)字超過最大安全數(shù)字
安全數(shù)字bigInt
最大數(shù)字1.111112^1023 Number.MAX_VALUE
最大安全數(shù)字1.111112^52 Number.MAX_SAFE_INTEGER
使用bigInt可以解決揍移,數(shù)字+n
typeof 12n//bigInt