JS相關(guān)
1歹河、ES6新特性
- Default Parameters(默認(rèn)參數(shù))
ES6中辙喂,我們可以直接把默認(rèn)值放在函數(shù)申明里:
var link = function(height = 50, color = 'red', url = 'http://azat.co') {
...
}
- Template Literals(模板對象)
在ES6中灾部,我們可以使用新的語法$ {NAME}
伯襟,并把它放在反引號里:
var name = `Your name is ${first} ${last}. `;
var url = `http://localhost:3000/api/messages/${id}`;
- Multi-line Strings (多行字符串)
在ES6中劈愚,僅僅用反引號就可以實(shí)現(xiàn)多行字符串:
var fourAgreements = `You have the right to be you.
You can only be you when you do your best.`;
- Destructuring Assignment (解構(gòu)賦值)
解構(gòu)對象:
var { house, mouse } = $('body').data();
var { jsonMiddleware } = require('body-parser');
var { username, password } = req.body;
同樣也適用于數(shù)組:
var [col1, col2] = $('.column');
var [line1, line2, line3, , line5] = file.split('n');
- Arrow Functions(箭頭函數(shù))
主要解決this改變的問題
$('.btn').click((event) => {
this.sendData();
});
Promises 可用于異步加載等熊泵,之后單獨(dú)詳細(xì)列出相關(guān)方法
Block-Scoped Constructs Let and Const (塊級作用域聲明方式)
let和const均為ES6新引申的塊級作用域矛绘,由一對花括號{}中的語句集都屬于一個(gè)塊丽啡,在這個(gè){}里面包含的塊內(nèi)定義的所有變量在代碼塊外都是不可見的瘤泪,因此稱為塊級作用域灶泵。
而以前的var為函數(shù)作用域。let和const的區(qū)別為const聲明的是不變量
2对途、Promise介紹
-
promise的生命周期
每個(gè) Promise都會經(jīng)歷一個(gè)短暫的生命周期赦邻,初始為掛起態(tài)( pending state),這表示異步操作尚未結(jié)束实檀。一個(gè)掛起的 Promise 也被認(rèn)為是未決的( unsettled )惶洲。一旦異步操作結(jié)束, Promise就會被認(rèn)為是已決的( settled )膳犹,并進(jìn)入兩種可能狀態(tài)之一:
1. 已完成(fulfilled ): Promise 的異步操作已成功結(jié)束恬吕;
2. 已拒絕(rejected ): Promise 的異步操作未成功結(jié)束,可能是一個(gè)錯(cuò)誤镣奋,或由其他原因?qū)е隆?/p>一旦狀態(tài)改變币呵,就「凝固」了,會一直保持這個(gè)狀態(tài)侨颈,不會再發(fā)生變化余赢。當(dāng)狀態(tài)發(fā)生變化,promise.then綁定的函數(shù)就會被調(diào)用哈垢。注意:Promise一旦新建就會「立即執(zhí)行」妻柒,無法取消。這也是它的缺點(diǎn)之一
promise的方法
then()方法: then()方法在所有的 Promise上都存在耘分,并且接受兩個(gè)參數(shù)举塔。第一個(gè)參數(shù)是 Promise 被完成時(shí)要調(diào)用的函數(shù)绑警,與異步操作關(guān)聯(lián)的任何附加數(shù)據(jù)都會被傳入這個(gè)完成函數(shù)。第二個(gè)參數(shù)則是 Promise 被拒絕時(shí)要調(diào)用的函數(shù)央渣,與完成函數(shù)相似计盒,拒絕函數(shù)會被傳入與拒絕相關(guān)聯(lián)的任何附加數(shù)據(jù)。
catch()方法:其行為等同于只傳遞拒絕處理函數(shù)給 then() 芽丹。
resolve()方法:這段代碼會讓這個(gè)Promise對象立即進(jìn)入resolved狀態(tài)北启,并將結(jié)果success傳遞給then指定的onFulfilled回調(diào)函數(shù)。由于Promise.resolve()也是返回Promise對象拔第,因此可以用.then()處理其返回值咕村。
reject()方法:這段代碼會讓這個(gè)Promise對象立即進(jìn)入rejected狀態(tài),并將錯(cuò)誤對象傳遞給then指定的onRejected回調(diào)函數(shù)蚊俺。
all()方法:傳入Promise對象組成的數(shù)組懈涛,然后同時(shí)執(zhí)行,并且返回對應(yīng)返回值的數(shù)組泳猬。
race()方法:與all方法調(diào)用方式一致批钠,只是返回值只返回第一個(gè)Promise結(jié)果。
3得封、閉包
定義:
閉包就是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù)价匠。
例子:
function func() {
var a = 1, b= 2;
function closure () { // 閉包
return a + b; // 返回a,b的值
}
return closure; // 返回閉包函數(shù)
}
運(yùn)用閉包的關(guān)鍵:
閉包引用外部函數(shù)變量對象中的值;在外部函數(shù)的外部調(diào)用閉包呛每。
閉包的缺陷:
閉包的缺點(diǎn)就是常駐內(nèi)存會增大內(nèi)存使用量踩窖,并且使用不當(dāng)很容易造成內(nèi)存泄露。
如果不是因?yàn)槟承┨厥馊蝿?wù)而需要閉包晨横,在沒有必要的情況下洋腮,在其它函數(shù)中創(chuàng)建函數(shù)是不明智的,因?yàn)殚]包對腳本性能具有負(fù)面影響手形,包括處理速度和內(nèi)存消耗啥供。
4、跨域
何為跨域
通常域名是由以下幾部分組成:
http:// www.baidu.com : 8080 / #abc
協(xié)議 域名 端口號 hash库糠、查詢字符串伙狐、文件名等
同源策略會限制以下的內(nèi)容:
1,cookie瞬欧、localstorage和indexDB無法讀取
2贷屎,DOM無法獲得
3,ajax發(fā)送后會被瀏覽器攔截
不過有些標(biāo)簽是可以允許跨域加載的:
1艘虎,img 標(biāo)簽
2唉侄,link 標(biāo)簽
3,script 文件
當(dāng)協(xié)議野建、域名属划、端口號任意一個(gè)不相同時(shí)恬叹,都算作不同域。不同域之間請求資源同眯,就是跨域绽昼。
如果是協(xié)議和端口號造成的跨域,前端是無法解決的须蜗。
在跨域的問題上绪励,是通過 ‘url首部’來識別而不會根據(jù)域名對應(yīng)的ip地址是否相同來判斷。 url首部可以理解為‘協(xié)議唠粥、域名和端口必須匹配’。
跨域并不是http請求發(fā)送不出去停做,請求可以發(fā)出去晤愧,服務(wù)端也能接受并正常返回結(jié)果,只是結(jié)果被瀏覽器攔截了蛉腌。
因?yàn)榭缬虮旧硎菫榱俗柚褂脩臬@取不同域下的內(nèi)容官份。所以表單提交這種方式是可以發(fā)起跨域請求的,因?yàn)楸韱沃粫峤徊粫@取新內(nèi)容烙丛。解決跨域的方法
1舅巷,jsonp
因?yàn)樵陧撁嫔险{(diào)用script標(biāo)簽沒有跨域的限制(不僅如此,凡是擁有src屬性的標(biāo)簽都具有跨域的能力)河咽。
首先在本頁面聲明一個(gè)用來獲取數(shù)據(jù)的回調(diào)函數(shù)钠右, 創(chuàng)建一個(gè)script標(biāo)簽,將要跨域的地址加上該回調(diào)函數(shù)賦值給script的src屬性(通過 忘蟹?callback= fn)
服務(wù)器接收到該請求后飒房,會在返回的文件中 將該回調(diào)函數(shù)名和數(shù)據(jù)拼接起來,返回給客戶端媚值『萏海客戶端執(zhí)行該回調(diào)函數(shù),就可以獲取到服務(wù)端傳過來的數(shù)據(jù)褥芒。
jsonp的兼容性很好嚼松,但是僅僅只支持get請求。
延伸:為什么不支持post請求
(JSONP的最基本的原理是:動態(tài)添加一個(gè)<script>標(biāo)簽锰扶,而script標(biāo)簽的src屬性是沒有跨域的限制的献酗。這樣說來,這種跨域方式其實(shí)與ajax XmlHttpRequest協(xié)議無關(guān)了坷牛。
可以說jsonp的方式原理上和<script src="http://跨域/...xx.js"></script>是一致的凌摄,因?yàn)樗脑韺?shí)際上就是 使用js的script標(biāo)簽 進(jìn)行傳參,那么必然是get方式的了漓帅,和瀏覽器中敲入一個(gè)url一樣)
2锨亏,cors
cors需要瀏覽器和后臺同時(shí)支持痴怨。 ie8和ie9需要通過XDomainRequest實(shí)現(xiàn)瀏覽器會自動進(jìn)行cors通信,所以只要后臺實(shí)現(xiàn)了cros器予,就實(shí)現(xiàn)了跨域浪藻。
服務(wù)端設(shè)置Access-Control-Allow-Origin就可以開啟cors,該屬性表示哪些域名可以訪問資源乾翔。
在使用cors發(fā)送請求時(shí)爱葵,會出現(xiàn)兩種情況:
簡單請求:
只要同時(shí)滿足以下兩種條件就屬于簡單請求
條件1: 使用get 、head反浓、post方法
條件2: content-type的值為 text/plain萌丈、 multipart/form-data、 application/x-www-form-urlencoded 三者之一雷则。
復(fù)雜請求:
不符合簡單請求的就屬于復(fù)雜請求辆雾。 復(fù)雜請求的cors會在正式請求之前增加一次http查詢請求(預(yù)檢請求),該請求是option方法月劈,通過該請求來知道服務(wù)端是否允許跨域請求度迂。
3,postMessage
XMLHttpRequest Level 2的api猜揪,可以解決以下的問題:
頁面和其打開的新窗口的數(shù)據(jù)傳遞
多窗口之間消息傳遞
頁面和嵌套的iframe消息傳遞
以上三個(gè)場景的跨域數(shù)據(jù)傳遞
postMessage方法允許來自不同源的腳本采用異步方式進(jìn)行有限的通信惭墓。
otherWindow.postMessage(message,targetOrigin而姐,[transfer])腊凶;
message: 要發(fā)送的數(shù)據(jù)
targetOrigin:通過窗口的origin屬性來指定哪些窗口能接收到消息,只有目標(biāo)窗口的協(xié)議拴念、域名和端口都和提供的targetOrigin匹配的時(shí)候吭狡,才會被發(fā)送。
transfer: 和message同時(shí)傳遞的Transferable對象丈莺,這些對象的所有權(quán)將被轉(zhuǎn)移給消息的接收方划煮,發(fā)送方不再保有所有權(quán)〉薅恚
4弛秋,websocket
h5的一個(gè)持久化協(xié)議。實(shí)現(xiàn)了瀏覽器和服務(wù)器的全雙工通信俐载,同時(shí)也是跨域的一種解決方案蟹略。
websocket和http都是應(yīng)用層協(xié)議,都基于TCP遏佣。但是websocket是一種雙向通信協(xié)議挖炬,一旦連接建立,服務(wù)端和客戶端都可以向?qū)Ψ桨l(fā)送或接收數(shù)據(jù)状婶。
websocket建立的時(shí)候需要用到http協(xié)議意敛,建立好連接之后就與http無關(guān)了馅巷。
5,Node js中間件代理
同源策略是瀏覽器需要遵循的標(biāo)準(zhǔn)草姻,而如果服務(wù)端向服務(wù)端請求就無需遵循同源策略钓猬。
代理服務(wù)器接收瀏覽器的請求,處理后轉(zhuǎn)發(fā)給服務(wù)器撩独,收到服務(wù)器的響應(yīng)后再轉(zhuǎn)發(fā)給瀏覽器敞曹。
需要注意的是代理服務(wù)器和瀏覽器之間也遵循同源策略。
6综膀,nginx反向代理
類似node中間件代理澳迫,需要搭建一個(gè)中轉(zhuǎn)nginx服務(wù)器,用于轉(zhuǎn)發(fā)請求剧劝。
最簡單的跨域方式橄登。只要修改nginx的配置即可解決跨域問題。
5担平、Cookie、LocalStorage 與 SessionStorage的區(qū)別在哪里锭部?
- Cookie
一般由服務(wù)器生成暂论,可設(shè)置失效時(shí)間。如果在瀏覽器端生成Cookie拌禾,默認(rèn)是關(guān)閉瀏覽器后失效取胎;
只能儲存4kb左右;
每次都會攜帶在HTTP頭中湃窍,如果使用cookie保存過多數(shù)據(jù)會帶來性能問題
需要程序員自己封裝闻蛀,源生的Cookie接口不友好 - LocalStorage
除非被清除,否則永久保存
一般為5MB
僅在客戶端(即瀏覽器)中保存您市,不參與和服務(wù)器的通信
源生接口可以接受觉痛,亦可再次封裝來對Object和Array有更好的支持 - SessionStorage
僅在當(dāng)前會話下有效,關(guān)閉頁面或?yàn)g覽器后被清除
其余和LocalStorage一樣
6茵休、關(guān)于異步解決方案
- 使用Promise來處理薪棒,上面有Promise的詳細(xì)介紹
- Async/Await
async/await是寫異步代碼的新方式,優(yōu)于回調(diào)函數(shù)和Promise榕莺。
async/await是基于Promise實(shí)現(xiàn)的俐芯,它不能用于普通的回調(diào)函數(shù)。
async/await與Promise一樣钉鸯,是非阻塞的吧史。
async/await使得異步代碼看起來像同步代碼,再也沒有回調(diào)函數(shù)唠雕。但是改變不了JS單線程贸营、異步的本質(zhì)吨述。
Async/Await比起Promise的好處:
1、簡潔
使用Async/Await明顯節(jié)約了不少代碼莽使。我們不需要寫.then锐极,不需要寫匿名函數(shù)處理Promise的resolve值,也不需要定義多余的data變量芳肌,還避免了嵌套代碼灵再。
2、中間值使用簡單
const makeRequest = async () => {
const value1 = await promise1()
const value2 = await promise2(value1)
return promise3(value1, value2)
}
7亿笤、前端性能優(yōu)化
- 靜態(tài)資源優(yōu)化
主要是減少靜態(tài)資源的加載時(shí)間翎迁,主要包括html、css净薛、js和圖片文件汪榔,靜態(tài)資源的加載時(shí)間是前端性能最大的瓶頸(特別是圖片),現(xiàn)如今優(yōu)化的手段也很豐富肃拜,以下簡要列舉幾種常用的方法痴腌。
1、合并css燃领、js文件士聪,制作雪碧圖:減少http的請求次數(shù),節(jié)省網(wǎng)絡(luò)請求時(shí)間
2猛蔽、靜態(tài)資源cdn分發(fā):客戶端可以通過最佳的網(wǎng)絡(luò)鏈路加載靜態(tài)資源
3剥悟、js、css文件壓縮曼库,圖片壓縮区岗,gzip壓縮:減少請求返回的數(shù)據(jù)量
4、靜態(tài)資源緩存機(jī)制
5毁枯、權(quán)衡dns的查找 - 接口訪問優(yōu)化
首屏直出慈缔、同構(gòu):前者利用ajax加載、后者使用node.js后端
接口合并 - 頁面渲染速度優(yōu)化
1种玛、css放在頂部:優(yōu)先渲染
2胀糜、js放在底部:避免阻塞
3、減少DOM元素?cái)?shù)量:這個(gè)最能體現(xiàn)變成水平了
4蒂誉、img標(biāo)簽要設(shè)置高寬:減少重繪重排
另外教藻,新晉前端框架 vue、react右锨,虛擬dom的渲染方案括堤,在內(nèi)存中進(jìn)行 dom diff 比較,做到最小化的操作真實(shí)的 dom (操作真實(shí)的 dom 常常會成為性能瓶頸),能極大的提高渲染速度悄窃。
Vue相關(guān)
1讥电、關(guān)于雙向綁定的原理
核心:vue數(shù)據(jù)雙向綁定是通過數(shù)據(jù)劫持結(jié)合發(fā)布者-訂閱者模式的方式來實(shí)現(xiàn)的。是通過Object.defineProperty()的get轧抗、set方法來實(shí)現(xiàn)數(shù)據(jù)劫持的
實(shí)現(xiàn)過程:我們已經(jīng)知道實(shí)現(xiàn)數(shù)據(jù)的雙向綁定恩敌,首先要對數(shù)據(jù)進(jìn)行劫持監(jiān)聽,所以我們需要設(shè)置一個(gè)監(jiān)聽器Observer横媚,用來監(jiān)聽所有屬性纠炮。如果屬性發(fā)上變化了,就需要告訴訂閱者Watcher看是否需要更新灯蝴。因?yàn)橛嗛喺呤怯泻芏鄠€(gè)恢口,所以我們需要有一個(gè)消息訂閱器Dep來專門收集這些訂閱者,然后在監(jiān)聽器Observer和訂閱者Watcher之間進(jìn)行統(tǒng)一管理的穷躁。接著耕肩,我們還需要有一個(gè)指令解析器Compile,對每個(gè)節(jié)點(diǎn)元素進(jìn)行掃描和解析问潭,將相關(guān)指令對應(yīng)初始化成一個(gè)訂閱者Watcher猿诸,并替換模板數(shù)據(jù)或者綁定相應(yīng)的函數(shù),此時(shí)當(dāng)訂閱者Watcher接收到相應(yīng)屬性的變化狡忙,就會執(zhí)行對應(yīng)的更新函數(shù)梳虽,從而更新視圖。因此接下去我們執(zhí)行以下3個(gè)步驟去枷,實(shí)現(xiàn)數(shù)據(jù)的雙向綁定:
1.實(shí)現(xiàn)一個(gè)監(jiān)聽器Observer怖辆,用來劫持并監(jiān)聽所有屬性是复,如果有變動的删顶,就通知訂閱者。
2.實(shí)現(xiàn)一個(gè)訂閱者Watcher淑廊,可以收到屬性的變化通知并執(zhí)行相應(yīng)的函數(shù)逗余,從而更新視圖。
3.實(shí)現(xiàn)一個(gè)解析器Compile季惩,可以掃描和解析每個(gè)節(jié)點(diǎn)的相關(guān)指令录粱,并根據(jù)初始化模板數(shù)據(jù)以及初始化相應(yīng)的訂閱器。
2画拾、關(guān)于v-show和v-if的相同不同
共同點(diǎn):都能控制元素的顯示和隱藏啥繁;
不同點(diǎn):實(shí)現(xiàn)本質(zhì)方法不同,v-show本質(zhì)就是通過控制css中的display設(shè)置為none青抛,控制隱藏旗闽,只會編譯一次;v-if是動態(tài)的向DOM樹內(nèi)添加或者刪除DOM元素,若初始值為false适室,就不會編譯了嫡意。而且v-if不停的銷毀和創(chuàng)建比較消耗性能。
總結(jié):如果要頻繁切換某節(jié)點(diǎn)捣辆,使用v-show(切換開銷比較小蔬螟,初始開銷較大)。如果不需要頻繁切換某節(jié)點(diǎn)使用v-if(初始渲染開銷較小汽畴,切換開銷比較大)旧巾。
3、$nextTick
當(dāng)你修改了data的值然后馬上獲取這個(gè)dom元素的值整袁,是不能獲取到更新后的值菠齿,
你需要使用$nextTick這個(gè)回調(diào),讓修改后的data值渲染更新到dom元素之后在獲取坐昙,才能成功绳匀。
new Vue({
el: '.app',
data: {
msg: 'Hello Vue.',
msg1: '',
msg2: '',
msg3: ''
},
methods: {
changeMsg() {
this.msg = "Hello world."
this.msg1 = this.$refs.msgDiv.innerHTML
this.$nextTick(() => {
this.msg2 = this.$refs.msgDiv.innerHTML
})
this.msg3 = this.$refs.msgDiv.innerHTML
}
}
})
如上代碼:只有this.msg2是顯示更新后的值,1和3都依然顯示更新前的值
4炸客、單頁面應(yīng)用(SPA)
單頁面應(yīng)用(SPA)疾棵,通俗一點(diǎn)說就是指只有一個(gè)主頁面的應(yīng)用,瀏覽器一開始要加載所有必須的 html, js, css痹仙。所有的頁面內(nèi)容都包含在這個(gè)所謂的主頁面中是尔。但在寫的時(shí)候,還是會分開寫(頁面片段)开仰,然后在交互的時(shí)候由路由程序動態(tài)載入拟枚,單頁面的頁面跳轉(zhuǎn),僅刷新局部資源众弓。多應(yīng)用于pc端恩溅。
5、Vue常用修飾符
.stop:等同于JavaScript中的event.stopPropagation()谓娃,防止事件冒泡脚乡;
.prevent:等同于JavaScript中的event.preventDefault(),防止執(zhí)行預(yù)設(shè)的行為(如果事件可取消滨达,則取消該事件奶稠,而不停止事件的進(jìn)一步傳播);
.capture:與事件冒泡的方向相反捡遍,事件捕獲由外到內(nèi)锌订;
.self:只會觸發(fā)自己范圍內(nèi)的事件,不包含子元素画株;
.once:只會觸發(fā)一次辆飘。
6涩搓、關(guān)于Vue生命周期
beforeCreate:在new一個(gè)vue實(shí)例后,只有一些默認(rèn)的生命周期鉤子和默認(rèn)事件劈猪,其他的東西都還沒創(chuàng)建昧甘。在beforeCreate生命周期執(zhí)行的時(shí)候,data和methods中的數(shù)據(jù)都還沒有初始化战得。不能在這個(gè)階段使用data中的數(shù)據(jù)和methods中的方法
create:data 和 methods都已經(jīng)被初始化好了充边,如果要調(diào)用 methods 中的方法,或者操作 data 中的數(shù)據(jù)常侦,最早可以在這個(gè)階段中操作
beforeMount:執(zhí)行到這個(gè)鉤子的時(shí)候浇冰,在內(nèi)存中已經(jīng)編譯好了模板了,但是還沒有掛載到頁面中聋亡,此時(shí)肘习,頁面還是舊的
mounted:執(zhí)行到這個(gè)鉤子的時(shí)候,就表示Vue實(shí)例已經(jīng)初始化完成了坡倔。此時(shí)組件脫離了創(chuàng)建階段漂佩,進(jìn)入到了運(yùn)行階段。 如果我們想要通過插件操作頁面上的DOM節(jié)點(diǎn)罪塔,最早可以在和這個(gè)階段中進(jìn)行
beforeUpdate: 當(dāng)執(zhí)行這個(gè)鉤子時(shí)投蝉,頁面中的顯示的數(shù)據(jù)還是舊的,data中的數(shù)據(jù)是更新后的征堪, 頁面還沒有和最新的數(shù)據(jù)保持同步
updated:頁面顯示的數(shù)據(jù)和data中的數(shù)據(jù)已經(jīng)保持同步了瘩缆,都是最新的
beforeDestory:Vue實(shí)例從運(yùn)行階段進(jìn)入到了銷毀階段,這個(gè)時(shí)候上所有的 data 和 methods 佃蚜, 指令庸娱, 過濾器 ……都是處于可用狀態(tài)。還沒有真正被銷毀
destroyed: 這個(gè)時(shí)候上所有的 data 和 methods 谐算, 指令熟尉, 過濾器 ……都是處于不可用狀態(tài)。組件已經(jīng)被銷毀了
7氯夷、關(guān)于深拷貝
對于一個(gè)引用類型臣樱,如果直接將它賦值給另一個(gè)變量靶擦,由于這兩個(gè)引用指向同一個(gè)地址腮考,這時(shí)改變其中任何一個(gè)引用,另一個(gè)都會受到影響玄捕。當(dāng)我們想復(fù)制一個(gè)對象并且切斷與這個(gè)對象的聯(lián)系踩蔚,就要使用深拷貝。對于一個(gè)對象來說枚粘,由于可能有多層結(jié)構(gòu)馅闽,所以我們可以使用遞歸來解決這個(gè)問題
方法1:遞歸循環(huán),先判斷是數(shù)組還是對象,使用對應(yīng)的for循環(huán)遞歸遍歷福也,然后賦值局骤。可解決所有深拷貝問題暴凑。
方法2:JSON.stringify()以及JSON.parse()
問題:使用JSON.stringify()以及JSON.parse()它是不可以拷貝 undefined 峦甩, function, RegExp 等等類型的
方法3: Object.assign(target, source)
問題:無法拷貝多層對象
方法4:concat现喳、slice方法(針對數(shù)組)
方法5:ES6擴(kuò)展運(yùn)算符
var arr = [1,2,3,4,5]
var [ ...arr2 ] = arr
arr[2] = 5