JSV5
1藏澳、vue 雙向綁定的原理
通過object.defineProperty()方法來劫持屬性的getter和setter,當(dāng)Observer監(jiān)聽到屬性變化時(shí)喷市,就會(huì)發(fā)布消息給訂閱者Watcher瞄沙,指令解析器Compile會(huì)對(duì)每個(gè)節(jié)點(diǎn)元素進(jìn)行掃描和解析为朋,將相關(guān)指令對(duì)應(yīng)初始化成訂閱者watcher患亿,替換模板的數(shù)據(jù)或者綁定相應(yīng)的函數(shù)传蹈,當(dāng)訂閱者watcher接收到屬性變化時(shí),就會(huì)執(zhí)行對(duì)應(yīng)的更新函數(shù)步藕,從而更新視圖惦界,實(shí)現(xiàn)雙向綁定。
2咙冗、需要使用key來給每個(gè)節(jié)點(diǎn)做一個(gè)唯一標(biāo)識(shí)沾歪,Diff算法就可以正確的識(shí)別此節(jié)點(diǎn)。
作用主要是為了高效的更新虛擬DOM
3乞娄、使用$nextTick這個(gè)回調(diào),讓修改后的data值渲染更新到dom元素之后在獲取
4显歧、vue-loader是基于webpack的一個(gè)的loader仪或,解析和轉(zhuǎn)換 .vue 文件,提取出其中的邏輯代碼 script士骤、樣式代碼 style范删、以及 HTML 模版 template,再分別把它們交給對(duì)應(yīng)的 Loader 去處理拷肌,核心的作用到旦,就是提取,劃重點(diǎn)巨缘。
5添忘、keep-alive 是 Vue 內(nèi)置的一個(gè)組件,可以使被包含的組件保留狀態(tài)若锁,或避免重新渲染搁骑。
6、對(duì)vue生命周期的理解又固?
Vue 實(shí)例在被創(chuàng)建時(shí)經(jīng)過一系列的初始化過程仲器。 總共分為8個(gè)階段創(chuàng)建前/后,載入前/后仰冠,更新前/后乏冀,銷毀前/后。
創(chuàng)建前/后: 在beforeCreated階段洋只,vue實(shí)例的掛載元素$el和**數(shù)據(jù)對(duì)象**data都為undefined辆沦,還未初始化昼捍。在created階段,vue實(shí)例的數(shù)據(jù)對(duì)象data有了众辨,$el還沒有端三。
載入前/后:在beforeMount階段,vue實(shí)例的$el和data都初始化了鹃彻,但還是掛載之前為虛擬的dom節(jié)點(diǎn)郊闯,data.message還未替換。在mounted階段蛛株,vue實(shí)例掛載完成团赁,data.message成功渲染。
更新前/后:當(dāng)data變化時(shí)谨履,會(huì)觸發(fā)beforeUpdate和updated方法欢摄。
銷毀前/后:在執(zhí)行destroy方法后,對(duì)data的改變不會(huì)再觸發(fā)周期函數(shù)笋粟,說明此時(shí)vue實(shí)例已經(jīng)解除了事件監(jiān)聽以及和dom的綁定怀挠,但是dom結(jié)構(gòu)依然存在。
7害捕、什么是vuex?以及相關(guān)屬性
Vuex是通過全局注入store對(duì)象绿淋,來實(shí)現(xiàn)組件間的狀態(tài)共享。
vuex五大核心屬性:state尝盼,getters,mutations盾沫,actions失尖,module
state:存儲(chǔ)數(shù)據(jù)琼富,存儲(chǔ)狀態(tài);在根實(shí)例中注冊(cè)了store 后,用 this.$store.state 來訪問纱注;對(duì)應(yīng)vue里面的data瞎嬉;存放數(shù)據(jù)方式為響應(yīng)式挑胸,vue組件從store中讀取數(shù)據(jù),如數(shù)據(jù)發(fā)生變化坝茎,組件也會(huì)對(duì)應(yīng)的更新蜕煌。
getters:可以認(rèn)為是 store 的計(jì)算屬性,它的返回值會(huì)根據(jù)它的依賴被緩存起來堵腹,且只有當(dāng)它的依賴值發(fā)生了改變才會(huì)被重新計(jì)算释液。
mutations:包含了很多方法 用于更改 Vuex 的 store 中的狀態(tài)牲蜀。
actions:包含任意異步操作,通過提交 mutation 間接更變狀態(tài)缎浇。
module:將 store 分割成模塊俊鱼,每個(gè)模塊都具有state、mutation侵俗、action卿城、getter星掰、甚至是嵌套子模塊多望。
視圖通過點(diǎn)擊事件,觸發(fā)mutations中方法氢烘,可以更改state中的數(shù)據(jù)怀偷,一旦state數(shù)據(jù)發(fā)生更改,getters把數(shù)據(jù)反映到視圖播玖。
那么actions,可以理解處理異步椎工,而單純多加的一層。
既然提到了mutions actions這時(shí)候 就不得不提commit蜀踏,dispatch
在vue例子中维蒙,通過click事件,觸發(fā)methods中的方法脓斩。當(dāng)存在異步時(shí)木西,而在vuex中需要dispatch來觸發(fā)actions中的方法畴栖,actions中的commit可以觸發(fā)mutations中的方法随静。同步,則直接在組件中commit觸發(fā)vuex中mutations中的方法。
為什么vuex中要通過mutations修改state燎猛,而不是直接修改state恋捆?
因?yàn)閟tate是實(shí)時(shí)更新的,mutations無法進(jìn)行異步操作重绷,而如果直接修改state的話是能夠異步操作的沸停,當(dāng)你異步對(duì)state進(jìn)行操作時(shí),還沒執(zhí)行完昭卓,這時(shí)候如果state已經(jīng)在其他地方被修改了愤钾,這樣就會(huì)導(dǎo)致程序存在問題了。所以state要同步操作候醒,通過mutations的方式限制了不允許異步能颁。
Vue-router原理
vue-router通過hash與History interface兩種方式實(shí)現(xiàn)前端路由,更新視圖但不重新請(qǐng)求頁面”是前端路由原理的核心之一倒淫。
hash模式url里面永遠(yuǎn)帶著#號(hào)伙菊,我們?cè)陂_發(fā)當(dāng)中默認(rèn)使用這個(gè)模式。那么什么時(shí)候要用history模式呢敌土?如果用戶考慮url的規(guī)范那么就需要使用history模式镜硕,因?yàn)閔istory模式?jīng)]有#號(hào)
在history下,是h5推出的新api返干,你可以自由的修改path兴枯,當(dāng)二跳刷新時(shí),如果服務(wù)器中沒有相應(yīng)的響應(yīng)或者資源,會(huì)報(bào)404
8矩欠、vue2.0和vue3.0區(qū)別
????8.1.項(xiàng)目目錄結(jié)構(gòu)變化
移除了配置文件目錄 例如config和build文件夾 配置文件從config/index.js 挪到了vue.config.js
移除了static靜態(tài)文件夾念恍,新增public文件夾,并把index.html移動(dòng)到public中
????8.2.數(shù)據(jù)監(jiān)聽
2.0基于object.defineProperty()來挾持屬性的getter和setter 當(dāng)給一個(gè)對(duì)象新增屬性時(shí) 這個(gè)對(duì)象的所有訂閱者watcher都會(huì)重新運(yùn)行晚顷,而3.0是基于Proxy來按需監(jiān)聽 減少內(nèi)存占用
proxy其實(shí)就是在對(duì)目標(biāo)對(duì)象的操作之前提供了攔截峰伙,可以對(duì)外界的操作進(jìn)行過濾和改寫,修改某些操作的默認(rèn)行為该默,這樣我們可以不直接操作對(duì)象本身瞳氓,而是通過操作對(duì)象的代理對(duì)象來間接來操作對(duì)象,達(dá)到預(yù)期的目的~
9栓袖、vue組件中的data為何必須是一個(gè)function
首先需要?jiǎng)?chuàng)建一個(gè)組件構(gòu)造器匣摘,然后注冊(cè)組件。注冊(cè)組件的本質(zhì)其實(shí)就是建立一個(gè)組件構(gòu)造器的引用裹刮。使用組件才是真正創(chuàng)建一個(gè)組件實(shí)例音榜。所以,注冊(cè)組件其實(shí)并不產(chǎn)生新的組件類捧弃,但會(huì)產(chǎn)生一個(gè)可以用來實(shí)例化的新方式赠叼。
vue組件中data值不能為對(duì)象擦囊,因?yàn)閷?duì)象是引用類型,組件可能會(huì)被多個(gè)實(shí)例同時(shí)引用嘴办。如果data值為對(duì)象瞬场,將導(dǎo)致多個(gè)實(shí)例共享一個(gè)對(duì)象,其中一個(gè)組件改變data屬性值涧郊,其它實(shí)例也會(huì)受到影響贯被。
data為函數(shù),通過return 返回對(duì)象的拷貝妆艘,致使每個(gè)實(shí)例都有自己獨(dú)立的對(duì)象批旺,實(shí)例之間可以互不影響的改變data屬性值苞轿。
10翎卓、computed和watch的區(qū)別
如果沒有computed對(duì)屬性進(jìn)行計(jì)算的話 屬性計(jì)算可能需要用表達(dá)式的方式放在模板上執(zhí)行 這樣模板就顯得過重 而且在頁面中大量使用表達(dá)式去處理復(fù)雜的邏輯數(shù)據(jù)時(shí) 維護(hù)性不友好
10.1 computed是計(jì)算一個(gè)新的屬性 并將其掛載在vue實(shí)例上 而watch是監(jiān)聽已經(jīng)存在且已掛載在實(shí)例上的數(shù)據(jù)
10.2 computed具有緩存性,只有依賴發(fā)生變化后,第一次訪問computed屬性才會(huì)計(jì)算新值 而watch則是當(dāng)數(shù)據(jù)發(fā)生變化便會(huì)調(diào)用執(zhí)行函數(shù)
10.3 computed適用一個(gè)數(shù)據(jù)被多個(gè)數(shù)據(jù)影響,而watch適用一個(gè)數(shù)據(jù)影響多個(gè)數(shù)據(jù);
computed原理
https://segmentfault.com/a/1190000018821652
11、為何vue數(shù)組通過下標(biāo)方式無法改變視圖更新
vue對(duì)數(shù)組只是observe了每個(gè)元素的值 數(shù)組的下標(biāo)并沒有被監(jiān)聽 所以通過下標(biāo)是不能更新視圖 而數(shù)組方法能夠響應(yīng)式 是因?yàn)閷?duì)數(shù)組的方法進(jìn)行了def操作姐呐≡ǎ可能僅僅只需要改變數(shù)組的一個(gè)值而已 如果使用下標(biāo)方式 會(huì)對(duì)數(shù)組的每一項(xiàng)進(jìn)行監(jiān)聽 當(dāng)遇到一個(gè)數(shù)組較大時(shí) 對(duì)性能是一個(gè)比較大的損耗
12末荐、從URL輸入到頁面展現(xiàn)的過程
? ??1.在瀏覽器輸入url
? ? 2.瀏覽器獲取了這個(gè)url,當(dāng)然就去解析了,它先去緩存當(dāng)中看看有沒有,從 瀏覽器緩存-系統(tǒng)緩存-路由器緩存 當(dāng)中查看臣疑,如果有從緩存當(dāng)中顯示頁面,然后沒有那就進(jìn)行步驟三域名解析;
? ? 3.域名解析
? ? 由DNS服務(wù)器來完成將域名解析成對(duì)應(yīng)的服務(wù)器IP地址這項(xiàng)工作
? ? 4.服務(wù)器處理請(qǐng)求 TCP三次握手連接
TCP是互聯(lián)網(wǎng)中的傳輸層協(xié)議,提供可靠的鏈接服務(wù)片酝,采用三次握手確認(rèn)一個(gè)連接:
瀏覽器向服務(wù)器發(fā)送建立連接的請(qǐng)求审轮。
服務(wù)器接收到瀏覽器發(fā)送的請(qǐng)求后榴捡,想瀏覽器發(fā)送統(tǒng)一連接的信號(hào)项乒。
瀏覽器接受到服務(wù)器發(fā)出的同意連接的信號(hào)后埃碱,再次向服務(wù)器發(fā)出確認(rèn)連接的信號(hào)似炎。
當(dāng)三次握手返程仆嗦,TCP客戶端和服務(wù)端成功的建立連接集绰,就可以開始傳輸數(shù)據(jù)了罕袋。
? ? ? 5.服務(wù)器收到請(qǐng)求
服務(wù)器收到瀏覽器發(fā)送的請(qǐng)求信息炫贤,返回一個(gè)響應(yīng)頭和一個(gè)響應(yīng)體亮元。
? ? ?6.頁面渲染
瀏覽器收到服務(wù)器發(fā)送的響應(yīng)頭和響應(yīng)體煮甥,進(jìn)行客戶端渲染卖局,生成Dom樹染坯、解析css樣式是趴、js交互
13肛搬、前端性能優(yōu)化
? ??1.使用字體圖標(biāo)代替圖片
? ? 2.html css js 圖片等文件的壓縮 圖片懶加載
? ? 3.使用CDN
? ? 4.模塊按需加載 import require
? ? ?5.減少重繪 避免使用層級(jí)較深的選擇器 提升渲染效率
? ? 6.減少dom操作 由于DOM操作比較耗時(shí),且可能會(huì)造成回流毕贼,因此要避免頻繁操作DOM温赔,可以批量操作DOM,先用字符串拼接完畢鬼癣,再用innerHTML更新DOM
14陶贼、webpack 構(gòu)建流程
? ??1.從配置文件或者腳本語句中得出初始化參數(shù)
? ? 2.通過參數(shù)初始化compiler對(duì)象,加載配置的插件待秃,開始編譯
? ?3.根據(jù)配置中的 entry 找出所有的入口文件
? ?4.從入口文件 通過遞歸處理 對(duì)模塊進(jìn)行編譯 找到依賴的模塊
? ?5.模塊編譯完成后拜秧,得到編譯后的內(nèi)容和彼此的依賴關(guān)系
? ?6.根據(jù)依賴關(guān)系,對(duì)模塊進(jìn)行分片組裝章郁,轉(zhuǎn)換成單獨(dú)文件加入到輸出列表中
? ?7.確定輸出內(nèi)容的路徑和文件名枉氮,進(jìn)行輸出
webpack里的loader和plugin
loader是使webpack擁有加載和解析非js文件的能力 對(duì)模塊的源代碼進(jìn)行轉(zhuǎn)換 可以在import 或"加載"模塊時(shí)預(yù)處理文件 常見的 style-loader css-loader? file-loader(把url里面內(nèi)容轉(zhuǎn)換成我們最終需要使用的那個(gè)路徑。把圖片轉(zhuǎn)移到我們輸出的目錄暖庄,并且把圖片更改為另外一種名字或者做一些其他的處理
) url-loader(引入圖片資源base64處理 用limit約束 小于某個(gè)大小時(shí)才base64處理)
plugin可以拓展webpack的功能 比如通過api改變輸出結(jié)果 使webpack更加靈活
常見的
1. clean-webpack-plugin 配合 webpack -p命令 編譯文件時(shí)清楚build或dist文件 再生成新的
2.html-webpack-plugin 簡(jiǎn)單創(chuàng)建html文件 用于服務(wù)器訪問 同時(shí)為輸出文件添加哈希值標(biāo)記聊替,避免老的不變的文件重新加載,避免新修改的文件受緩存影響
3.extract-text-webpack-plugin 主要是為了抽離css樣式,防止將樣式打包在js中引起頁面樣式加載錯(cuò)亂的現(xiàn)象雄驹。
Gulp和webpack
Gulp?就是為了規(guī)范前端開發(fā)流程佃牛,實(shí)現(xiàn)前后端分離、模塊化開發(fā)医舆、版本控制俘侠、文件合并與壓縮、mock數(shù)據(jù)等功能的一個(gè)前端自動(dòng)化構(gòu)建工具蔬将。Gulp側(cè)重于前端開發(fā)的?整個(gè)過程?的控制管理爷速。
Webpack?是前端資源模塊化管理和打包工具。它可以將許多松散的模塊按照依賴和規(guī)則打包成符合生產(chǎn)環(huán)境部署的前端資源霞怀。還可以將按需加載的模塊進(jìn)行代碼分隔惫东,等到實(shí)際需要的時(shí)候再異步加載。Webpack更側(cè)重于模塊打包。
15廉沮、內(nèi)存泄漏
已經(jīng)不再使用的內(nèi)存未能被程序釋放颓遏,叫內(nèi)存泄露(memory leak)
原因
1.全局變量
? ? 全局對(duì)象就是window對(duì)象。變量在窗口關(guān)閉或重新刷新頁面之前都不會(huì)被釋放
2.閉包
? ? 閉包是內(nèi)部函數(shù)總是可以訪問其所在的外部函數(shù)中聲明的參數(shù)和變量滞时,可以讀取函數(shù)內(nèi)部的變量叁幢,然后讓這些變量始終保存在內(nèi)存中。如果在使用結(jié)束后沒有將局部變量清除坪稽,就可能導(dǎo)致內(nèi)存泄露曼玩。
3.事件監(jiān)聽
? 對(duì)同一個(gè)事件重復(fù)監(jiān)聽,但是忘記移除窒百,會(huì)導(dǎo)致內(nèi)存泄露黍判。
4.其他原因
? console.log打印的對(duì)象不能被垃圾回收,可能會(huì)導(dǎo)致內(nèi)存泄露篙梢。
? setInterval也可能會(huì)導(dǎo)致內(nèi)存泄露顷帖。
內(nèi)存泄漏的識(shí)別方法
開發(fā)者工具Performance勾選 Memory 點(diǎn)擊左側(cè)record 訪問網(wǎng)頁 stop 查看Event Log分析結(jié)果
16、new和聲明的不同
? ?1.聲明的作用域限制在定義類對(duì)象的方法中庭猩,當(dāng)方法結(jié)束時(shí)窟她,類對(duì)象也被系統(tǒng)釋放了陈症,(安全不會(huì)造成內(nèi)存系統(tǒng)泄漏)蔼水。
? ?2.new 創(chuàng)建的是指向類對(duì)象的指針,作用域變成了全局录肯,當(dāng)程序結(jié)束時(shí)趴腋,必須用delete刪除,系統(tǒng)不會(huì)自動(dòng)釋放论咏,(不注意可能造成內(nèi)存泄漏)优炬。
? ?3.new的存儲(chǔ)空間在堆上 聲明的存儲(chǔ)空間在棧上
18、vue和react的區(qū)別
1.模板渲染方式
Vue是在模板中厅贪,通過指令來實(shí)現(xiàn)渲染 模板的數(shù)據(jù)都必須掛在this上進(jìn)行一次中轉(zhuǎn) 而React是在組件JS代碼中蠢护,通過原生JS實(shí)現(xiàn)模板中的常見語法,比如插值养涮,條件葵硕,循環(huán)等,都是通過JSX渲染模板
2.渲染過程不同
vue在渲染過程中贯吓,會(huì)跟蹤每一個(gè)組件的依賴關(guān)系懈凹,不需要重新渲染整個(gè)組件樹 而react在狀態(tài)被改變時(shí),全部子組件都會(huì)重新渲染悄谐。不過可以通過shouldComponentUpdate這個(gè)生命周期方法進(jìn)行控制
3.數(shù)據(jù)
vue是數(shù)據(jù)可變的介评,雙向綁定,聲明式的寫法 而react是整體的思路是函數(shù)式的爬舰,推崇純組件的方式们陆,數(shù)據(jù)不可變寒瓦,單向數(shù)據(jù)流
19、狀態(tài)碼:
400 Bad Request 語義有誤坪仇,當(dāng)前請(qǐng)求無法被服務(wù)器理解? 或者 請(qǐng)求參數(shù)有誤
403 Forbidden 服務(wù)器已經(jīng)理解請(qǐng)求孵构,但是拒絕執(zhí)行它
404 Not Found
502 Bad Gateway 作為網(wǎng)關(guān)或者代理工作的服務(wù)器嘗試執(zhí)行請(qǐng)求時(shí),從上游服務(wù)器接收到無效的響應(yīng)烟很。
504 Gateway Timeout
20颈墅、防抖與節(jié)流
防抖
等待足夠的空閑時(shí)間后,才執(zhí)行代碼一次 利用定時(shí)器實(shí)現(xiàn)防抖
節(jié)流
一定時(shí)間內(nèi)只執(zhí)行代碼一次 有時(shí)間戳和定時(shí)器兩種簡(jiǎn)單的實(shí)現(xiàn)方式
21雾袱、es6新特性
1.let const塊級(jí)作用域 不會(huì)變量提升 var會(huì)變量提升
2.for(let item of arr){} 循環(huán)數(shù)組 可以用break來終止整個(gè)循環(huán)恤筛,或者continute來跳出當(dāng)前循環(huán),繼續(xù)后面的循環(huán)芹橡;
3.反引號(hào)創(chuàng)建字符串模板 `your num is ${num}`
4.函數(shù)的默認(rèn)參數(shù) function sayHello2(name='dude'){
console.log(`Hello ${name}`);
}
5.拓展參數(shù)
它允許傳遞數(shù)組或者類數(shù)組直接做為函數(shù)的參數(shù)而不用通過apply毒坛。
var people=['Wayou','John','Sherlock'];
//sayHello函數(shù)本來接收三個(gè)單獨(dú)的參數(shù)人妖,人二和人三
function sayHello(people1,people2,people3){
console.log(`Hello ${people1},${people2},${people3}`);
}
//但是我們將一個(gè)數(shù)組以拓展參數(shù)的形式傳遞林说,它能很好地映射到每個(gè)單獨(dú)的參數(shù)
sayHello(...people);//輸出:Hello Wayou,John,Sherlock
// 而在以前煎殷,如果需要傳遞數(shù)組當(dāng)參數(shù),我們需要使用函數(shù)的apply方法
sayHello.apply(null,people);//輸出:Hello Wayou,John,Sherlock
6.新API
"abcde".contains("cd") // true
"abc".repeat(3) // "abcabcabc"
Object.assign
ES6模塊與CommonJS模塊的差異
討論Node加載ES6模塊之前腿箩,必須了解ES6模塊與CommonJS模塊的差異豪直,具體的兩大差異如下。
CommonJS模塊輸出的是一個(gè)值的復(fù)制珠移,ES6模塊輸出的是值的引用弓乙。
CommonJS模塊是運(yùn)行時(shí)加載,ES6模塊是編譯時(shí)輸出接口钧惧。
第二個(gè)差異是因?yàn)镃ommonJS加載的是一個(gè)對(duì)象(即module.exports屬性)暇韧,該對(duì)象只有在腳本運(yùn)行結(jié)束時(shí)才會(huì)生成。而ES6模塊不是對(duì)象浓瞪,它的對(duì)外接口只是一種靜態(tài)定義懈玻,在代碼靜態(tài)解析階段就會(huì)生成。
22乾颁、filter() let arr2 = arr1.filter(item => item.age > 20);
filter()方法:主要用于過濾篩選數(shù)組涂乌,數(shù)組filter后,返回的結(jié)果為新的數(shù)組,不會(huì)改變?cè)瓟?shù)組的值钮孵。
find() 主要用于查找數(shù)組的數(shù)據(jù)骂倘,只要查找到一條符合條件的數(shù)據(jù),直接返回巴席,不會(huì)再繼續(xù)查找下去历涝。
23、Array.prototype.filter的實(shí)現(xiàn)
Array.prototype.filter = function(cb, context){
? context = context || this;? //確定上下文,默認(rèn)為this
? var len = this.length;? //數(shù)組的長(zhǎng)度
? var r = [];? //最終將返回的結(jié)果數(shù)組
? for(var i = 0; i < len; i++){
? ? if(cb.call(context, this[i], i, this)){? //filter回調(diào)函數(shù)的三個(gè)參數(shù):元素值荧库,元素索引堰塌,原數(shù)組
? ? ? r.push(this[i]);
? ? }
? }
? return r;
};
24、存儲(chǔ)
數(shù)據(jù)上的生命周期的不同
Cookie 一般由服務(wù)器生成分衫,可設(shè)置失效時(shí)間场刑,如果在瀏覽器端生成cookie,默認(rèn)是關(guān)閉后失效蚪战。
localStorage 除非被永久清除牵现,否則永久保存。
sessionStorage 僅在當(dāng)前會(huì)話會(huì)有效邀桑,關(guān)閉頁面或?yàn)g覽器后被清除
存放數(shù)據(jù)的大小不同
Cookie 一般為4kb
localStorage 和 sessionStorage 一般為5mb
與服務(wù)器端通信不同
Cookie 每次都會(huì)攜帶HTTP頭中瞎疼,如果使用cookie保存過多數(shù)據(jù)會(huì)帶來性能問題
localStorage 和 sessionStorage 僅在客戶端(即瀏覽器)中保存,不參與和服務(wù)器的通信壁畸。
易用性
Cookie 需要程序員自己來封裝贼急,原生的cookie接口不夠友好
localStorage 和 sessionStorage 原生接口可以接受,可以封裝來對(duì)Object和Array有更好的支持捏萍。
25太抓、緩存
緩存分為
1. 服務(wù)端側(cè)如CDN緩存
其目的是通過在現(xiàn)有的Internet中增加一層新的網(wǎng)絡(luò)架構(gòu),將網(wǎng)站的內(nèi)容發(fā)布到最接近用戶的網(wǎng)絡(luò)"邊緣"令杈,使用戶可 以就近取得所需的內(nèi)容走敌,解決Internet網(wǎng)絡(luò)擁塞狀況膊爪,提高用戶訪問網(wǎng)站的響應(yīng)速度膳灶。從技術(shù)上全面解決由于網(wǎng)絡(luò)帶寬小、用戶訪問量大、網(wǎng)點(diǎn)分布不均等 原因给赞,解決用戶訪問網(wǎng)站的響應(yīng)速度慢的根本原因。
2. 客戶端緩存就是指瀏覽器緩存
瀏覽器緩存分為強(qiáng)緩存和協(xié)商緩存
? ? 強(qiáng)緩存:瀏覽器在加載資源時(shí)矫户,先根據(jù)這個(gè)資源的一些http header判斷它是否命中強(qiáng)緩存片迅,強(qiáng)緩存如果命中,瀏覽器直接從自己的緩存中讀取資源皆辽,不會(huì)發(fā)請(qǐng)求到服務(wù)器柑蛇。比如某個(gè)css文件,如果瀏覽器在加載它所在的網(wǎng)頁時(shí)驱闷,這個(gè)css文件的緩存配置命中了強(qiáng)緩存耻台,瀏覽器就直接從緩存中加載這個(gè)css,連請(qǐng)求都不會(huì)發(fā)送到網(wǎng)頁所在服務(wù)器空另;
? 協(xié)商緩存:當(dāng)強(qiáng)緩存沒有命中的時(shí)候盆耽,瀏覽器一定會(huì)發(fā)送一個(gè)請(qǐng)求到服務(wù)器,通過服務(wù)器端依據(jù)資源的另外一些http header驗(yàn)證這個(gè)資源是否命中協(xié)商緩存,如果協(xié)商緩存命中摄杂,服務(wù)器會(huì)將這個(gè)請(qǐng)求返回(304)坝咐,但是不會(huì)返回這個(gè)資源的數(shù)據(jù),而是告訴客戶端可以直接從緩存中加載這個(gè)資源析恢,于是瀏覽器就又會(huì)從自己的緩存中去加載這個(gè)資源墨坚;若未命中請(qǐng)求,則將資源返回客戶端映挂,并更新本地緩存數(shù)據(jù)(200)泽篮。
強(qiáng)緩存與協(xié)商緩存區(qū)別:強(qiáng)緩存不發(fā)請(qǐng)求到服務(wù)器,協(xié)商緩存會(huì)發(fā)請(qǐng)求到服務(wù)器柑船。
設(shè)置緩存
1. html Meta標(biāo)簽控制緩存 CONTENT="no-cache"
2.HTTP頭信息控制緩存是通過Expires(強(qiáng)緩存)咪辱、Cache-control(強(qiáng)緩存)、Last-Modified/If-Modified-Since(協(xié)商緩存)椎组、Etag/If-None-Match(協(xié)商緩存)實(shí)現(xiàn)
26油狂、promise弊端
arr.slice(a, b); // 不包括結(jié)束位置 不改變?cè)瓟?shù)組的值
arr.splice(a, b, c, d); // 會(huì)改變?cè)瓟?shù)組
27、eventloop機(jī)制
主線程從“任務(wù)隊(duì)列”中讀取事件寸癌,這個(gè)過程是循環(huán)不斷的专筷,所以整個(gè)的這種運(yùn)行機(jī)制又稱為event loop(事件循環(huán))
28、$attrs概念: 包含了父作用域中不作為 prop 被識(shí)別 (且獲取) 的特性綁定 (class 和 style 除外)蒸苇。
$listeners概念:包含了父作用域中的 (不含 .native 修飾器的) v-on 事件監(jiān)聽磷蛹。
29、Promise.then() 微任務(wù)定義之后便會(huì)立即執(zhí)行 會(huì)在當(dāng)前事件循環(huán)末尾中執(zhí)行溪烤,而settimeout宏任務(wù)中的任務(wù)是在下一次事件循環(huán)中執(zhí)行
30味咳、https和http
http請(qǐng)求頭有哪些字段
https相對(duì)于http的劣勢(shì)是,https建立連接需要多次握手檬嘀,而且還要進(jìn)行RSA加密解密槽驶。http是用明文傳輸,在傳輸過程中鸳兽,我們的信息可能會(huì)被篡改掂铐,或者會(huì)被第三方截取插入一些別的信息,比如說廣告植入揍异,這嚴(yán)重影響了用戶體驗(yàn)全陨。
HTTPS在傳輸?shù)倪^程中會(huì)涉及到三個(gè)密鑰:
服務(wù)器端的公鑰和私鑰,用來進(jìn)行非對(duì)稱加密
客戶端生成的隨機(jī)密鑰衷掷,用來進(jìn)行對(duì)稱加密
一個(gè)HTTPS請(qǐng)求實(shí)際上包含了兩次HTTP傳輸辱姨,可以細(xì)分為8步。
1.客戶端向服務(wù)器發(fā)起HTTPS請(qǐng)求戚嗅,連接到服務(wù)器的443端口
2.服務(wù)器端有一個(gè)密鑰對(duì)雨涛,即公鑰和私鑰枢舶,是用來進(jìn)行非對(duì)稱加密使用的,服務(wù)器端保存著私鑰镜悉,不能將其泄露祟辟,公鑰可以發(fā)送給任何人。
3.服務(wù)器將自己的公鑰發(fā)送給客戶端侣肄。
4.客戶端收到服務(wù)器端的證書之后旧困,會(huì)對(duì)證書進(jìn)行檢查,驗(yàn)證其合法性稼锅,如果發(fā)現(xiàn)發(fā)現(xiàn)證書有問題吼具,那么HTTPS傳輸就無法繼續(xù)。嚴(yán)格的說矩距,這里應(yīng)該是驗(yàn)證服務(wù)器發(fā)送的數(shù)字證書的合法性拗盒,關(guān)于客戶端如何驗(yàn)證數(shù)字證書的合法性,下文會(huì)進(jìn)行說明锥债。如果公鑰合格陡蝇,那么客戶端會(huì)生成一個(gè)隨機(jī)值,這個(gè)隨機(jī)值就是用于進(jìn)行對(duì)稱加密的密鑰哮肚,我們將該密鑰稱之為client key登夫,即客戶端密鑰,這樣在概念上和服務(wù)器端的密鑰容易進(jìn)行區(qū)分允趟。然后用服務(wù)器的公鑰對(duì)客戶端密鑰進(jìn)行非對(duì)稱加密恼策,這樣客戶端密鑰就變成密文了,至此潮剪,HTTPS中的第一次HTTP請(qǐng)求結(jié)束涣楷。
5.客戶端會(huì)發(fā)起HTTPS中的第二個(gè)HTTP請(qǐng)求,將加密之后的客戶端密鑰發(fā)送給服務(wù)器抗碰。
6.服務(wù)器接收到客戶端發(fā)來的密文之后狮斗,會(huì)用自己的私鑰對(duì)其進(jìn)行非對(duì)稱解密,解密之后的明文就是客戶端密鑰改含,然后用客戶端密鑰對(duì)數(shù)據(jù)進(jìn)行對(duì)稱加密情龄,這樣數(shù)據(jù)就變成了密文。
7.然后服務(wù)器將加密后的密文發(fā)送給客戶端捍壤。
8.客戶端收到服務(wù)器發(fā)送來的密文,用客戶端密鑰對(duì)其進(jìn)行對(duì)稱解密鞍爱,得到服務(wù)器發(fā)送的數(shù)據(jù)鹃觉。這樣HTTPS中的第二個(gè)HTTP請(qǐng)求結(jié)束,整個(gè)HTTPS傳輸完成睹逃。
HTTPS的安全性主要依賴于對(duì)數(shù)字證書的驗(yàn)證以及非對(duì)稱加密機(jī)制盗扇,細(xì)看步驟3)祷肯,客戶端具體是如何判斷證書的合法性的?
先來看看數(shù)字證書都有哪些內(nèi)容
Issuer--證書的發(fā)布機(jī)構(gòu)
發(fā)布證書的機(jī)構(gòu)疗隶,指明證書是哪個(gè)公司創(chuàng)建的(并不是指使用證書的公司)佑笋。出了問題具體的頒發(fā)機(jī)構(gòu)是要負(fù)責(zé)的
Valid from,Valid to--證書的有效期
證書的使用期限斑鼻。過了這個(gè)期限證書就會(huì)作廢蒋纬,不能使用。
Public key--公鑰
剛開始的時(shí)候介紹過公鑰的概念坚弱,用于對(duì)消息加密的蜀备。
Subject--主題
證書是頒發(fā)給誰了,一般是個(gè)人或公司名稱或機(jī)構(gòu)名稱或公司網(wǎng)站的網(wǎng)址荒叶。
Signature algorithm--簽名所使用的算法
數(shù)字證書的數(shù)字簽名所使用的加密算法碾阁,根據(jù)這個(gè)算法可以對(duì)指紋解密。指紋加密的結(jié)果就是數(shù)字簽名些楣。
Thumbprint脂凶,Thumbprint algorithm--指紋以及指紋算法(一種HASH算法)
指紋和指紋算法會(huì)使用證書機(jī)構(gòu)的私鑰加密后和證書放在一起。主要用來保證證書的完整性愁茁,確保證書沒有修改過蚕钦。使用者在打開證書時(shí)根據(jù)指紋算法計(jì)算證書的hash值,和剛開始的值一樣埋市,則表示沒有被修改過冠桃。
a)
繞了一大圈,問題回來了道宅,客戶端如何檢測(cè)數(shù)字證書是合法的并是所要請(qǐng)求的公司的食听?
首先應(yīng)用程序讀取證書中的Issuer(發(fā)布機(jī)構(gòu)),然后會(huì)在操作系統(tǒng)或?yàn)g覽器內(nèi)置的受信任的發(fā)布機(jī)構(gòu)中去找該機(jī)構(gòu)的證書(為什么操作系統(tǒng)會(huì)有受信任機(jī)構(gòu)的證書污茵?先看完這個(gè)流程再來回答)樱报。如果找不到就說明證書是水貨,證書有問題泞当,程序給錯(cuò)誤信息迹蛤。如果找到了,或用戶確認(rèn)使用該證書襟士。就會(huì)拿上級(jí)證書的公鑰盗飒,解密本級(jí)證書,得到數(shù)字指紋陋桂。然后對(duì)本級(jí)證書的公鑰進(jìn)行數(shù)字摘要算法(證書中提供的指紋加密算法)計(jì)算結(jié)果逆趣,與解密得到的指紋對(duì)比。如果一樣嗜历,說明證書沒有被修改過宣渗。公鑰可以放心使用抖所,可以開始握手通信了。
b)
接下來解答操作系統(tǒng)為什么會(huì)有證書發(fā)布機(jī)構(gòu)的證書痕囱?
其實(shí)證書發(fā)布機(jī)構(gòu)除了給別人發(fā)布證書外田轧,自己也有自己的證書。在操作系統(tǒng)安裝好時(shí)鞍恢,受信任的證書發(fā)布機(jī)構(gòu)的數(shù)字證書就已經(jīng)被微軟安裝在操作系統(tǒng)中了傻粘,根據(jù)一些權(quán)威安全機(jī)構(gòu)的評(píng)估,選取一些信譽(yù)很好并且通過一定安全認(rèn)證的證書發(fā)布機(jī)構(gòu)有序,把這些證書默認(rèn)安裝在操作系統(tǒng)中并設(shè)為信任的數(shù)字證書抹腿。發(fā)布機(jī)構(gòu)持有與自己數(shù)字證書對(duì)應(yīng)的私鑰,會(huì)用這個(gè)私鑰加密所有他發(fā)布的證書及指紋整體作為數(shù)字簽名旭寿。
c)
步驟4)中客戶端生成隨機(jī)數(shù)并用公鑰加密,讓服務(wù)端用私鑰解密來確保對(duì)方是否真的持有私鑰盅称。但是肩祥,黑客也可以發(fā)送字符串讓服務(wù)器用私鑰加密,并得到加密后的信息缩膝,從而找到規(guī)律混狠,導(dǎo)致私鑰的安全性下降。如何解決疾层?
服務(wù)端并不是真的加密這個(gè)字符串将饺,而是把字符串進(jìn)行hash計(jì)算后再進(jìn)行加密后發(fā)送給客戶端⊥蠢瑁客戶端收到后再解密這個(gè)hash值與原來字符串的hash值對(duì)比予弧,從而確定對(duì)方是否持有私鑰。
d)
在通信的過程中湖饱,黑客可以截獲加密內(nèi)容掖蛤,雖不能理解具體內(nèi)容,但可以搗亂井厌,修改內(nèi)容或重復(fù)發(fā)送該內(nèi)容蚓庭,如何解決?
給通信的內(nèi)容加版本號(hào)或隨機(jī)值仅仆,如果接收到版本號(hào)或隨機(jī)值不相同的信息器赞,雙方立刻停止通信。若一直搗亂就無法正常通信墓拜,因?yàn)橛腥丝刂屏四愕穆酚善魅梢葬槍?duì)你。所以一些對(duì)于安全性較強(qiáng)的部門來說就不使用公網(wǎng)撮弧,而是內(nèi)部網(wǎng)絡(luò)潘懊,一般不會(huì)被破環(huán)通信。
跨域
https://www.it610.com/article/1296513648377798656.htm
https://www.cnblogs.com/sdcs/p/8484905.html
1贿衍、 通過jsonp跨域
2授舟、 document.domain + iframe跨域
3、 location.hash + iframe
4贸辈、 window.name + iframe跨域
5释树、 postMessage跨域
6、 跨域資源共享(CORS)?普通跨域請(qǐng)求:只服務(wù)端設(shè)置Access-Control-Allow-Origin即可擎淤,前端無須設(shè)置奢啥,若要帶cookie請(qǐng)求:前后端都需要設(shè)置。由于同源策略的限制嘴拢,所讀取的cookie為跨域請(qǐng)求接口所在域的cookie桩盲,而非當(dāng)前頁。如果想實(shí)現(xiàn)當(dāng)前頁cookie的寫入席吴,可參考下文:七赌结、nginx反向代理中設(shè)置proxy_cookie_domain 和 八、NodeJs中間件代理中cookieDomainRewrite參數(shù)的設(shè)置孝冒。
7柬姚、 nginx代理跨域
8、 nodejs中間件代理跨域
9庄涡、 WebSocket協(xié)議跨域
簡(jiǎn)單請(qǐng)求和復(fù)雜請(qǐng)求
這兩種請(qǐng)求的區(qū)別主要在于是否會(huì)觸發(fā)CORS(Cross-Origin Resource Sharing)預(yù)檢請(qǐng)求量承。
1)簡(jiǎn)單請(qǐng)求
請(qǐng)求方法是以下三種方法之一:
HEAD
GET
POST
HTTP的頭信息修改不超出以下幾種字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三個(gè)值application/x-www-form-urlencoded、multipart/form-data穴店、text/plain
不能為XMLHttpRequestUpdate注冊(cè)監(jiān)聽器撕捍,XMLHttpRequestUpload 對(duì)象可以使用 XMLHttpRequest.upload 屬性訪問
請(qǐng)求中沒有使用readableStream對(duì)象
復(fù)雜請(qǐng)求在正式請(qǐng)求前都會(huì)有CORS預(yù)檢請(qǐng)求,在瀏覽器中都能看到有OPTIONS請(qǐng)求迹鹅,用于向服務(wù)器請(qǐng)求權(quán)限信息的卦洽。
復(fù)雜請(qǐng)求發(fā)送真正的請(qǐng)求前, 會(huì)先發(fā)送一個(gè)方法為OPTIONS的預(yù)請(qǐng)求(preflight request), 用于試探服務(wù)端是否能接受真正的請(qǐng)求,如果options獲得的回應(yīng)是拒絕性質(zhì)的斜棚,比如404\403\500等http狀態(tài)阀蒂,就會(huì)停止post、put等請(qǐng)求的發(fā)出
axios 都是復(fù)雜請(qǐng)求弟蚀,ajax 可以是簡(jiǎn)單請(qǐng)求
附帶身份憑證的請(qǐng)求
一般而言蚤霞,對(duì)于跨域?XMLHttpRequest或?Fetch?請(qǐng)求,瀏覽器不會(huì)發(fā)送身份憑證信息义钉。如果要發(fā)送憑證信息昧绣,需要設(shè)置?XMLHttpRequest?的某個(gè)特殊標(biāo)志位。如果在發(fā)送請(qǐng)求的時(shí)候捶闸,給xhr 設(shè)置了withCredentials為true夜畴,從而向服務(wù)器發(fā)送?Cookies拖刃,如果服務(wù)端需要向客戶端也發(fā)送cookie的情況,需要服務(wù)器端也返回Access-Control-Allow-Credentials: true響應(yīng)頭信息贪绘。對(duì)于附帶身份憑證的請(qǐng)求兑牡,服務(wù)器不得設(shè)置?Access-Control-Allow-Origin的值為“*”。這是因?yàn)檎?qǐng)求的首部中攜帶了Cookie信息税灌,如果?Access-Control-Allow-Origin的值為“*”均函,請(qǐng)求將會(huì)失敗。而將?Access-Control-Allow-Origin的值設(shè)置為?http://foo.example(請(qǐng)求源)菱涤,則請(qǐng)求將成功執(zhí)行苞也。
判斷數(shù)據(jù)類型:
https://blog.csdn.net/weixin_42259266/article/details/90028388?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control
1. typeof 檢測(cè)基本數(shù)據(jù)類型時(shí)沒有問題,但是當(dāng)其對(duì)引用類型進(jìn)行檢測(cè)時(shí)粘秆,會(huì)返回object如迟,這樣就無法進(jìn)行精準(zhǔn)的判斷,這樣也不足為奇翻擒,因?yàn)樗械膶?duì)象其原型鏈最終都指向了object
2.instanceof只能用來檢測(cè)兩個(gè)對(duì)象是否在一條原型鏈上氓涣,并不能檢測(cè)出對(duì)象的具體類型。
3.constructor?也是存在問題的陋气,比如當(dāng)我們重寫了F的prototype之后劳吠,原有的constructor會(huì)丟失,此時(shí)F的實(shí)例對(duì)象f的constructor也不會(huì)再指向F巩趁,這時(shí)候的constructor會(huì)默認(rèn)指向Object痒玩。
F.prototype = { a: 'test' }; var f = new F(); f.constructor == F;// false议慰,但是f.constructor == Object; // true為什么呢蠢古??别凹?
因?yàn)镕.prototype被重新賦值了 {}草讶,而{}是new Object()的一個(gè)實(shí)例對(duì)象,因此炉菲,new Object()會(huì)把其原型上的constructor傳遞給 {}
因此堕战,為了規(guī)范,在重寫對(duì)象原型時(shí)一般都需要重新給constructor賦值拍霜,以保證實(shí)例對(duì)象的類型不被改寫嘱丢。
4.Object.prototype.toString?
toString 方法默認(rèn)返回其調(diào)用者的具體類型,更嚴(yán)格的講是toString運(yùn)行時(shí)祠饺,this指向的對(duì)象類型越驻。但是需要注意的是,必須要通過Object.prototype.toString這種方法來查找,不能直接使用toString缀旁,從原型鏈的角度講记劈,所有對(duì)象的原型鏈最終都指向了Object,按照J(rèn)S變量查找規(guī)則诵棵,其他對(duì)象也是可以直接訪問到Object的toString方法的抠蚣,但是事實(shí)上,大部分對(duì)象都已經(jīng)實(shí)現(xiàn)了自身的toString方法履澳,這樣就可能導(dǎo)致Object的toString被終止查找,所以我們使用call方法來強(qiáng)制執(zhí)行Object的toString方法怀跛。
原型鏈
因?yàn)槊總€(gè)對(duì)象和原型都有原型距贷,對(duì)象的原型指向原型對(duì)象,
而父的原型又指向父的父吻谋,這種原型層層連接起來的就構(gòu)成了原型鏈忠蝗。
實(shí)例對(duì)象與原型之間的鏈接,叫做原型鏈。
在js里漓拾,繼承機(jī)制是原型繼承阁最。繼承的起點(diǎn)是對(duì)象的原型(Object prototype)。
一切皆為對(duì)象骇两,只要是對(duì)象速种,就會(huì)有proto屬性,該屬性存儲(chǔ)了指向其構(gòu)造的指針低千。
Object prototype也是對(duì)象配阵,其proto指向null。
對(duì)象分為兩種:函數(shù)對(duì)象和普通對(duì)象示血,只有函數(shù)對(duì)象擁有『原型』對(duì)象(prototype)棋傍。
prototype的本質(zhì)是普通對(duì)象。
Function prototype比較特殊难审,是沒有prototype的函數(shù)對(duì)象瘫拣。
new操作得到的對(duì)象是普通對(duì)象。
當(dāng)調(diào)取一個(gè)對(duì)象的屬性時(shí)告喊,會(huì)先在本身查找麸拄,若無,就根據(jù)proto找到構(gòu)造原型葱绒,若無感帅,繼續(xù)往上找。最后會(huì)到達(dá)頂層Object prototype地淀,它的proto指向null失球,均無結(jié)果則返回undefined,結(jié)束。
由proto串起的路徑就是『原型鏈』实苞。
31豺撑、簡(jiǎn)單實(shí)現(xiàn)promise.all
Promise.prototype.all = function (promises) {
? ? return new Promise((resolve, reject) => {
? ? ? ? let count = 0;
? ? ? ? let result = new Array(promises.length);
? ? ? ? for (let i = 0; i < promises.length; i++) {
? ? ? ? ? ? Promise.resolve(promises[i]).then((res) => {
? ? ? ? ? ? ? ? count++;
? ? ? ? ? ? ? ? result[i] = res;
? ? ? ? ? ? ? ? if (count === promises.length) {
? ? ? ? ? ? ? ? ? ? return resolve(result);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }).catch((err) => {
? ? ? ? ? ? ? ? reject('err');
? ? ? ? ? ? });
? ? ? ? }
? ? })
}
32、淺拷貝和深拷貝
淺拷貝如Object.assign()的時(shí)候如果數(shù)據(jù)是基本數(shù)據(jù)類型黔牵,那么就如同直接賦值那種聪轿,會(huì)拷貝其本身,如果除了基本數(shù)據(jù)類型之外還有一層對(duì)象猾浦,那么對(duì)于淺拷貝而言就只能拷貝其引用陆错,對(duì)象的改變會(huì)反應(yīng)到拷貝對(duì)象上;但是深拷貝如JSON.parse(JSON.stringify())就會(huì)拷貝多層金赦,即使是嵌套了對(duì)象音瓷,也會(huì)都拷貝出來。
實(shí)現(xiàn)深拷貝
function extendDeep(parent, child) {
? ? let i,
? ? proxy;
? ? proxy = JSON.stringify(parent);
? ? proxy = JSON.parse(proxy);
? ? child = child || {};
? ? for(i in proxy) {
? ? ? ? if(proxy.hasOwnProperty(i)) {
? ? ? ? ? ? child[i] = proxy[i];
? ? ? ? }
? ? }
? ? proxy = null;
? ? return child;
}
33夹抗、鏈接取值
function GetQueryString(name)
{
let reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
let r = window.location.search.substr(1).match(reg);
if(r!=null)return unescape(r[2]); return null;
}
GetQueryString('open_id')
34绳慎、bind函數(shù)并手寫
Function.prototype.bind
bind() 函數(shù)會(huì)創(chuàng)建一個(gè)新綁定函數(shù),綁定函數(shù)與被調(diào)函數(shù)具有相同的函數(shù)體(在 ECMAScript 5 中)漠烧。調(diào)用綁定函數(shù)通常會(huì)導(dǎo)致執(zhí)行包裝函數(shù) 綁定函數(shù)也可以使用new運(yùn)算符構(gòu)造:這樣做就好像已經(jīng)構(gòu)造了目標(biāo)函數(shù)一樣杏愤。提供的this值將被忽略,而前置參數(shù)將提供給模擬函數(shù)
bind有如下三個(gè)功能點(diǎn):
改變?cè)瘮?shù)的 this 指向已脓,即綁定上下文珊楼,返回原函數(shù)的拷貝
當(dāng)綁定函數(shù)被調(diào)用時(shí),bind的額外參數(shù)將置于實(shí)參之前傳遞給被綁定的方法摆舟。
注意亥曹,一個(gè)綁定函數(shù)也能使用new操作符創(chuàng)建對(duì)象,這種行為就像把原函數(shù)當(dāng)成構(gòu)造器,thisArg 參數(shù)無效恨诱。也就是 new 操作符修改 this 指向的優(yōu)先級(jí)更高媳瞪。
Function.prototype.bindFn = function bind(thisArg) {
? ? if (typeof this !== 'function') {
? ? ? ? throw new TypeError(this + 'must be a function');
? ? }
? ? // 存儲(chǔ)函數(shù)本身
? ? var self = this;
? ? // 去除thisArg的其他參數(shù) 轉(zhuǎn)成數(shù)組
? ? var args = [].slice.call(arguments, 1);
? ? return function () {
? ? ? ? // bind返回的函數(shù) 的參數(shù)轉(zhuǎn)成數(shù)組
? ? ? ? var boundArgs = [].slice.call(arguments);
? ? ? ? // apply修改this指向,把兩個(gè)函數(shù)的參數(shù)合并傳給self函數(shù)照宝,并執(zhí)行self函數(shù)蛇受,返回執(zhí)行結(jié)果
? ? ? ? return self.apply(thisArg, args.concat(boundArgs));
? ? }
}
35、獲取數(shù)組最大值的下標(biāo)
Math.max(...arr)
function getMaxIndex(arr) {
? ? let max = arr[0];
? ? let index = 0;
? ? for (let i = 0; i < arr.length; i++) {
? ? ? ? if (max < arr[i]) {
? ? ? ? ? ? max = arr[i];
? ? ? ? ? ? index = i;
? ? ? ? }
? ? }
? ? return index;
}
36厕鹃、數(shù)組去重
? ? 1.ES6的set函數(shù) return [...new Set(arr)]
? ?2.把數(shù)組的值轉(zhuǎn)化成對(duì)象的屬性 function unique(arr) {
? ? let json = {};
? ? let newArr = [];
? ? for (let i = 0; i < arr.length; i++) {
? ? ? ? if (!json[arr[i]]) {
? ? ? ? ? ? newArr.push(arr[i]);
? ? ? ? ? ? json[arr[i]] = 1;
? ? ? ? }
? ? ? ? else {
? ? ? ? ? ? json[arr[i]]++;
? ? ? ? }
? ? }
? ? return newArr;
}
37兢仰、冒泡排序
function bubbleSort(arr){
? ? for(var i = 0;i<arr.length;i++){
? ? ? ? for(var j=arr.length-1;j>i;j--){
? ? ? ? ? ? if(arr[j]<arr[j-1]){
? ? ? ? ? ? ? ? var temp = arr[j]
? ? ? ? ? ? ? ? arr[j] = arr[j-1]
? ? ? ? ? ? ? ? arr[j-1] = temp
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? return arr
}
38、快排
var quickSort = function(arr) {
if (arr.length <= 1) { return arr; }
var pivotIndex = Math.floor(arr.length / 2);
var pivot = arr.splice(pivotIndex, 1)[0];
var left = [];
var right = [];
for (var i = 0; i < arr.length; i++){
if (arr[i] < pivot) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
return quickSort(left).concat([pivot], quickSort(right));
};
39剂碴、求dom樹的最大深度
? ? const getDepth = node => {
? ? ? if (!node.children || node.children.length === 0) {
? ? ? ? return 1
? ? ? }
? ? ? const maxChildrenDepth = [...node.children].map(v => getDepth(v))
? ? ? return 1 + Math.max(...maxChildrenDepth)
? ? }
? ? console.log(getDepth(document.documentElement))把将;
怎么去設(shè)計(jì)一個(gè)組件封裝?
1忆矛、組件封裝的目的是為了重用察蹲,提高開發(fā)效率和代碼質(zhì)量
2请垛、低耦合,單一職責(zé)洽议,可復(fù)用性宗收,可維護(hù)性
3、前端組件化設(shè)計(jì)思路
display:flex;
flex-wrap:wrap;
justify-content: space-between
常見web安全及防護(hù)原理
sql注入原理
就是通過把SQL命令插入到Web表單遞交或輸入域名或頁面請(qǐng)求的查詢字符串亚兄,最終達(dá)到欺騙服務(wù)器執(zhí)行惡意的SQL命令混稽。
總的來說有以下幾點(diǎn):
1.永遠(yuǎn)不要信任用戶的輸入,要對(duì)用戶的輸入進(jìn)行校驗(yàn)审胚,可以通過正則表達(dá)式匈勋,或限制長(zhǎng)度,對(duì)單引號(hào)和雙"-"進(jìn)行轉(zhuǎn)換等菲盾。
2.永遠(yuǎn)不要使用動(dòng)態(tài)拼裝SQL颓影,可以使用參數(shù)化的SQL或者直接使用存儲(chǔ)過程進(jìn)行數(shù)據(jù)查詢存取。
3.永遠(yuǎn)不要使用管理員權(quán)限的數(shù)據(jù)庫連接懒鉴,為每個(gè)應(yīng)用使用單獨(dú)的權(quán)限有限的數(shù)據(jù)庫連接。
4.不要把機(jī)密信息明文存放碎浇,請(qǐng)加密或者h(yuǎn)ash掉密碼和敏感的信息临谱。
XSS原理及防范
Xss(cross-site scripting)攻擊指的是攻擊者往Web頁面里插入惡意 html標(biāo)簽或者javascript代碼。比如:攻擊者在論壇中放一個(gè)看似安全的鏈接奴璃,騙取用戶點(diǎn)擊后悉默,竊取cookie中的用戶私密信息;或者攻擊者在論壇中加一個(gè)惡意表單苟穆,
當(dāng)用戶提交表單的時(shí)候抄课,卻把信息傳送到攻擊者的服務(wù)器中,而不是用戶原本以為的信任站點(diǎn)雳旅。
XSS防范方法
首先代碼里對(duì)用戶輸入的地方和變量都需要仔細(xì)檢查長(zhǎng)度和對(duì)”<”,”>”,”;”,”’”等字符做過濾跟磨;其次任何內(nèi)容寫到頁面之前都必須加以encode,避免不小心把html tag 弄出來攒盈。這一個(gè)層面做好抵拘,至少可以堵住超過一半的XSS 攻擊。
首先型豁,避免直接在cookie 中泄露用戶隱私僵蛛,例如email、密碼等等迎变。
其次充尉,通過使cookie 和系統(tǒng)ip 綁定來降低cookie 泄露后的危險(xiǎn)。這樣攻擊者得到的cookie 沒有實(shí)際價(jià)值衣形,不可能拿來重放驼侠。
如果網(wǎng)站不需要再瀏覽器端對(duì)cookie 進(jìn)行操作,可以在Set-Cookie 末尾加上HttpOnly 來防止javascript 代碼直接獲取cookie 。
盡量采用POST 而非GET 提交表單
如果不需要用戶輸入 HTML泪电,可以直接對(duì)用戶的輸入進(jìn)行 HTML 轉(zhuǎn)義
當(dāng)用戶需要輸入 HTML 代碼時(shí):更好的方法可能是般妙,將用戶的輸入使用 HTML 解析庫進(jìn)行解析,獲取其中的數(shù)據(jù)相速。然后根據(jù)用戶原有的標(biāo)簽屬性碟渺,重新構(gòu)建 HTML 元素樹。構(gòu)建的過程中突诬,所有的標(biāo)簽苫拍、屬性都只從白名單中拿取。
CSRF(Cross-site request forgery)跨站請(qǐng)求偽造:攻擊者誘導(dǎo)受害者進(jìn)入第三方網(wǎng)站旺隙,在第三方網(wǎng)站中绒极,向被攻擊網(wǎng)站發(fā)送跨站請(qǐng)求。利用受害者在被攻擊網(wǎng)站已經(jīng)獲取的注冊(cè)憑證蔬捷,繞過后臺(tái)的用戶驗(yàn)證垄提,達(dá)到冒充用戶對(duì)被攻擊的網(wǎng)站執(zhí)行某項(xiàng)操作的目的。
CSRF 可以簡(jiǎn)單理解為:攻擊者盜用了你的身份周拐,以你的名義發(fā)送惡意請(qǐng)求铡俐,容易造成個(gè)人隱私泄露以及財(cái)產(chǎn)安全。
如何防范CSRF攻擊?
1.添加驗(yàn)證碼(體驗(yàn)不好)
2.判斷請(qǐng)求的來源:檢測(cè)Referer(并不安全妥粟,Referer可以被更改)
3.使用Token(主流)
Javascript垃圾回收方法
標(biāo)記清除(mark and sweep)
這是JavaScript最常見的垃圾回收方式审丘,當(dāng)變量進(jìn)入執(zhí)行環(huán)境的時(shí)候,比如函數(shù)中聲明一個(gè)變量勾给,垃圾回收器將其標(biāo)記為“進(jìn)入環(huán)境”滩报,當(dāng)變量離開環(huán)境的時(shí)候(函數(shù)執(zhí)行結(jié)束)將其標(biāo)記為“離開環(huán)境”。
垃圾回收器會(huì)在運(yùn)行的時(shí)候給存儲(chǔ)在內(nèi)存中的所有變量加上標(biāo)記播急,然后去掉環(huán)境中的變量以及被環(huán)境中變量所引用的變量(閉包)脓钾,在這些完成之后仍存在標(biāo)記的就是要?jiǎng)h除的變量了
引用計(jì)數(shù)(reference counting)
在低版本IE中經(jīng)常會(huì)出現(xiàn)內(nèi)存泄露,很多時(shí)候就是因?yàn)槠洳捎靡糜?jì)數(shù)方式進(jìn)行垃圾回收旅择。引用計(jì)數(shù)的策略是跟蹤記錄每個(gè)值被使用的次數(shù)惭笑,當(dāng)聲明了一個(gè)變量并將一個(gè)引用類型賦值給該變量的時(shí)候這個(gè)值的引用次數(shù)就加1遗锣,如果該變量的值變成了另外一個(gè)砰苍,則這個(gè)值得引用次數(shù)減1,當(dāng)這個(gè)值的引用次數(shù)變?yōu)?的時(shí) 候对蒲,說明沒有變量在使用柱蟀,這個(gè)值沒法被訪問了川蒙,因此可以將其占用的空間回收,這樣垃圾回收器會(huì)在運(yùn)行的時(shí)候清理掉引用次數(shù)為0的值占用的空間长已。
在IE中雖然JavaScript對(duì)象通過標(biāo)記清除的方式進(jìn)行垃圾回收畜眨,但BOM與DOM對(duì)象卻是通過引用計(jì)數(shù)回收垃圾的昼牛,
也就是說只要涉及BOM及DOM就會(huì)出現(xiàn)循環(huán)引用問題。
重排重繪
當(dāng)DOM的變化引發(fā)了元素幾何屬性的變化康聂,比如改變?cè)氐膶捀叻〗。氐奈恢茫瑢?dǎo)致瀏覽器不得不重新計(jì)算元素的幾何屬性恬汁,并重新構(gòu)建渲染樹伶椿,這個(gè)過程稱為“重排”。完成重排后氓侧,要將重新構(gòu)建的渲染樹渲染到屏幕上脊另,這個(gè)過程就是“重繪”。
簡(jiǎn)單的說约巷,重排負(fù)責(zé)元素的幾何屬性更新偎痛,重繪負(fù)責(zé)元素的樣式更新。而且独郎,重排必然帶來重繪踩麦,但是重繪未必帶來重排。比如氓癌,改變某個(gè)元素的背景靖榕,這個(gè)就不涉及元素的幾何屬性,所以只發(fā)生重繪顽铸。
h5和小程序的區(qū)別
https://www.douban.com/note/707405724/
一、運(yùn)行環(huán)境
1.1 H5 既然是網(wǎng)頁料皇,那么依賴的外殼主要是瀏覽器谓松,因此只要有瀏覽器,就可以使用践剂。比如手機(jī)內(nèi)置的瀏覽器鬼譬,APP 的 web-view 組件,以及小程序提供的 web-view 組件逊脯,都可以打開 H5 頁面优质。
1.2 小程序只能依賴微信客戶端,也就是說只能在微信里打開军洼。那么巩螃,如果你的產(chǎn)品需要通過短信通知用戶帶上訪問地址,就無法用小程序?qū)崿F(xiàn)了匕争。而 H5 頁面避乏,則可以在短信正文中直接用手機(jī)內(nèi)置瀏覽器打開。
二甘桑、系統(tǒng)權(quán)限
2.1這里的系統(tǒng)權(quán)限拍皮,可以理解為隱私級(jí)別比較高的歹叮,如通訊錄,或能調(diào)用硬件的铆帽,比如藍(lán)牙功能等咆耿。從這個(gè)角度看,H5 本身可以說幾乎是沒有什么系統(tǒng)權(quán)限的爹橱。雖然也有攝像頭之類的接口萨螺,但是重度依賴瀏覽器能力,兼容性有限宅荤。
2.2.而小程序屑迂,由于依賴微信客戶端本身,所以微信小程序團(tuán)隊(duì)將客戶端的很多能力開放給了小程序環(huán)境冯键,當(dāng)然惹盼,前提是你給微信也授權(quán)了相關(guān)的能力,比如允許訪問麥克風(fēng)惫确,允許訪問相冊(cè)等手报。
三、能力限制
1改化、前面提到了系統(tǒng)權(quán)限層面的差異掩蛤,其實(shí)也是一種能力限制。除此之外陈肛,還有一些能力是微信本身的策略限制的揍鸟,比如 H5 在微信里可以直接分享朋友圈,而小程序目前就只能轉(zhuǎn)發(fā)好友或群句旱。對(duì)于朋友圈阳藻,就只能生成帶小程序碼的圖片發(fā)到朋友圈。
2谈撒、而對(duì)于分享到好友或群腥泥,小程序又提供了卡片式的分享界面,看起來很高端啃匿,信息也多蛔外,并且能追蹤用戶行為。這一點(diǎn)溯乒,H5 又無法做到夹厌。
3、再比如支付能力橙数,小程序只支持微信支付尊流,而 H5 里可以選擇使用其他支付平臺(tái)提供的支付方式。
四灯帮、用戶體驗(yàn)
1崖技、小程序基于微信客戶端實(shí)現(xiàn)逻住,對(duì)解析進(jìn)行了優(yōu)化,并且一旦首次打開小程序迎献,可以直接緩存很多資源瞎访。因此,在使用小程序時(shí)可以明顯感覺很流暢吁恍,接近原生 APP 的體驗(yàn)扒秸。
2、而 H5 本質(zhì)上還是網(wǎng)頁冀瓦,跟之前在 PC 上瀏覽網(wǎng)頁沒區(qū)別伴奥,每次要請(qǐng)求各種圖片樣式資源,在瀏覽器內(nèi)核里渲染翼闽,因此體驗(yàn)會(huì)差一些拾徙。
微信小程序集成了很多原生APP的組件,從體驗(yàn)和頁面流暢度來說感局,都會(huì)比HTML5要優(yōu)秀很多尼啡。 微信小程序相對(duì)于HTML5開發(fā)來說,除了熟悉API需要學(xué)習(xí)成本之外询微,還要學(xué)習(xí)小程序組件崖瞭,布局。 行的速度方面撑毛,傳統(tǒng)HTML5在加載的時(shí)候受限于網(wǎng)絡(luò)環(huán)境书聚,需要順序加載HTML、CSS藻雌、JS寺惫,然后返回?cái)?shù)據(jù),最后渲染頁面顯示在瀏覽器中蹦疑。用戶經(jīng)常需要等待很長(zhǎng)時(shí)間,體驗(yàn)會(huì)受到影響萨驶。相比之下歉摧,小程序的兩個(gè)線程:Appservice Thread和View Thread會(huì)同時(shí)進(jìn)行、并行加載腔呜,甚至Appservice Thread會(huì)更早執(zhí)行叁温,當(dāng)視圖線程加載完,通知Appservice核畴,Appservice 會(huì)把準(zhǔn)備好的數(shù)據(jù)用setData的方法返回給視圖線程膝但。小程序的這種優(yōu)化策略,可以減少用戶的等待時(shí)間谤草、加快小程序的響應(yīng)速度跟束。
js原型鏈以及特點(diǎn)
原型鏈繼承和類繼承莺奸。然后類繼承只繼承了實(shí)例屬性,沒有原型屬性冀宴。原型鏈繼承可以繼承所有灭贷。然后用apply和call怎么繼承原型鏈上的共享屬性?通過空函數(shù)傳值略贮。新建一個(gè)空函數(shù)C甚疟。C實(shí)例化后C的實(shí)例屬性就是空,然后用B的apply/call去繼承C逃延,相當(dāng)于繼承了C的實(shí)例屬性览妖。
typeof null ==== object。? null是一個(gè)只有一個(gè)值的特殊類型揽祥。表示一個(gè)空對(duì)象引用讽膏。
typeof undefined? ===?undefined。? ?undefined?是一個(gè)沒有設(shè)置值的變量盔然。
二叉樹的遍歷主要有三種:
(1)先(根)序遍歷(根左右) 根節(jié)點(diǎn) 左右子樹
(2)中(根)序遍歷(左根右)
(3)后(根)序遍歷(左右根)
JSBridge
讓native可以調(diào)用web的js代碼桅打,讓web可以 “調(diào)用” 原生的代碼。
流程:H5->通過某種方式觸發(fā)一個(gè)url->Native捕獲到url,進(jìn)行分析->原生做處理->Native調(diào)用H5的JSBridge對(duì)象傳遞回調(diào)愈案。
JsBridge之所以能實(shí)現(xiàn)Native與Js相互調(diào)用的功能挺尾,其核心實(shí)現(xiàn)其實(shí)就是:
攔截Url
load url("javascript:js_method()");
先說第二點(diǎn),Native調(diào)用Js站绪,通過加載以javascript:開頭的url即可實(shí)現(xiàn)調(diào)用Js的方法遭铺。這個(gè)很好理解,在web中也是通過這種方式調(diào)用Js的方法的恢准。
然后細(xì)說下第一點(diǎn)的實(shí)現(xiàn):
向body中添加一個(gè)不可見的iframe元素魂挂。通過攔截url的方法來執(zhí)行相應(yīng)的操作,但是頁面本身不能跳轉(zhuǎn)馁筐,所以改變一個(gè)不可見的iframe的src就可以讓webview攔截到url涂召,而用戶是無感知的。
攔截url敏沉。通過shouldOverrideUrlLoading來攔截約定規(guī)則的Url果正,再做具體操作。
304與200讀取緩存的區(qū)別
封裝api
const promisic =function (n) {
? ? returnfunction(t = {}) {
? ? ? ? returnnewPromise((c, r) => {
? ? ? ? ? ? const s = Object.assign(t, {
? ? ? ? ? ? ? ? success: n => {
? ? ? ? ? ? ? ? ? ? c(n)
? ? ? ? ? ? ? ? }, fail: n => {
? ? ? ? ? ? ? ? ? ? r(n)
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? ? ? n(s)
? ? ? ? })
? ? }
}
promisic(wx.getStorage)().then(res=>{
? console.log(res) //成功
}).catch(err=>{
? console.err(err) //失斆顺佟(可省略)
})
// 倒計(jì)時(shí)
function countDown(countTime) {
? let startTime = new Date().getTime();
? let endTime = new Date(countTime).getTime();
? let time = endTime - startTime;
? let day,hour,minute,seconds;
? if (time >= 0) {
? ? day = time/1000/60/60/24;
? hour = time/1000/60/60%24;
? minute = time/1000/60%60;
? seconds = time/1000%60;
? ? this.day = day
? setTimeout(countDown, 1000);
? }
}
// 數(shù)組隨機(jī)抽取
function getRandomEle(arr, num) {
? let newArr = [];
? for (let i = num; i > 0; i--) {
? ? let index = Math.floor(Math.random()*arr.length);
? ? newArr.push(arr[index]);
? ? arr.splice(index, 1);
? }
? return newArr;
}
typeof
https://segmentfault.com/a/1190000018821652
蛇形矩陣
let arr = [
? ? [1,2,3,8],
? ? [4,5,6,9],
? ? [3,4,6,8],
? ? [7,8,9,0]
];
snail = function(arr) {
? var result;
? while (array.length) {
? ? // Steal the first row.
? ? result = (result ? result.concat(array.shift()) : array.shift());
? ? // Steal the right items.
? ? for (var i = 0; i < array.length; i++)
? ? ? result.push(array[i].pop());
? ? // Steal the bottom row.
? ? result = result.concat((array.pop() || []).reverse());
? ? // Steal the left items.
? ? for (var i = array.length - 1; i >= 0; i--)
? ? ? result.push(array[i].shift());
? }
? return result;
}
let result;
snail = function(arr) {
? ? result = result ? result.concat(arr.shift()) : arr.shift();
? ? for(let i = 0; i < arr.length; i++) {
? ? ? ? result.push(arr[i].pop());
? ? }
? ? result = result.concat(arr.pop().reverse());
? ? for(let j = arr.length - 1; j >=0; j--) {
? ? ? ? result.push(arr[j].shift());
? ? }
? ? while(arr.length) {
? ? ? ? snail(arr);
? ? }
? ? return result;
}
let arr = [
? ? [1,2,3,8],
? ? [4,5,6,9],
? ? [3,4,6,8],
? ? [7,8,9,0]
];
實(shí)現(xiàn)EventEmitter類秋泳,常見的on off emmit once
class EventEmitter {
? ? constructor() {
? ? ? ? this.events = {};
? ? }
? ? on(event, callback) {
? ? ? ? if(!this.events[event]) {
? ? ? ? ? ? this.events[event] = [];
? ? ? ? }
? ? ? ? this.events[event].push(callback);
? ? ? ? return this;
? ? }
? ? off(event, callback) {
? ? ? ? let callbacks = this.events[event];
? ? ? ? this.events[event] = callbacks && callbacks.filter(fn => {
? ? ? ? ? ? return fn !== callback;
? ? ? ? });
? ? ? ? return this;
? ? }
? ? emit(event, ...arg) {
? ? ? ? let callbacks = this.events[event];
? ? ? ? callbacks && callbacks.map(fn => {
? ? ? ? ? ? fn(...arg);
? ? ? ? });
? ? ? ? return this;
? ? }
? ? once(event, callback) {
? ? ? ? let only = () => {
? ? ? ? ? ? callback.apply(this, arguments);
? ? ? ? ? ? this.off(event, only);
? ? ? ? }
? ? ? ? this.on(event, only);
? ? ? ? return this;
? ? }
}
構(gòu)造一個(gè)函數(shù):將dom類數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)化成真實(shí)的dom
輸入?yún)?shù)例子:
element類節(jié)點(diǎn)
let json = {
? ? "tag": "div",
? ? "className": ["clearfix", "left"],
? ? "children": [
? ? ? ? "hello word",
? ? ? ? {...node}
? ? ]
}
function creatDom(json) {
? ? let el = document.createElement(json.tag);
? ? if(json.className && json.className.length) {
? ? ? ? el.setAttribute('class', json.className.join(' '));
? ? }
? ? json.children.forEach(child => {
? ? ? ? let childEle = null;
? ? ? ? if(typeof child === 'object') {
? ? ? ? ? ? childEle = creatDom(child);
? ? ? ? }
? ? ? ? else {
? ? ? ? ? ? childEle = document.createTextNode(child);
? ? ? ? }
? ? ? ? el.appendChild(childEle);
? ? });
? ? return el;
}
document.querySelector('body').appendChild(creatDom(json));
abbbac 用棧消除重復(fù)字符串 bbb需要還剩一個(gè)b
function foo(str) {
? let s = []
? const getTop = () => {
? ? return s[s.length - 1]
? }
? Array.prototype.slice.call(str).forEach(ch => {
? ? let top = getTop()
? ? if (top === ch) {
? ? ? s.pop()
? ? } else {
? ? ? s.push(ch)
? ? }
? })
? return s.join('')
}
foo("abbbac");
css實(shí)現(xiàn)鐘擺效果
https://juejin.cn/post/6844903942904610830
transform-origin: center top;// 這里指定起始點(diǎn)為居中攒菠,靠上
animation: swing 5s;// 指定動(dòng)畫的名稱迫皱,與整個(gè)動(dòng)畫的時(shí)間
animation-iteration-count:infinite;//設(shè)置無限擺動(dòng)
animation-timing-function: linear;//指定運(yùn)行的速度曲線,liner表示線性的辖众,即勻速卓起。
.line{width:20px;height:400px;background: red;margin:50pxauto;transform-origin: center top;animation: swing5s;animation-iteration-count:infinite;animation-timing-function: linear;position: relative;}.ball{width:60px;height:60px;border-radius:30px;background: blue;position: absolute;bottom: -60px;left: -20px;}@keyframesswing {0%{transform:rotate(45deg);}25%{transform:rotate(0deg);}50%{transform:rotate(-45deg);}75%{transform:rotate(0deg);}100%{transform:rotate(45deg);}}
<div class="line"><div class=" ball"></div></div>
function foo(node) {
? let queue = [node]
? let ret = []
? let c = 0
? while(queue.length) {
? ? let arr = []
? ? for (let i = 0, len = queue.length; i < len; i++) {
? ? ? node = queue.shift()
? ? ? arr.push(node)
? ? ? if (node.left) {
? ? ? ? queue.push(node.left)
? ? ? }
? ? ? if (node.right) {
? ? ? ? queue.push(node.right)
? ? ? }
? ? }
? ? ret.push(arr)
? }
? return ret
}
react虛擬dom?解釋一下它的工作原理和敬。
Virtual DOM 是一個(gè)輕量級(jí)的 JavaScript 對(duì)象,它最初只是 real DOM 的副本既绩。它是一個(gè)節(jié)點(diǎn)樹概龄,它將元素、它們的屬性和內(nèi)容作為對(duì)象及其屬性饲握。 React 的渲染函數(shù)從 React 組件中創(chuàng)建一個(gè)節(jié)點(diǎn)樹私杜。然后它響應(yīng)數(shù)據(jù)模型中的變化來更新該樹,該變化是由用戶或系統(tǒng)完成的各種動(dòng)作引起的救欧。
Virtual DOM 工作過程有三個(gè)簡(jiǎn)單的步驟衰粹。
1.每當(dāng)?shù)讓訑?shù)據(jù)發(fā)生改變時(shí),整個(gè) UI 都將在 Virtual DOM 描述中重新渲染笆怠。
2.然后計(jì)算之前 DOM 表示與新表示的之間的差異铝耻。
3.完成計(jì)算后,將只用實(shí)際更改的內(nèi)容更新 real DOM蹬刷。
數(shù)據(jù)如何通過 Redux 流動(dòng)
使用 React Hooks 好處是啥瓢捉?
Hooks是 React 16.8 中的新添加內(nèi)容。它們?cè)试S在不編寫類的情況下使用state和其他 React 特性办成。使用 Hooks泡态,可以從組件中提取有狀態(tài)邏輯,這樣就可以獨(dú)立地測(cè)試和重用它迂卢。Hooks 允許咱們?cè)诓桓淖兘M件層次結(jié)構(gòu)的情況下重用有狀態(tài)邏輯某弦,這樣在許多組件之間或與社區(qū)共享 Hooks 變得很容易。
首先而克,Hooks 通常支持提取和重用跨多個(gè)組件通用的有狀態(tài)邏輯靶壮,而無需承擔(dān)高階組件或渲染?props?的負(fù)擔(dān)。Hooks?可以輕松地操作函數(shù)組件的狀態(tài)员萍,而不需要將它們轉(zhuǎn)換為類組件腾降。
Hooks 在類中不起作用,通過使用它們碎绎,咱們可以完全避免使用生命周期方法蜂莉,例如?componentDidMount、componentDidUpdate混卵、componentWillUnmount。相反窖张,使用像useEffect這樣的內(nèi)置鉤子幕随。