1.自我介紹:製作和背誦
2.對方可能提問的問題
3.個人詞彙和英語聽力提升
webpack
webpack的預載入:prefecth和preload【瀏覽器相容問題,所以還是自己動態寫非同步載入比較好,就是用import或者require.ensure來實現模組非同步載入】
import(/* webpackPrefetch: true */ './path/to/LoginModal.js')//會生成 <link rel="prefetch" href="login-modal-chunk.js"> 並追加到頁面頭部:
閒置時間預取 login-modal-chunk.js 檔案只要父 chunk 完成載入,webpack 就會新增 prefetch hint(預取提示)
preload chunk 會在父 chunk 載入時,以並行方式開始載入。prefetch chunk 會在父 chunk 載入結束後開始載入。
preload chunk 具有中等優先順序,並立即下載。prefetch chunk 在瀏覽器閒置時下載。
preload chunk 會在父 chunk 中立即請求,用於當下時刻。prefetch chunk 會用於未來的某個時刻。
import或者require.ensure來實現模組非同步載入:!!!!!!!!!!!
由於 import() 會返回一個 promise,因此它可以和 async 函式一起使用。下面是如何透過 async 函式簡化程式碼:
async function getComponent() {
const { default: _ } = await import('lodash');
return data||{}
}
getComponent().then((data) => {
載入了“lodash”模組後,繼續寫後面的邏輯
});
//在點選事件的收去非同步載入模組,import返回的是一個promise,引數中可以獲取到模組【如果import放在js頭部,不用then,就是同步載入js模組】
button.onclick = e => import(/* webpackChunkName: "print" */ './print').then(module => {
const print = module.default;
print(); // 如果print是一個react的component,那就可以寫成<print >來獲取元件
});
require.ensure用法:
function getAsyncJs(callback){
//如果裡面的require是相同的,這個require.ensure不會再發請求;
//裡面所有的檔案都單獨打包
require.ensure([],function(require){
// require('util.js');
require('../../components/login');
require('../../components/article-edit');
require('../../components/article-list');
require('../../components/article-display');
require('./components/regist');
// require('./components/search-list');//搜尋列表
if(callback){
callback();
}
});
},
使用的時候,直接getAsyncJs(callback函式):這樣callback函式就會在其他的非同步js模組載入完成以後再執行
提取頁面公共模組:方法很多,下面2個方法都可以;方法1疊加“細分模組的懶載入”,可以很靈活地控制包的數量和每個包的大小和載入順序【手動】;方法2可以自動劃分包,防止重複;
1.自己寫common檔案,然後在入口總手動新增公共js檔案的入口,生成一個bound包,然後在所有頁面的公共html上引入這個公共的js包,這個是自己手動靈活的方式;好處是靈活,壞處是需要自己手動抽離寫到common檔案中去
2.新增公共模組外掛設定,能自動提取出所有bound的公共模組和模組的分包;【從 webpack v4 開始,移除了 CommonsChunkPlugin,取而代之的是 optimization.splitChunks。】
具體設定詳見:https://webpack.docschina.org/plugins/split-chunks-plugin/#optimization-splitchunks
可以把公共的模組提取出來避免重複載入,同時對於太大的js檔案,會根據裡面的import的不同js檔案,來進行相應的拆包,比如有三個import的js檔案,分別是a[100k],b[5k],c[1k];
那麼透過對最大包和最小包的大小設定和包的數量的設定,會把a單獨打一個包,b和c合起來打一個包,滿足每個包的大小要求和總體包的個數的要求
optimization: {
splitChunks: {
chunks: 'all'
}
}
模組化最佳實踐:所有的都要用到
1.自定義common模組,放所有頁面必須用到的公共js模組,並作為單獨的js放到html裡面【頁面公共js】
2.設定 optimization,因為有的時候每個頁面都統一用到了某個業務模組,或者大多數頁面用到了某個業務模組;所以得用optimization來進一步細化每個頁面內的“模組數量”和“模組大小”進行限制;也就是“分包”或“程式碼分割”
3.對於頁面的懶載入模組和預載入模組,需要同時用import或require.ensure來非同步載入對應的js模組:【webpack打包的時候把非同步的js都打成了單獨的js檔案,請求伺服器的時候也是請求這些單獨的檔案的快取】
mobx管理react!!!!!!!!!!
node包開發,webpack外掛開發!!!!!!!!!!!!!
git命令重新熟悉
typescript: javascript的一個超集,也就是在ts內寫js完全沒問題
https://www.runoob.com/w3cnote/getting-started-with-typescript.html
1. 型別批註,介面,類【es6】,extends繼承
2....
後端傳流檔案,前端截斷處理????
package.json devdepedence和depedence區別??????
webpack的proxy設定跨域
react-native
restfulapi含義:以http為基礎,透過ajax+JSON實現互動,;url定位資源【URL中只能有名詞而不能有動詞】,get post等定位動作
fetch或axios的ajax庫:自己寫一個都可以,只是ajax而已
物件導向的三大概念、三種境界(封裝,繼承,多型)
封裝:封裝就是將資料或函式等集合在一個單元中(類);用了類,成員函式與屬性;使得程式碼模組化
繼承: 繼承可以複用以前人寫的程式碼;js用原型繼承;程式碼重用
多型:一個類或繼承體系結構的基類與派生類中,用同名函式來實現各種不同的功能;為不同資料型別的實體提供統一的介面,說白了就是“引數型別,順序,數量”不同,產生不同的行為:介面重用
JSBridge原理:透過JSBridge來實現H5和Native的通訊,核心就是在native上開一個webview【核心是根據ios和android系統自帶的webview來獲取的】,透過native和webview的通訊實現互動,這個JSBridge就是native和webview通訊的橋樑
一句話,JSBridge就是提供native介面給js呼叫,構建雙向訊息通道
js在app上是執行在WebView 的 Webkit 引擎或JSCore上這個js的Context和app是隔離的;把它們之間的訊息通訊看成RPC(遠端過程呼叫),前端看出客戶端,native看出伺服器
1.JS呼叫native,有2中方式,注入API和攔截URL Scheme
1.1注入API的方式其實就是透過webview的開放介面,向JS Context注入物件或方法【原生方法】;js呼叫時(傳入資料),就直接執行了native的方法(獲得了js資料);
1.2 URL SCHEME 是一種類似於url的連結,是為了方便app直接互相呼叫設計的,形式和普通的 url 近似,主要區別是 protocol 和 host 一般是自定義的。
例如:qunarhy://hy/url?url=ymfe.tech;其中protocol 是 qunarhy,host 則是 hy。
具體的流程就是webview端透過iframe.src等方式修改url,native自動攔截到請求,根據URL Scheme(包括引數)獲得對應的資料,進行操作
scheme的引數對應native的方法,scheme變了,就執行對應的方法;
推薦注入API的方式呼叫Native的原始方法
2.Native呼叫js:
用到就是類似JSONP機制,就是JS呼叫原始方法以後,傳入了callback函式;native根據js提供的資料執行後得到返回data,同時之前傳入的引數中也有callback;
直接自動生成一個唯一的 ResponseId,並儲存控制代碼,然後和 data 一起傳送給前端【就是<script>callbackName(data)</script>】,前端接收到這個callback函式【就是控制代碼】和對應的資料,直接就執行了。
IP代理原理:【有專門的ip代理商】
代理伺服器的工作機制與生活中的代理商相似;假設一臺機器為A機,想獲得由B機提供的資料,代理伺服器為C機,那麼具體的連線過程是這樣的:首先,當A機需要B機的資料時,它會與C機建立連線,
C機接收到A機的資料請求後,會與B機建立連線,下載A機所請求的B機上的資料到本地,再將此資料傳送至A機,此時即可完成代理任務。
爬蟲+node後端,是一種很好的商業模式,不是UGC,而是爬蟲產生資料,然後自動展現到自己的網站上!!!!!!!!!!
常見的爬蟲網站:百度和360等搜尋網站,導航網站,今日頭條等新聞網站,其實就是資訊集合類網站,核心是爬蟲如何寫,完全不需要註冊登入等模組,只負責資訊的聚合展示
這兩年火熱的今日頭條就是典型案例,不太嚴謹的說,今日頭條核心就是做了三件事——
把網路上所有的資訊文章,以及使用者在社交網站上的資料爬取下來。
把這些資料進行分類打標籤,進行一一對應。
將擁有同類標籤的文章和使用者進行匹配。
寫爬蟲不一定要用python,用js在node端也可以寫爬蟲:https://blog.csdn.net/qingshandaijason/article/details/116145395 :
簡單的node搜尋引擎【知乎的資料都是用node爬取的】:
https://blog.csdn.net/qingshandaijason/article/details/116145395
https://www.cnblogs.com/coco1s/p/4954063.html
核心原理:
1.寫好前端頁面,有input輸入框等,所有搜尋框
2.點選搜尋後,傳送ajax請求到node端,node端透過request外掛來模擬傳送http請求,就是類似前端的ajax請求之類的http請求,請求型別和type之類的http頭自己設定,url之類的也自己設定;
npm i request :傳送請求的npm包
npm i cheerio :篩選網頁資訊【解析頁面用的是cheerio,全相容jQuery語法】
npm i iconv-lite :多種型別字串(包括gbk,utf8)的編碼與解碼。
npm i data-utils :
前端相關:
1.前端工程化:webpack,vite,grunt,gulp等工程化打包工具
2.前端Framework[框架],一般涉及到DOM,Event,Template,資料繫結等,常見的框架有React,Vue ,Angular,Backbone,Knockout,jQuery等
3.Css相關:CSS的前處理器【Sass Less等】,css後處理器【例如autoprefixer,一般在post-css外掛中用到】;css的reset;css的框架BootStrap和tailwindcss。同時包括css最最基本的選擇器和屬性以及最新的css3等
4.HTML相關,HTML常用標籤,以及HTML5的新標籤【canvas,audio,video,header,footer,nav,article,aside等】;同時jsx語法也需要關注【react就用jsx來寫】
5.ECMAScript相關,例如ES3 ,ES5,ES6等各個版本,以及相關的polyfill工具【babel】;這裡還有注意,有的專案以及用typeSctipt來寫了,它是js的超集;
6.前端Library的方法庫:就是常用的js方法,不如cookie,ajax,資料型別處理相關的庫,例如underscore或http請求相關的庫axios等;
7.前端Library的通用UI元件庫:ant-design;antd-vue等第三方關於React或Vue的庫;react-bootstrap和bootstrap-vue;jQuery UI等,這些是通用元件的UI庫,
8.前端Library的專業圖形庫:專門做圖形展示,例如D3 ,Echart,antV等,同時echart還有對應vue和react的版本,分別是v-chart和echarts-for-react;其中d3是基於svg,相容ie6+;echart是基於canvas,相容ie9+;antv是螞蟻金服的一個專業的圖形庫,裡面有G2Plot,Graphin,XFlow,F2|F6|F2Native等分支,做各自擅長的領域
9.DOM,BOM,ECMAScript相關知識:這個是js基礎,包括資料型別,語法等,自己可以查“權威指南或小紅書”看
10.npm包和webpck外掛的開發,這個是node包開發的東西
11.小程式相關:微信小程式,支付寶小程式等,這些基本只用到了Js的ECMAScript語法;
12.node後端:就是node後端的第三方庫,V8引擎,LIBUV等這些node基礎的東西,以及後端的資料庫【mongodb,sql server,mySql,oracle等】,後端安全【csrf,xss,ssrf,sql注入,重播攻擊,http劫持,dns劫持,ddos,檔案上傳安全等】,併發【多執行緒(worker_threads 模組),多程序(cluster 模組),事務的隔離界別,加鎖】,伺服器叢集【負載均衡】,資料庫叢集和分片,伺服器監控,node後端框架【koa,express】,http各個版本以及https相關,資料加密等等非常多的後端相關的東西。
13.桌面應用:electron框架
14.移動端小遊戲:例如微信小遊戲,如果選擇cocos Creator遊戲引擎開發,就可以用js這門語言來寫微信小遊戲,當然這個cocos Creator遊戲引擎是基於webgl
第三方圖形庫:D3,echart,antv
antv:移動端和PC端不同,而Echart基本都一樣,只要自己做一些特殊的處理即可
G2:視覺化引擎:例如柱狀圖,折線圖,階梯,面積等,這個是最常用的,相容IE9+
G2Plot:圖表庫
G6 : 圖視覺化引擎:關係資料視覺化方案,樹狀
Graphin:基於G6的圖分析元件
X6:極易定製、開箱即用、資料驅動的圖編輯引擎:用於製作“思維導圖,流程圖”
XFlow:基於X6,面向React的解決方案
F2|F6|F2Native :移動視覺化方案!!!
ChartCube:AntV 圖表線上製作
L7|L7plot:地理空間資料視覺化
D3:基於SVG,相容到ie6,適合dom互動較多的內容,可以自定義事件,D3和Echart區別其實就是svg和canvas區別,d3用svg,echart用canvas;D3庫直接在vue或react專案中使用
echart【大多數都是影像展示,用echart就可以了】:圖表展示,封裝好的方法直接呼叫;相容到ie6以及以上的所有主流瀏覽器;echarts透過canvas來繪製圖形,依賴解析度,相容IE9
v-chart:基於“vue2.0和echart”的圖形庫
echarts-for-react:基於“react和echart”的圖形庫
前端開發效率提升[sublime內支援]:!!!!!!!!!!!!!!!!!!!!
f+tab:匿名函式 : [有了這個,完全沒必要用箭頭函式,因為寫起來比箭頭函式還要方便]
fun+tab:正常函式
for+tab:for迴圈自動補全,tab切換到下一個for迴圈變數
函式名寫完,按tab直接切到函式引數位置;函式引數寫完,按tab直接切換到函式體內寫程式碼
多用es6的解構和...擴充
let,var,import,require,module,defaults,debugger這種經常用的,會有快取記憶,打一半直接出現在第一行就可以tab了
!!!!!!!!!
熟悉antv-design:看看什麼元件,當自己需要類似元件,不要傻乎乎自己去寫,先借外力,外面有現成了就不要自己造輪子!!!!!!!!!!!!
!!!!!!!!!
前端開發的時候,不要去寫註釋,因為中文和英文切換很花費時間,而且寫註釋也費時間;高手都是函式命名語義化,完全不需要寫註釋,等這一塊功能全部開發完,再寫註釋
程式碼自動摺疊到第2層:ctrl+shift+x;crlt+shift+數字【自動摺疊刀第幾層】
屬性簡寫{val:25,age,name}等價於{val:25,age:age,name:name}
前端測試框架:
!!!!!只要用jest就可以了,測似框架使用非常簡單!!!!!!
0.Jest:Github上排名第一的測試框架;Jest具有簡潔清晰的使用者介面,以及高效的載入效能。在預設情況下,它能夠與探查(spying)及模擬(mocking)程式一起,構建出與測試相關的全域性變數
1.Jasmine:Jasmine是Angular建議開發人員廣泛使用的、最為流行的前端測試框架之一
2.Karma:最適合在瀏覽器、或類似瀏覽器的環境中執行測試框架
3.QUnit 【主要對於jquery】
https://developer.aliyun.com/article/1050432
前端效能最佳化:lighthouse模組【npm install -g lighthouse 然後執行lighthouse 網站地址,就可以看到網站整體效能評估】【chrome外掛自帶這個功能】;同時chrome偵錯程式的“網路”+“效能”模組,是可以觀察站點的表現
lighthouse:Performance;Accessibility ;Best Practices;SEO
1.https://blog.csdn.net/c11073138/article/details/84700482
2.瀏覽器的lighthouse包含如下指標:Performance;Accessibility(可訪問性);Best Practices;SEO等;
“效能”tab上可以檢視下列指標
2.0 FP(First Paint),表示渲染出第一個畫素點。FP一般在HTML解析完成或者解析一部分時候觸發。
2.1 FCP(首屏繪製)
2.2 LCP(用於度量視口中最大的內容元素何時可見)”;
2.3 可以檢視“載入,渲染,繪製,js執行”時間
2.4 有個時間瀑布,可以檢視每個檔案載入的具體時間【點選那個檔案,還可以檢視對於的網路等待時間,傳輸時間】
“網路”tab上可以看其他指標
1.載入的時間瀑布,
2.DOMContentLoaded,load時間
前端記憶體洩露:
2.在Class filter(類過濾器)文字框中輸入Detached可以搜尋分離的DOM樹
3.“堆快照”分析記憶體洩露:簡單的分析是否記憶體洩露,比如登入操作是否記憶體洩露:
3.1先登陸,然後記憶體,最上面有個垃圾回收站,表示清理記憶體,登入之前清理記憶體,然後登入再清理記憶體,看記憶體多少;
3.2然後退出登入,再登入,清除記憶體,再看堆快照的記憶體;反覆多次,如果記憶體越來越大,那就是登入操作有記憶體洩露
4.“Allocation instrumentation on timeline”時間軸上的分配插樁 :這個是最常用的判斷記憶體洩露的方法,點選開始,然後進行各種操作,看藍柱,藍柱表示當前的記憶體佔用,隨著時間向後退役,之氣操作的藍柱子越來越小最後沒了【變灰】
就可以判斷之前的這個操作沒有洩露記憶體,少量藍柱剩餘也沒關係,如果“某個行為”產生的藍柱,沒有隨著時間的推移而大幅減少,那麼就有記憶體洩露
如果某個行為反覆操作後,每次操作後隨著時間的推遲仍然都藍柱子殘留,那就說明每次這個操作都會有記憶體產生,就可莪能是記憶體洩露
這個時候就可以選擇區間【把這個藍柱包含進去】,在下面的建構函式內就可以看到是那些“建構函式”佔用了記憶體,
這個時候可以檢視建構函式,函式的記憶體大小有2個:
“Shallow size”【淺層大小】:物件的直接記憶體總數,直接記憶體是指物件自身佔用的記憶體大小
“Retained size”【保留的大小】:物件的最大保留記憶體,保留記憶體是指物件被刪除後可以釋放的那部分記憶體;就是物件刪了以後,和依賴他的也會被刪,一共能騰出多大記憶體
1.頁面解除安裝(window.onunload事件[能起作用,但不能debug時候斷點],safari下用pageshow 和 pagehide 事件來替代)的時候傳送ajax,如何保證條跳轉之前ajax請求能成功傳送【因為頁面跳轉的時候,如果ajax還沒傳送資料或傳送一半,就會被自動取消】:
navigator.sendBeacon(url,data);瀏覽器將少量資料 非同步 傳輸到 Web 伺服器,就算tab頁面關閉,也會成功傳送,同時還不會阻塞頁面跳轉【他是把傳送資料的這個功能交給了瀏覽器內部,不依賴於當前的tab】
該方法主要用於滿足統計和診斷程式碼的需要,一般再unload事件之前觸發
如果用較老的方法來實現頁面解除安裝之前把ajax成功傳送,一般就是傳送同步的ajax,這樣就會產生一個阻塞頁面跳轉或者關閉的問題,而且有的瀏覽器不支援這麼做。
同時有一點移動端的相容性的問題要注意,例如在 iOS Safari 上對於頁面導航的前進和後退做了最佳化,load 和 unload以及beforeunload 事件不會觸發, Apple 官方文件建議使用 pageshow 和 pagehide 事件來替代。
就是判斷 onpagehide in window是否為true //onpagehide 事件在使用者離開網頁時觸發。
cookie預設時間是多少:預設設定session cookie,關閉tab就會自動刪除
React: 直接看一遍redux_demo裡面的註釋即可,下面是redux和vuex的資料管理的異同點
1.redux同步非同步是都是store.dispatch(actionCreate函式),因為是函式,而且這個函式又是透過 store.dispatch((function (){ return actionCreate函式})(param))這種方式來呼叫actionCreate函式的,非常不直觀
redux只是把store.dispatch改造了一下,讓他可以接受函式,而最原始的dispatch則放在action.js裡面的函式里面作為形參,最終還是透過最原始的那個dispatch來執行對應的行為,跳轉到mutation
vuex非同步是用store.dispatch({"actionName":param})的方式,直接跳轉action.js裡面對應的actionName的函式,最終還是呼叫的commit函式,非常直觀;同步的話用store.commit({"actionName":param}),函式名稱不同,引數都是一樣的
所以vuex的commit函式和redux裡面沒有改造過的dispatch函式是一樣的【不是redux的store.dispatch,這個函式已經被redux改造過了】;
2.redux使用store.dispatch後,透過action的型別,自動跳轉到對於的reduce,這個reduce是唯一能改變state的地方,action型別放在action.js中,表示執行某種行為,同時流程會自動跳轉到reduce,透過reduce來修改state
而vuex在store.commit或dispatch後,跳轉到對應的mutation函式執行,修改state,也就是說,mutation是函式,和reduce類似,
redux因為多了一個actionType陣列,在reduce裡面,可以按照元件名稱來細化,就是把action的型別分別放到各自的元件名稱下面,其實最終還是一樣的,呼叫的時候會把所有的“action型別”全部匹配一邊,找到匹配的action名稱
4.vuex中所有的state屬性透過getter來訪問,把getter賦值給元件computed屬性中;
而redux管理state,如何訪問,????????????????,上班之前寫一個React的小專案
目前猜測是在store.js中傳入初始化的state後,入口元件【最外層統一的大元件】把state透過ReactRedux.connect(mapStateToProps, mapDispatchToProps)(Container)的方式把state中的屬性一一對映到props
也就是把已經透過Object.defineProperties監控的初始化state物件傳入到最外層元件中,然後把所有state屬性傳遞給props,這樣,props一旦修改,其實就是被監控的state修改了,自動觸發UI更新
而state屬性同時透過this.props來訪問,透過store.dispatch來修改
網路訪問流程:https://blog.csdn.net/jun2016425/article/details/81506353
1.首先得知道物理層【為資料段裝置(電腦)提供bit流資料的傳輸通路】,網路層【ip,icmp,igmp】,傳輸層【tcp,udp】,傳輸層【TLS|SSL(可選)】,【應用層http,ftp】
1.本地輸入網址,瀏覽器傳送請求到附近的dns伺服器【中間協議的具體操作不詳細說】,查詢站點對應的ip地址,這個就是dns域名解析的過程
2.dns解析正確,最終傳送到了對應的ip的網站[透過tcp或udp協議傳輸],資料傳送大資料庫伺服器,資料庫伺服器應用層能接受並解析http協議,然後從應用層返回資料給物理層,物理層又是重新透過網路層[ip]到傳輸層[tcp,udp],
最終到達使用者客戶端這個應用層【http,tcp】
3.瀏覽器接收到返回的資料,如果是https協議,那麼會驗證安全性,否則就直接接受http請求的資料包展示了;
https防止dns劫持和http劫持的原理:https://blog.csdn.net/ahou2468/article/details/108368246
0.總結起來一句話,證書保證站點正確性,非對稱加密保證“對稱加密金鑰的安全性”,對稱加密保證資料傳輸不被看到;加密和先hash後加密的資料一起傳送保證資料不被篡改
1.瀏覽器向伺服器傳送請求,這個請求裡面包含當前瀏覽器支援的加密演算法【金鑰演算法套件】發給伺服器
2.伺服器接受瀏覽器支援的加密演算法後,看伺服器上是否有與之匹配的加密演算法,如果沒有的話,就斷開,有的話,就生成RSA非對稱加密的公鑰私鑰,
然後向客戶斷返回公鑰【公鑰裡面包含“加密演算法+網站ca證書【域名,ip,頒發機構,有效期等資訊】”】,公鑰是對這些資訊使用hash加密產生的一個字串,把公鑰和hash演算法傳給客戶端;
3.客戶端獲取公鑰和hash演算法名稱,hash演算法就是客戶端和伺服器商定的“對稱加密”的方法,同時透過對公鑰的驗證,獲取網站的證書相關的資訊,包括域名,ip,頒發時間,有效時間,頒發機構等資訊;
客戶端驗證“證書”的"頒發機構,ip地址等資訊",證書ip和訪問網站的ip是否一致,辦法機構是否合法等做驗證,保證訪問網站的合法性,排除dns劫持。到這裡網站安全驗證就結束了,接下來就是資料傳輸安全了
客戶端生成隨機字串,然後用公鑰對隨機字串進行加密,保證這個隨機字串的安全,因為它要作為對稱加密的金鑰,一旦洩露就完了,所以只能是客戶端和伺服器才能看到,中間傳輸不能被其他人看到,所以要對他進行非對稱加密。
根據握手資訊和服務端商定的hash演算法【加密】,先對要傳送的資訊進行hash;然後用客戶端生成“隨機字串”(這個隨機字串就是“對稱加密”的金鑰)對“hash內容”和沒被hash的內容進行加密;
最後把三份內容傳給服務端:1.被公鑰加密好的“隨機字串”;2.被隨機字串對稱加密過的“原版傳送內容” 3.先被hash再被“隨機字串”對稱加密過的資訊
非對稱加密保證“隨機字串”金鑰的安全;隨機字串進行對稱加密保證資料的安全;額外傳送了一份先被hash後對稱加密的內容,用來驗證防止資料被篡改【hash雖然不是加密,但hash可以防止被篡改】
4.服務端接受到資料,先用私鑰解密獲得“隨機字串”【其實就是客戶端傳過來的對稱加密的金鑰】;然後用這個金鑰去解密內容,得到一份原始資料,一份hash過的資料,然後把原始資料hash以下,看資料內容是否一致,防止資料被篡改。
服務端完成驗證然後處理完資料後,仍然使用原來的"隨機字串“,對“返回資訊和返回的HASH值”進行加密,然後傳送給客戶端;
5.客戶端接收到資料後,用原來的"隨機字串"進行解密;再對比hash看資料是否被篡改,驗證透過後,就是握手完成
前端,dns,伺服器快取策略:不同的操作【重新整理,強制重新整理,瀏覽器back返回等】,伺服器可以設定不同的快取策列?????????unfinish
//一般的靜態資源,都是結果下面幾步
1.本地快取【expires頭或cache-control的max-age】
2.本地快取過期就304快取,就是向伺服器傳送請求,伺服器發現沒過期,就返回一個304,告訴你檔案沒修改,可以繼續使用本地的快取【last-modify或etag,目前基本用etag】
3.如果伺服器校驗發現檔案有修改,就直接返回最新的檔案
計算機網路OSI模型【七層】:詳見koa-node中的“OSI模型.png”,物理層【bit】,鏈路層【幀】,網路層【ip:包】,傳輸層【tcp,udp:segment,資料段】,會話層,表示層,應用層【http:訊息,資料流,幀】
一般只需要記住:物理層【為資料段裝置(電腦)提供bit流資料的傳輸通路】,網路層【ip】,傳輸層【tcp,udp】,應用層【http,ftp】
所謂的HTTPS,其實就是在“傳輸層【tcp】和應用層【http】之間,插入了SSL或TLS協議,但是這個不能放在OSI模型中,如果硬要放在OSI模型中,那麼SSL或TLS應該算"會話層"
tcp協議:https://baike.so.com/doc/3381795-3560087.html 【tcp四元組確定tcp連線唯一性:本機IP,本機埠 ;伺服器ip 伺服器埠;】;
建立一個連線需要三次握手,而終止一個連線要經過四次握手
應用層向TCP層傳送用於網間傳輸的、用8位位元組表示的資料流,然後TCP把資料流分割成適當長度的報文段(通常受該計算機連線的網路的資料鏈路層的最大傳送單元(MTU)的限制)。
之後TCP把結果包傳給IP層,由它來透過網路將包傳送給接收端實體的TCP層
埠範圍:0 - 65535;一般1024 - 5000是臨時埠,其他埠是固定給其他機器用的
快取相關:資料庫快取,cdn快取【中間商,比如某個公司在上海,成都,海南都有cdn伺服器,它們只是一箇中間儲存資源的機器】,代理伺服器快取,瀏覽器快取
css ,圖片,js等,都是http請求,http2.0之前,一個域名下的tcp通道里面的http請求都是序列,但是可以開啟多個tcp,所以就有了“單域名”下資源的並行下載【一般是6個tcp】;多域名讓tcp連線數增多
HTTP/1.1中,單個TCP連線,在同一時間只能處理一個http請求;但是可以併發多個tcp,一般是6個tcp;下載資源是併發的,js下載完以後解析和執行不會阻塞之前的tcp下載,但是卻會阻塞之後的資源下載
因為後面的資源下載之前,是需要先解析dom元素,然後再建立tcp連線的,而js執行會直接阻塞頁面的渲染
https://blog.csdn.net/wu_xianqiang/article/details/105837869
關於瀏覽器的執行緒,dom解析和“js的下載,解析和執行”互斥【核心是:js的載入,解析,執行這個一個流程都會阻塞頁面接下來的DOM解析和頁面渲染】【阻塞了dom解析,自然就阻塞了dom渲染】
1.載入html,順序解析html標籤,DOM
2.DOM解析後出現節點,透過tcp載入資源【tcp並行】,但是因為解析的時候順序解析,所以一旦遇到解析的dom下載js,執行緒就會被js阻塞,後面就無法繼續解析了,後面的連線也就無法並行了;遇到js之前,圖片和css都是並行下載和解析的
3.解析dom,cssom有各自的執行緒;不會相互阻塞,各自解析,但是cssom解析會阻塞後面的js執行,所以也就阻塞了頁面
http升級流程如下:
1.目前網上很少用http1.1,這個算比較老的版本了,大多數都是https或http2.0【2.0是基於https的】;HTTP2.0 支援明文 HTTP 傳輸,而 HTTP2.0中使用的升級版的SPDY 強制使用 HTTPS
2.先把http1.1升級https【用http1.1】,也就是在tcp和http1.1之間,新增了ssl或TLS協議,完成http升級https改造
3.然後可以在https的基礎上升級到http2.0【因為http2.0只支援https,不支援http,所以要升級2.0必須先升級到https】,目前主流電商網站基本都支援http2了
4.目前絕大多數網際網路公司都完成了https的升級【https2上只支援https,不支援http】,如果有需要,仍然可以在node端開啟原來的http服務,不過一般都不用了
5.高版本瀏覽器都是向下相容的,所以一個網站如果不支援https,輸入網址的時候就會自動用http協議
http的各個版本:對於一個域名,瀏覽器一般允許連結多個tcp請求【但是有上限,chrome是6個tcp連線(斷開的tcp連線就不算了,斷開了就是沒了)】,一個tcp連線允許並行多個http請求【http2.0】,一個http請求就是一個流;一個流裡面包含多個幀
http各個版本,以及https等關於協議的傳輸流程,詳見koa-node站點下的http-https.png,詳細連線是https://www.51cto.com/article/612101.html
請求頭和響應頭具體資訊:https://www.cnblogs.com/honghong87/articles/6941436.html
http請求頭:
!!!Accept:text/plain [可接受的相應內容,和響應頭裡面的content-type對應]
!!!Content-Type:請求體的MIME型別 (用於POST和PUT請求中) application/x-www-form-url (get請求); application/x-www-form-urlencoded (普通post請求); multipart/form-data 【檔案上傳的post請求用到】
!!!Cache-Control:快取機制public private no-cache no-store max-age 其實這個是服務端設定的,前端這邊不設定
!!!Connection:連線方式【keep-alive:啟動長連線;close:關閉長連線】
Accept-Charset:utf-8【可接受的字符集】
Accept-Encodeing:gzip, deflate [預設值:可接受的返回包的編碼方式,gzip編碼方式是壓縮的編碼]
Authrization:驗證訊息,一般這個頭存放的是 token,現在的登入態token基本放再cookie裡面了;這個基本不用
Cookie:
Host:伺服器的域名以及伺服器所監聽的埠號,寫埠就是預設80埠;例如:www.itbilu.com :域名+埠
Origin:發起一個針對跨域資源共享的請求(該請求要求伺服器在響應中加入一個Access-Control-Allow-Origin的訊息頭,表示訪問控制所允許的來源)。 協議+域名+埠【這個需要自己設定!!!!!】
Referer:頁面從哪個其他頁面跳轉過來的
User-Agent:客戶端資訊
//簡單請求
$.ajax({
url:'http://ajax2.com:8888/index',
type:'POST',
data:{'k1':'v1'},
success:function(arg){ console.log(arg); },
});
//非簡單請求
$.ajax({
url:"",
type:"put",
data:{},
headers:{"h1":''},
xhrFields:{withCredentials:'true'},//如果ajax需要帶上需要cookie,就需要新增 withCredentials;其實核心就是設定xhr.withCredentials=true;
success:function(){}
})
http響應頭: 關於快取,就是先判斷本地快取機制【4種不同的行為對應的不同cache-control有不同的本地快取機制;本地快取過去後,接下來就是服務端的etag或者last-modified快取機制】
Access-Control-Allow-Origin:那些域名可以跨域源資源共享
Cache-Control【快取相關】:預設是private;服務端的快取設定
max-age:快取多久【這個和public是不衝突的,把cache-control設定為"public, max-age=3600"】,個人估計max-age時間是否過期,時把當前的時間和http請求的Date頭的時間做差,看是否大於max-age的值
public:結果所有路徑,都可以快取資料【非重要資料】
private:發起請求的瀏覽器才能使用返回資料的快取【私密資料】
no-store:瀏覽器和其他中間快取(如 CDN)從不儲存檔案的任何版本
no-cache:瀏覽器每次使用 URL 的快取版本之前都必須與伺服器重新驗證【也就是不走本地快取,去伺服器判斷檔案是否變更,如果沒有變更(兩個Last-Modified相同),那麼仍然會返回304,讓瀏覽器從本地快取獲取檔案】
設定max-age後,瀏覽器傳送這個請求的正確流程是:
1.本地快取頭max-age是否過期,沒過期直接走本地快取
2.過期了直接請求伺服器,伺服器那邊判斷檔案是否更新;這個涉及到當前檔案的Last-Modified和伺服器檔案的Last-Modified或者eTag,etag優先順序高於Last-Modified
如果兩個時間相等,那就說明檔案沒有更新過,伺服器會返回304,告訴客戶端檔案還是最新的,客戶端最後仍然從快取獲取請求的檔案
3.如果Etag相同就是沒過期,或者兩個Last-Modified時間相同,那就是沒更新了;否則就服務端重新傳輸檔案,並返回200,瀏覽器接受檔案後把最新的檔案快取下來覆蓋原來的檔案。
瀏覽器不同的行為對應的cache-control:新視窗,重新整理,回退,地址按enter鍵:
詳見:https://baike.so.com/doc/4806790-5023130.html
1.重新整理:全部重新訪問伺服器【所以這個時候伺服器返還304來提高效能就非常重要了,etag來判斷檔案是否有變更】那麼在此值內的時間裡就不會重新訪問伺服器
2.開啟新視窗【偏重新整理,max-age不影響】:除了public和“max-age未過期”會取快取,其他都是重新請求;!!!!!
3.瀏覽器enter:太多了,不記了
4.返回【偏快取,max-age不影響】:no-cache/no-store直接請求服務,max-age過期也請求服務,其他都不會重新訪問伺服器,直接從快取獲取
ETag[快取相關:伺服器傳送給客戶端的HTTP請求頭標籤]:請求檔案的資源識別符號,用於和伺服器做對比,看資原始檔是否改變,和last-Modified的目的時一樣的,都是為了判斷資原始檔是否改變
etag經常和“If-None-Match或者If-Match”頭一起使用,http1.1新增的,優於last-modified
當你第一次發起HTTP請求時,伺服器會返回一個Etag;並在你第二次發起同一個請求時,客戶端會同時傳送一個If-None-Match(瀏覽器自動新增),而它的值就是Etag的值
伺服器會比對這個客服端傳送過來的Etag是否與伺服器的相同,如果相同,就將If-None-Match的值設為false,返回狀態為304,客戶端繼續使用本地快取,不解析伺服器返回的資料
如果不相同,就將If-None-Match的值設為true,返回狀態為200,客戶端重新解析伺服器返回的資料
ETag 實體標籤: 一般為資源實體的雜湊值;且Etag的優先順序高於Last-Modified。
//Last-Modified[快取相關:也可以直接放棄,都用etag;伺服器傳送給客戶端的HTTP請求頭標籤]:請求的物件最後的修改時間,只能精確到秒;它經常和If-Modified-Since一起使用
If-Modified-Since是瀏覽器發給服務端的請求頭,
客戶端第二次請求此URL時,根據 HTTP 協議的規定,瀏覽器會向伺服器傳送 If-Modified-Since 報頭,詢問該時間之後檔案是否有被修改過
所以它是瀏覽器自動新增的,和Last-Modified配套使用的請求頭
//Expires【快取相關:直接放棄不看,要用也用cache-control的max-age】:過期時間:有缺陷,“要求伺服器與客戶端的時鐘保持嚴格的同步”,max-age優先順序高於Expires
Content-Encoding:資源編碼
Content-Language:響應資源的語言
Content-Type:當前內容的MIME型別
Date:訊息傳送時的日期;
Set-Cookie:設定HTTP cookie ;例如“Set-Cookie:UserID=itbilu; Max-Age=3600; Version=1”
Status:返回狀態碼,200表示成功
Refresh:用於重定向,或者當一個新的資源被建立時。預設會在5秒後重新整理重定向。
Server:伺服器名稱
//安全頭相關,用helmet外掛來完成:https://www.jianshu.com/p/f7b5b7d91238
X-Frame-Options:防止自己的網站被插入到其他網站裡面,然後被點選劫持;設定SAMEORIGIN
X-Content-Type-Options:則 script 和 styleSheet 元素會拒絕包含錯誤的 MIME 型別的響應。這是一種安全功能,有助於防止基於 MIME 型別混淆的攻擊。設定nosniff
X-DNS-Prefetch-Control:dns預解析,它可以增加 5% 或更高的圖片載入速度;如果關閉就沒有了,預設off是設定關閉的,如果你希望透過它提升效能,可以在呼叫 helmet() 時傳入 { dnsPrefetchControl: { allow: true }} 開啟 DNS 預讀取。
X-XSS-Protection:瀏覽器的XSS防護機制,設定“1; mode=block”就表示“如果檢測到惡意程式碼,在不渲染惡意程式碼”;設定“1; mode=block”就表示
X-Download-Options:這個 header 僅用於保護你的應用免受老版 IE 漏洞的困擾。一般來說,如果你部署了不能被信任的 HTTP 檔案用於下載,使用者可以直接開啟這些檔案(而不需要先儲存到硬碟去)並且可以直接在你 app 的上下文中執行。
Strict-Transport-Security:如果使用者一旦訪問了帶有此 header 的 HTTPS 網站,瀏覽器就會確保將來再次訪問次網站時不允許使用 HTTP 進行通訊。此功能有助於防範中間人攻擊。
http1.0:一個tcp裡面只能有一個http請求和響應;一個域名可以開啟多個tcp連線,但是不多,chrome是6個;每個tcp連線裡面的http請求是序列
1.隊頭阻塞:當順序傳送的請求序列中的一個請求因為某種原因被阻塞時,在後面排隊的所有請求也一併被阻塞,會導致客戶端遲遲收不到資料。
解決方案:將同一頁面的資源分散到不同域名下,提升連線上限。在一個tcp連線中所有請求是序列的,在當前的請求沒有結束之前,其他的請求只能處於阻塞狀態
2.傳輸內容不加密:容易被篡改 :
DNS劫持:請求網站A,但是返回給你的是網站B;dns伺服器把ip和域名的mapping做修改把你多請求的域名對應到其他站點的ip上,實在dns伺服器上做手腳;
一般而言,使用者上網的DNS伺服器都是運營商分配的,所以,在這個節點上,運營商可以為所欲為,直接dns劫持;
http劫持:傳輸層中有許多種協議,首先在tcp連線中找出http連線【如何篩選出】,然後透過閘道器來獲取資料包進行http響應體,因為http沒有加密,所以插入廣告就是最簡單的形式,是在閘道器上擷取資料做手腳。
最後搶先發包,篡改後的資料包搶先“正常站點返回的資料包”,搶先返回到客戶端瀏覽器,那麼後到的真實的資料包就會被直接丟棄,因為前面已經有人搶先返回了
對於普通網民來說,閘道器和dns伺服器都在運營商那邊,閘道器和dns伺服器可以是同一個ip,也可以是不同的ip,就看是否選同一個運營商
技術難點:
1.如何篩選抓到http請求包,本地可以透過fiddler抓包;那麼資料傳輸的中間節點,如何抓包,是在哪個機器上抓包
2.抓完包以後,進行資料篡改很容易,但是如何返回給客戶端瀏覽器,因為客戶端瀏覽器肯定會有校驗,tcp本身就有三次握手協議
http1.1:谷歌提出的
SPDY:主要是“長連線”【請求資源請求適合用長連線,預設基本都是長連線】和Etag
1. 長連線:Connection:keep-alive = true,因為tcp三次握手有時候太麻煩【http是基於tcp協議的】,短時間內經常交換資料,用長連線更為高效
使用場景,一般預設都是用長連線,偶爾用的ajax可以不設定長連線;長連線的好處是,比如js,css,圖片等靜態資源,如果每次都用tcp三次握手,那就建立一次tcp連線就需要三次握手,
一個http建一次tcp連線,這樣很費事;如果改成長連線,那麼一個tcp內就可以串聯多個http請求,不需要再頻繁斷開了;
可以再http的header中設定長連線時效,比如1分鐘之內,tcp連線裡面沒有傳送http請求,那麼就自動斷開。這樣避免產生大量的tcp連線,因為一個域名下的tcp連線是有限的
2. 節約頻寬:支援只傳送header資訊(不帶任何body資訊);比如401返回客戶沒有訪問許可權,壓根就不需要body,支援不傳送body資訊就節省頻寬;
允許請求某個自由的某一部分,雖然不支援“斷點續傳”,但它是“斷點續傳”的基礎。
3. 新增了部分錯誤狀態碼例如409(confilct):請求資源和當前資源衝突
4. 新增了部分快取策略,例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供選擇的快取頭來控制快取策略等快取策列
http2.0:
基於SPDY:2015年3月份百度開始率先支援HTTPS,但不支援SPDY。下半年阿里的淘寶和天貓也開始支援HTTPS,同時支援SPDY3.1。
新增的東西有:
0.多路複用【一個tcp連線上允許多個流併發,一個流裡面有多個幀】,允許在一個連線上無限制併發流;解決了“隊頭阻塞”問題,
多路複用【解決序列的檔案傳輸和連線數過多】:一個域名對應一個tcp連線,
連線【connection】:就是一個tcp連線,裡面可以併發多個流,就是“多路複用”
流【stream】:一個流代表一個完整的http請求[包括http請求+伺服器響應],虛擬通道,可以承載雙向訊息,多路複用就是一個tcp連線可以併發多個流,也就是併發多個http請求,但是併發請求數量不同瀏覽器都會有限制
訊息【message】:邏輯上的HTTP訊息,比如請求、響應,流是一個完整的請求,一個完整的請求裡面分2部分,“請求和響應”,而一個訊息實際上就等價於“一個請求或者一個響應”,是邏輯上的“http請求”或“http響應”
幀【frame】:最小的單位,多個幀組成一個流【資料流:stream】,幀最小的通訊單位,承載特定型別的資料,比如HTTP首部、負荷等等,每個幀都採用二進位制格式編碼;
幀的型別:
1.Data:傳輸http訊息體
2.Headers:使用者傳輸關於流的額外的首部欄位
3.Ping:計算往返時間,執行“活性”檢查。
4.....
幀的存放:結果HPack壓縮
多路複用也造成了一些缺點:比如伺服器壓力上升,可能產生延遲
關於http請求的header中的Connection:keep-alive = true,只要tcp連線不斷開(預設2小時),一直可以進行http請求;也就是這個http請求存在的話,tcp請求是不會斷開的
1.二進位制分幀【效能增強的核心】:也就是在應用層使用“二進位制分幀”,引入了新的通訊單位:“幀,訊息,流”,一個流表示一個完整的請求;一個流裡面包含多個幀;
而分幀,實際就是把一個流分成多個幀【frame】;比如一個http請求裡面有header【chorme中的請求頭】和請求資料data【chrome荷載裡面的內容】,這個http請求在2.0中是分為“Headers幀”和“資料幀”
HTTP1.1 採用文字格式,http2是二進位制格式
2.使用Hpack對header的資料進行壓縮
3.伺服器推送,伺服器可以直接把資原始檔推送給客戶端,客戶端有權利選擇是否接收 !!【比如一個ajax請求,後端處理事件很長,可以先返回一個提示資訊,然後等後端處理完了,直接用伺服器開啟socket給客戶端推送資訊】!!!!
4.請求優先順序,每個 stream 都可以設定依賴 (Dependency) 和權重,可以按依賴樹分配優先順序,部分解決了關鍵請求被阻塞的問題!!!!!!
缺點:隊頭阻塞沒有完美解決,在http3.0中解決了
http3.0:核心是UDP和QUIC,解決”隊頭阻塞“,新增了"快速握手"
1.把TCP協議改成了UDP,也就是物理層 , 網路層【IP】 ,傳輸層【UDP】,額外新增【QUIC】+Qpack和stream,應用層【http】
2.TLS從1.2升級到1.3,並且在TLS1.3同一層新增了QUIC
3.QUIC是把TCP重新實現了一遍,並加上了一些額外的效能最佳化【包括之前的隊頭阻塞】:
QUIC用UDP實現快速握手,因為tcp是四元組【自己ip和埠,伺服器ip和埠】,任何一個變化都會斷開後重新建立連線,連線需要三次握手,而UDP是無連線的,只要ID不變【伺服器IP和埠不變】,就不需要重新建立連線;
所以快速握手核心還是UDP和TCP的區別
QUIC既然是面向連線的,也就像TCP一樣,是一個資料流,傳送的資料在這個資料流裡面有個偏移量offset,可以透過offset檢視資料傳送到了那裡,這樣只有這個offset的包沒有來,就要重發。
substr(開始下標,長度)和substring(開始下標,結束下標記)
Map:類似Object,但是key可以是一個物件,物件記憶體地址作為key;
weakMap :只允許物件記憶體地址作為key
(a == 1 && a == 2 && a ==3) 有可能是 true 嗎? 可以,如果a是物件,呼叫的是toString或者valueOf方法,方法內可以寫具體邏輯,每次對比,都是呼叫方法
set map object區別
時間複雜度【指的是計算次數和變數的關係】:常數階O(1), 線性階O(n),對數階O(log2n),平方階O(n^2),指數階O(2^n),雙階乘[n!,也就是n^n]
常數階【不管變數輸入多少,區塊內的js語句執行次數都是一次】:就是普通的js執行語句,例如sum=n*(n+1),console.log(sum);因為不管輸入n是多少,計算次數都是“常數”
//對數階【 log2^8=3,log2^n=m,就是2^m=n:2的m次方等於n】:int number=1;while(number<n){number=number*2;}:其實計算次數是lon2^number
線性階【單迴圈,設定n,塊內的js語句的執行次數就是n次】:for(i=0;i<n;i++){...};因為n決定了迴圈次數,所以決定了計算次數
平方階【雙巢狀迴圈】:fun cal(n){var rst=1;while(n--){while(n--){rst+1;}}}:時間複雜度就是n*n,就是n^2
指數階【遞迴呼叫:2^n時間複雜度】:
func cal(n){
if(n<0){
return 1
}else{
return cal(n-1)+cal(n-2)
}
}
雙階乘[n!,也就是n^n]:
func cal(n){
if(n<0){
return 1
}else{
var rst=0;
wihle(n--){
cal(n-1)
}
return rst
}
}
時間複雜度面試題:如何獲取n^m的最後兩位;時間複雜度是線性【n】;
for(i=0;i<m;i--){
n*=n;
}
(n+"").substr(n-2,2)
//如何簡化,降低計算次數;
Observer:資料監聽 Object.defineProperty或new Proxy//無法監控原型內的熟悉
Compiler:模板解析, AST 【抽象語法樹】
Watcher:...
vue和react底層渲染原理,虛擬dom,diff演算法原理:
0.都是把template字串解析成AST【抽象語法樹】後,在根據AST用render函式產生的“虛擬節點”【vue下是VNode】,然後在虛擬節點上展開diff演算法;虛擬節點原生是js物件,不是DOM節點,所以不會觸發repain和reflow消耗效能
1.都是深度優先遍歷,同級節點對比【不會跨層,預設原生的dom渲染會跨層(效能不高)】
2.資料更新後,都是結果虛擬節點對比後,返回一個patch物件【補丁】,用來標記兩個節點不同的地方,然後再透過patch物件來修改真實DOM;
3.同層對比演算法應該是相同的,就是新虛擬節點從左開始遍歷“同層老節點”,遇到“相同的節點”就把老的節點移到和新節點對應的位置,如果沒有,就在老節點處建立和新節點相同的節點
注意,patch物件儲存的是操作,也就是一個patch物件是一個action行為的描述,然後按照順序把patch物件串起來,最後要修改真實dom的時候,是統一把patch補丁按照之前的順序依次執行
詳見https://www.csdn.net/tags/MtTaMg4sNjYyOTg1LWJsb2cO0O0O.html
4.節點判斷後是重建還是修改的方式不同:
如何移動,React和Vue的節點移動區別:貌似沒區別,這個不看了
2.1 react比較:同層比較,type相同既是同型別節點,只修改節點屬性
2.2 vue比較:同層比較,當節點元素型別相同,但className不同時,vue認為是不同型別元素,會刪除重建;type型別和className都相同才會認為是同節點
2.3 原始diff:原始diff演算法就是,兩個虛擬dom樹,進行逐一對比,而且是不分層級的,對比量很大
在標準dom機制下:在同一位置對比前後的dom節點,發現節點改變了,會繼續比較該節點的子節點,一層層對比,找到不同的節點,然後更新節點。
在react的diff演算法下,在同一位置對比前後dom節點,只要發現不同,就會刪除操作前的dom節點(包括其子節點),替換為操作後的dom節點。
vue2以及以前,資料繫結用的是Obejct.defineProperty ;vue3用的是new Proxy(obj,{get,set})//監控繫結資料
vue2用defineProperty只能監聽已經列舉出的屬性,所以陣列的增加,屬性的增加都是不會自動響應的,需要重新複製整個物件或者陣列
而Proxy是下面的形式,所有的屬性不管有沒有定義,都會自動走到get和set公共函式,而非某個屬性特有的get和set,完美解決新增屬性無法監控的問題,同時這種屬性監控是所有屬性的代理,所以記憶體也會減少很多
new Proxy(obj, {
get(target, key, receiver) {
console.log("檢視的屬性為:" + key);
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
console.log("設定的屬性為:" + key);
console.log("新的屬性:" + key, "值為:" + value);
Reflect.set(target, key, value, receiver);
},
});
!!
樣式核心函式:document.defaultView.getComputedStyle()||window.getComputedStyle(ele);ie下用ele.currentStyle,獲取當前元素最終的樣式
渲染流程:document.addEventListener("DOMContentLoaded",...)
1.整個html文件解析完成:DOMContentLoaded
2.頁面所有資源載入完畢,包括css,js,圖片,iframe,vedio等:onLoad
其中async和defer指令碼的區別:它們的指令碼載入都是非同步的
1.async:立即非同步載入並非同步執行,下載的時候不會阻塞DOM渲染,不會影響DOMContentLoaded事件觸發;
一旦js開始執行【非同步執行,意思js下載完成後,插入非同步佇列,什麼時候執行這一段js得看前面的同步流程啥時候結束】,所以它不會阻塞頁面,以為頁面DOM解析和渲染時同步的,在他前面;
同步在前執行,非同步在後執行,就像ajax請求發出去,後面還有js邏輯,會繼續先執行後面的同步js,等到執行完了,才會去看非同步的請求是否返回,如果返回了就執行。
2.defer:立即非同步載入,同步延遲執行【需要在前面所有的dom和cssom完成解析之後,DOMContentLoaded之前執行,他和原來dom渲染以及js是同一個程序】,支隊非內嵌的script指令碼有效; 一般js都是同步立即載入立即執行,他是延遲執行
核心:下載,解析,執行
0.js下載,解析,執行完成之前,會阻塞後續dom的解析【阻塞解析自然阻塞渲染】,包括其他資源的下載
0.css和圖片是可以並行下載的,但是css後面如果有js,那麼css就會阻塞這個js的執行,js阻塞後面dom的渲染,所以css直接就把頁面阻塞了
1.因為渲染樹會因為cssom而改變,但是就算沒有cssom,渲染樹照樣會渲染,css載入和解析輸不會阻塞dom渲染的,但是會阻塞js執行,而js會阻塞dom渲染,所以css後面不能有js
2.因為js可能依賴於之前css樣式和dom節點,所以樣式表會在js執行之前載入和解析,也就是說js依賴之前dom和cssom,前面的css會阻塞後面的js執行;
3.dom css 和js都是按照在html檔案中的位置,按照順序來的;js會阻塞後面的dom解析,css會阻塞後面的js執行【不管後面的js是否有用到css的內容,css都會阻塞js】!!!。
4. DOMContendLoaded是頁面的所有dom解析完成觸發【在生成渲染樹之前就觸發了】,不是渲染後觸發,但是js會阻塞渲染,defer屬性的js也會阻塞【所以如果defer屬性的js不是在頁面底部,還是會阻塞頁面,他在DOMContenLoaded之前執行】,async屬性的js不會,
5. DOMContendLoaded不會等待圖片,影片,iframe以及頁面底部的css載入和解析【css非頁面底部,就會影響後面的頁面展示】。
6. css載入不會阻塞DOM樹的解析,css載入會阻塞後面js語句的執行【css載入阻塞js執行,自然就會阻塞DOM樹的渲染】
具體流程:
1. html檔案下載完成後,解析html生成dom;同時並行解析css生成cssom;
2. dom和cssom合併生成渲染樹,執行layout和paint
詳見// https://blog.51cto.com/u_15127592/4299317
package-lock.json作用:因為 package.json裡面的版本, ^是定義了向後(新)相容依賴,指如果 types/node的版本是超過 8.0.33 ,
並在大版本號(8)上相同,就允許下載最新版本的 types/node庫包,例如實際上可能執行npm install時候下載的具體版本是 8.0.35。
有時候大版本相同可能出現不相容,所以用package-lock.json來鎖定小版本,列出各個包之間詳細的依賴關係
主版本號.次版本號.補丁版本號
主版本號: 當API發生了改變,並與之前的版本不相容的時候。
次版本號【大版本】:當增加了功能,但是向後相容的時候。
補丁版本號【小版本】:當做了缺陷修復,但是向後相容的時候。
"1.2.3", // 安裝指定版本的1.2.3版本
"~1.2.3", // 安裝1.2.X 中的最新的版本【最近的小版本依賴包】,1.23,1.24等都是小版本:1.1;1.2;1.3之類的是大版本
"^1.2.3", // 安裝1.x.x中是最新的版本【最近的大版本依賴包】;^1.2.3會匹配所有1.x.x的包,包括1.3.0,但是不包括2.0.0
"*1.2.3", //安裝目前的最新版本
建議使用~來標記版本號,package-lock.json也會鎖定小版本號
??????????????如何在一個專案中安裝多個不同的框架版本,比如同一個專案同時安裝Vue2.0和Vue3.0?????????????????????????
如何監控DOM變化:有的時候前端開發再偵錯程式上惡意修改dom節點,而有些資料是從dom節點的內容中獲取,導致繞開一部分前端校驗。
new MutationObserver(callback).observe(需要監控的dom節點, {
childList: true, // 觀察目標子節點的變化,是否有新增或者刪除
attributes: true, // 觀察屬性變動
subtree: true // 觀察後代節點,預設為 false
});
效能最佳化:模板效能 https://cnodejs.org/topic/50e70edfa7e6c6171a1d70fa
1.載入時間最佳化:ssr,快取策略,預載入,懶載入,壓縮,檔案合併,首屏最佳化;互動最佳化【減少reflow,例如虛擬dom createDocumentFragment 】,事件委託
0.後端的最佳化:涉及到"快取策略",除seo外的其他部分用前端渲染,縮短響應時間;伺服器中間鍵的選擇,尤其是template的選擇【dot, Handlebars ,ejs(koa框架用),jade,nunjucks(koa框架用)】;伺服器叢集和負載均衡;資料庫叢集+分片+負載均衡;服務端gzip壓縮
2.前端和後端,就是伺服器渲染和前端渲染的抉擇,seo部分用伺服器渲染,其他前端渲染;
3.前端最佳化:
快取:cdn靜態資源快取,瀏覽器快取
請求數量和總量:js,css,圖片【 css spirit;圖片轉base64,iconfont代替圖片,圖片壓縮】;分割程式碼按需載入【預載入和懶載入】,檔案合併和壓縮,公共資源提取;渲染最佳化【非必要的js和css放底部】
2.互動體驗最佳化:介面抖動,點選或滾動的時候反應慢【涉及repaint refolw js計算量】,減少頻繁的dom操作,事件委託;html語義化
3.開發環境最佳化:webpack熱替換,不同執行環區分"境執行時包和線上包";oneOf,resolve,dll最佳化,壓縮,HappyPack【任務分解成多個子程序】;tree-shaking剔除js死程式碼
父子元件什麼週期:父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
vue相關知識:修飾符
vite知識點:和webpack grunt gulp一樣是前端構建工具
vite效能提升的原因:
1.公共的npm包全部快取,編譯的是頻繁更改的那部分js
vue的三大核心:模板編譯【AST】,資料繫結,虛擬dom【效能最佳化,diff】
compiler表示template編譯成樹狀的資料結構,即AST抽象語法樹【抽象語法樹本質上就是一個JS物件】,生成虛擬DOM[VNode就是AST抽象語法樹產生的物件後再轉化生成的新js物件,該js物件是用來描述DOM節點]。
reactivity表示data資料可以被監控,透過 Object.defineProperty。或new Proxy()
runtime表示執行時相關功能,虛擬DOM(即:VNode)、diff演算法、真實DOM操作等。
虛擬dom本質上就是一個普通的JS物件,用於描述檢視的介面結構,和AST是兩回事:
template字串 》 AST 》 render渲染函式【AST的產物,也是VNode的起點】 》 VNode虛擬節點 【涉及diff演算法】 》 介面
AST是指抽象語法樹(abstract syntax tree),或者語法樹(syntax tree):說白了就是把template字串,轉化成對應樹狀的一個資料結構(這裡是js物件,但是如果換一個場景,不是vue,而是編譯器產生AST,那就是其他物件了)
【AST是描述樹狀結構的資料結構,不是描述dom節點的js物件】,VUE的AST是用一個js物件來表述一個樹狀結構的資料結構物件。
是原始碼的抽象語法結構的樹狀表現形式,然後,經過generate(將AST語法樹轉化成render function字串的過程)得到render函式,返回VNode。VNode是Vue的虛擬DOM節點【用於描述dom節點的js物件】,就是用js原生物件來“描述真實DOM”
tcp和udp區別:
1.都基於tcp/ip 協議,傳輸層協議【ip才是網路層協議,http是應用層協議】
2.tcp一對一,可靠,連線,三次握手,四元組【本地地址和埠,伺服器地址和埠:缺點tcp唯一性】;udp可以一對一,一對多,多對多,不可靠,無連線
TCP四元組中的伺服器地址,一般就是伺服器ip,以為伺服器是固定ip;
而TCP的客戶端地址,一般有2個組成【外網ip和內網ip】,外網ip閘道器ip,也就是客戶端的外網ip地址;因為一個區域網內,所有人的外網ip都是相同的;
還有一個內網ip,就是我們ipconfig裡面出現的192.168.x.x這個內網地址;閘道器記錄了內網地址是哪一臺機器的。
//3.http是基於tcp協議
//4.http是應用層的協議,tcp和udp是傳輸層
伺服器返回碼:
1 開頭:臨時響應,並繼續
2 開頭:正常訪問,200 是請求成功
3 開頭:重定向,301 表示網頁被移動到新的位置:304快取【表示可以使用本地的快取,本地快取是最新的檔案】
4 開頭:請求錯誤; 400 表示錯誤請求,伺服器無法理解請求引數 ;401【身份驗證錯誤】;403【禁止訪問】;404【未找到】
5 開頭: 伺服器內部錯誤, 500 表示伺服器出錯
get和post區別:
get請求是url後面帶引數,長度有限制(url限制2048個字元),沒有對資料庫進行修改,用於查,有快取 ,不安全
post:用於增刪改資料庫,沒有快取,安全【請求引數放在body裡面】
GET的Content-Type是application/x-www-form-url ; POST的Content-Type是 application/x-www-form-urlencoded或multipart/form-data。
application/x-www-form-urlencoded :這種就是一般的文字表單用post傳地資料,只要將得到的data用querystring解析下就可以了,一般就是簡單的表單請求
multipart/form-data :用於檔案的上傳 【表單種包含上傳檔案用到】:它既可以傳送文字資料,也支援二進位制資料上載
window.requestAnimationFrame 【還有一個 cancelAnimationFrame有的瀏覽器是cancelRequestAnimationFrame】 詳解: 相容性【webkitRequestAnimationFrame,mozRequestAnimationFrame;cancelAnimationFrame也類似】
基礎:動畫涉及螢幕重新整理頻率【最佳狀態就是和螢幕重新整理率同步,因為如何大於螢幕重新整理率,也沒啥用】,一般是60hz,1 秒60幀,所以一般setInterval用的時間間隔都是1000/60
如何提高效能:requestAnimationFrame就是把所有的dom操作以1幀為單位進行repain和reflow,和螢幕重新整理率同步;而setInterval首先只能手動同步為60【很多螢幕不是60重新整理頻率】
1.同步頻率
2.每一個幀上儘量減少多次dom操作,因為再怎麼變,也都只是1幀而已,;1 幀只執行一次就是repain或reflow的渲染【reflow裡面肯定包含repaint】,螢幕重新整理頻率同步
3.一旦頁面不處於瀏覽器的當前標籤,就會自動停止重新整理。這就節省了CPU、GPU和電力
requestAnimationFrame用法:和setTimeout一摸一樣
事件冒泡,捕獲,對應的引數:e.target=e.srcElement;e.preventDefault(),e.returnValue=false;e.stopPropagation()=e.cancelBubble;e.currentTarget等價於this,ie中沒有對應的
佈局:
左側固定右側自適應:左側absolute,右側margin;做float,右側margin;左側設定寬度,右側設定flex-grow為1
兩邊固定中間自適應:2邊absolute 中間設margin ; 左float 右float 沒有浮動的第三個塊
垂直居中:position:absolute top:50% margin-top:-一般的高度; display:inline-block vertical-align:middle;前面需要有個span ;display:flex ; align-items:center
flex佈局:
//盒屬性
display:flex
align-items:center//垂直劇中
justify-content:center:水平居中
行內元素使用flex佈局,要用display:inline-flex
flex-direction:row row-reverse column colume-reverse
flex-wrap:nowrap wrap換行
flex-flow: direction wrap
justify-content:center居中對齊 flex-start flex-end flex-between【兩端對齊】 flex-around[間距相等]
align-items:center 垂直居中 flex-start flex-end flex-baseline stretch[不設定高度的時候,全部自動給設定為100%高度衍生
align-content:多條軸線
//內部元素屬性
order:1 2 3 展示順序
flew-grow:寬度佔比,比如4個1,一個4,就表示一個元素佔寬度一般,其他4個各佔1/8;//如果元素總寬度加起來超過了父元素寬度,那麼這個flew-grow的設定就不能按照比例了,必須給每個元素設定with為100%,才能讓flew-grow生效
flex-shirnk:預設為1 ,空間不足寬度等比例縮小
BFC: 塊級格式化上下文,元素佈局的規則:防止margin上下重疊,防止高度坍塌
float:
overflow:hidden
position:absolute,fixed
display:flex,table-cell,inline-block
this:當前物件的引用,是一個關鍵字,不是呼叫物件的屬性
一般情況下:this指向的是呼叫這個函式的物件,如果沒有物件呼叫這個函式,那麼this指向window;
特殊情況:
箭頭函式內的this:箭頭函式定義位置的父作用域【也就是外面的函式】的this,不是箭頭函式呼叫時所處的物件
建構函式內this是建立的物件
事件中的this是目標元素,currentTarget
bind,call,apply都可以改變this指向:func.apply(obj,arguments);func.call(obj,arg1,arg2...)
儲存相關:
web儲存:
Cookie:每個cookie內容不能大於4K ,伺服器最多20個cookie,瀏覽器最多儲存300個cookie 未過期就有效,同源可訪問
cookie 的httpOnly和sameSite:Strict Lax None
Lax:防禦的狀態如下:不傳送cookie
1.post表單【在其他站點傳送post請求】【post的action指向被攻擊站點,也就是之前登入的那個站點】 :
2.<iframe src="..."></iframe>
3.ajax
4.image
不預防的操作如下: 仍然會傳送cookie
1.連結<a href="..."></a>
2.預載入<link rel="prerender" href="..."/>
3.Get表單 <form method="GET" action="...">
cookie的name path domain結合在一起作為cookie的唯一標識用於更新cookie;一般的cookie都是直接透過name獲取cookie來修改對應的屬性即可
document.cookie=..,是新增或者更新cookie,自動會去cookie裡面尋找是否對應的cookie,存在就更新,不存在就新增,cookie的刪除只能是透過設定有效期讓cookie過期來刪除
name:cookie名稱
domain:如果設定.baidu.com 那麼www.baidu.com h5.baidu.com baidu.com都可以訪問這個cookie;預設就是伺服器主機名
path:cookie所屬路勁,不同路徑下訪問許可權不同,預設是/,就是主機下所有路勁都可以訪問,但是如果設定為/center,那麼www.baidu.com/就無法訪問了,但是www.baidu.com/center和www.baidu.com/center/page可以訪問
max-age|expires:有效期,max-age是秒數,expires是事件字串,比如new Date().toGMTString()
secure:安全性,設定為true的話只允許在https或其他安全的協議連結是才被傳輸
localStorage:每個瀏覽器對localstorage的支援大小是不一樣的,chrome是5M ,IE10是1630K;同源 set get removeItem clear()
localStorage超出最大限制會增樣:報錯,寫不進去,所以一旦報錯,需要清空一部分;各條業務線最好氛圍不同的子域名,這個樣localstorage就分開了,
sessionStorage:5M 瀏覽器關閉就沒了,只有同一個瀏覽器視窗下可用【一個url就只有一個視窗】
應用程式儲存:
html5的manifest:離線瀏覽 - 使用者可在應用離線時使用它們;瀏覽器將只從伺服器下載更新過或更改過的資源
每個指定了 manifest 的頁面在使用者對其訪問時都會被快取
html5的drag事件: https://blog.csdn.net/hsl0530hsl/article/details/88344225
1.圖片,連結,選中文字預設都可以拖拽
2.其他元素要拖拽,需要新增draggable屬性 <div dragable="true" ></div>;如果某個元素可以拖拽,那麼內部文字就不可再選中
//在拖動節點上觸發
document.addEventListener("dragstart",function(){})
document.addEventListener("drag",function(){})
document.addEventListener("dragend",function(){})
//在拖入拖出某個元素目標節點的時候觸發,和上面的觸發節點不是同一個
document.addEventListener("dragenter",function(){})
document.addEventListener("dragover",function(){}):這個需要event.preventDefault(),阻住預設不讓拖入
document.addEventListener("dragleave",function(){})
document.addEventListener("drop",function(){}) 這個也需要preventDefault
網頁亂碼:
頁面的編碼儲存是utf-8;同時html頁面的 charset="utf-8";保持一致
svg和canvas區別:
svg:向量圖,可縮放不會失真,類似xml,可以操作各個dom和事件處理,適合大型渲染區域,因為是dom,所以隨著dom節點的增多,效能會越來越差;文字渲染能力搶
canvas:html5新增的東西,整個畫布作為一個元素,所以裡面的事件處理,得自己透過區域計算才能得出具體的點選位置,絕對是否觸發事件,就是不支援內部dom,因為只有一個節點
文字渲染能力弱,可以儲存為圖片,也可以製作影片,適合區域較小且頻繁repaint的操作
label定義表單空間,選擇設定了for屬性的label,自動會把焦點轉移到id為label標籤的for屬性對應的值的input輸入框
iframe優缺點:
優點:可以實現post跨域,可以並行載入資料
缺點:阻塞onload事件,載入內容過多;如果iframe第三方站點內部不受我們控制,出現不友好的使用者體驗就很麻煩,尤其是iframe站點如果被駭客黑掉,然後利用瀏覽器安全漏洞下載木馬或其他危險的程式,或者載入垃圾資源佔用頻寬,頻繁alert影響使用者體驗,如果本站被黑,本站可以直接搞”點選劫持“來搞那個iframe站點:比如上方設定一個小遊戲,然後把iframe站點透明度設定100%覆蓋在上面;點選下游戲的時候其實是點選上面我們的網站,可能就是支付或者其他敏感詳細。
檔案上傳攻擊:前端能做的很有限[用postman fiddler,或者chrome偵錯程式上都可以偽造請求],如果是圖片,可以是前端直接轉base64上傳資料;伺服器把base64轉圖片儲存。
名稱內包含 .php .jsp .asp .aspx .js 0x00 %00 eval( 直接過濾掉;
0x00 %00 後臺轉換資料的時候換變成 chr(0) ,即空字元,從而階段了後面的檔案字尾比如檔名稱為1.php.0x00.jpg 以為儲存的是圖片,其實是php,使用者訪問這個圖片的時候,實際是啟用執行了php程式,上傳資料夾要取消可執行許可權
csrf:跨站請求偽造,cookie設定httpOnly和sameSite【lax或strict】
xss:跨站指令碼攻擊,後端:啟用白名單和黑名單策略,最好是白名單,周特定的資料才不會轉譯,其他都轉換,有可能導致使用者資料展示不正確;上傳檔案路徑固定不可以修改,資料夾沒有執行許可權 “0644”
前端:資料請求返回的資料,不要用innerHTML,或者vue的v-html,react的angerouslySetInnerHTML;不能啟用
css內最好別寫express,裡面可以寫js;同時最好別用外展js和css連結,直接本地化儲存使用
資料提交的時候也校驗【雖然意義不大,可以透過前端請求偽造來傳送】;最重要的就是資料渲染的時候,對於使用者產生的資料,不能用innerHTML和v-html;
react中的富文字輸入【類似vue的v-html】是dangerouslySetInnerHTML【危險地設定innerHTML】,<div dangerouslySetInnerHTML={{ __html: novelMsg.content }}></div>
核心源頭在於使用者提交的資料詳細內包含危險連結或者js程式碼:
基礎:
var宣告的變數不能用delete
基本型別:bool,number,string,null,undifined
typeof:bool,number,string,null,undifined, object function,typeOf null 是object
instanceof: {} instanceof Obejct 某個物件是否是某個建構函式的例項
Object.prototype.toString.call:"object Number" "object String" "object Boolean" "object Undefined" "object Null" "object Object" "object Function" "object RegExp" "object Array" "object Date" ;
引用型別:Object,Array,Function,ExgExp,Date
作用域【定義變數和函式的被使用的區域】:函式的作用域就是該函式的呼叫物件;變數的作用域看變數定義的位置,全域性變數作用域是全域性;函式內的變數,作用域知識函式內部【包括函式內部的函式】
改變作用域的語句:with新增一個呼叫物件到作用域鏈頭部,try-catch的catch的前端新增呼叫物件【呼叫物件包含“被丟擲的錯誤物件”】,eval【把字串改為js執行,如果內部有函式,就會建立js執行環境,js執行環境裡面自然就有自身的作用域】
js的執行環境:js直譯器執行函式,都會為函式建立一個執行環境;js允許有多個全域性執行環境【比如頁面內有iframe,一個iframe內就是一個全域性執行環境】;
js的執行環境內有一個呼叫物件,改物件包含了裡面定義函式內的區域性變數,且該呼叫物件不能直接被訪問,函式內輸入某個變數,先從這個呼叫物件上去找,沒找到再向上一級函式的呼叫物件找,每個函式都有一個呼叫物件,
呼叫物件的鏈就是作用域鏈【最外層是window全域性物件】
frame之間相互訪問詳細,可以用top.frames[x]或者parent.frames[x]相互訪問【js訪問前提是要同源】,沒有iframe,那麼top.frames或parent.frames就是window
條件對比:相同型別好比較,不同型別,有一個是引用型別,呼叫toString或valueOf【優先toString】獲得返回值,如果返回值仍然不是基礎型別就不等,如果返回的是基礎型別;
接下來就按照不同的基礎型別做對比; 基礎型別null==undefined,但不和其他任何基礎型別相等,NaN連自己都不相等;剩下的只有number,boole,string對比了,有數字優先轉數字,其次優先轉boole
for in無法列舉出那些:只讀,不可列舉的屬性 【可訪問原型鏈上所有屬性,用hasOwnProperty判斷是自己的數字而非原型上的屬性】
for in可以獲取物件的原型中的屬性,但是卻不能獲取原型prototype這個屬性,比如obj={age:24};obj.prototype.name="d";
for (key in obj){}的時候,可以訪問到age和原型中的name屬性,但是無法訪問prototype這個屬性
function:只有在後面加上了(),此時函式才會被編譯(JIT編譯器),產生函式的執行環境和呼叫物件
關於V8的知識:編譯器,解析器,AST,位元組碼,JIT【即時編譯器】 :https://blog.csdn.net/lovermeiy/article/details/110985294
編譯型和解釋型程式語言:
編譯型:會把檔案編譯成2進位制檔案,編譯一次即可,後續直接執行二進位制檔案;
程式碼進行“詞法分析【分詞】,語法分析【解析】”生成AST【先分詞,後解析,最終生成AST】;然後在最佳化程式碼,最後生成2進位制機械碼
解釋型:在執行的時候,需要透過“直譯器”動態解析和執行
因為沒有編譯,所以執行的時候,是靠“直譯器”對程式碼進行“詞法分析,語法分析”生成AST【抽象語法樹】,然後再基於AST生成位元組碼【或其他中間碼】,最後根據位元組碼來執行程式
V8既有編譯器,又有直譯器:
把程式碼轉化成AST抽象語法樹,生成一個 AST的過程和渲染引擎將 HTML 格式檔案轉換為計算機可以理解的 DOM 樹的情況類似;AST 看成程式碼的結構化表示而不是原始碼
AST 是非常重要的一種資料結構;
以前的V8是沒有位元組碼的,直接是機械碼,但是因為機械碼佔記憶體太大,後來就加了位元組碼,不用機械碼,用於解決手機上的記憶體佔用過大的問題。
直譯器把AST轉成“位元組碼”然後執行,重複的位元組碼會儲存成“機械碼”【其他機械碼都不儲存】
我們把“位元組碼配合直譯器和編譯器”這種技術稱為“即時編譯”JIT【就是V8用編譯器編譯產生AST,AST透過直譯器轉成“位元組碼”然後直譯器再執行位元組碼
程式碼處理流程:原始碼--編譯器-→抽象語法樹[AST]--直譯器-→位元組碼[最後直譯器執行(重複程式碼還會編譯成機械碼來執行)]
原始碼---→抽象語法樹[AST]---→原生代碼【機械碼】:透過JIT【即時編譯】來實現重原始碼到機械碼的過程,
之前V8是沒有“位元組碼”,直接編譯產生“機械碼”,後來為了減少記憶體,有了位元組碼整個環節,且預設開啟,減少手機上的V8引擎的記憶體佔用;但是在Node端,可以關閉來提高效能
執行環境:函式呼叫()的時候,建立的扎堆這個函式的執行環境
!!!!!
閉包【巢狀函式】:有權訪問另一個函式的作用域中變數的函式,說白了就是函式里面巢狀的函式!!!!!!!!!!
閉包記憶體洩露:最常見的就是,函式返回的閉包,返回值儲存到外部全域性物件中,就是記憶體洩露。
本質是,js執行環境內部的引用型別變數賦值給外部環境【外部js環境依賴內部js環境的資料】,如果外部函式的執行環境不釋放,內部js執行環境也就不會銷燬“呼叫物件”釋放記憶體【內部的所有變數都會儲存】!!!!!!!!!!!!
閉包經典案例:執行var arrst=exp();會造成記憶體洩露,因為執行環境不會被釋放;因為函式返回一個閉包【閉包就是內部巢狀函式】給了外部函式的一個變數,那麼這個函式作用域將會一致儲存在記憶體中,
直到外部函式的執行環境被銷燬的時候才會釋放,如果或者外部函式的變數就是全域性變數,那麼只要這個全域性變數還在,函式exp的作用域就會一直儲存在記憶體中
function exp(){
var arr=[],rst;
for(var i=0;i<10,i++){
rst[i]=function(){
return i
}
}
return rst
}
而且var arrst=exp();執行後,陣列內每一個函式執行,返回的都是10,因為都指向同一個執行環境內的變數,如何讓 arrst陣列內的每一個函式返回的i不是同一個【使用場景就是迴圈條件中傳送ajax,引數不能相互影響】
修改方式如下
function exp(){
var arr=[],rst;
for(var i=0;i<10,i++){
rst[i]=(function(num){//內部巢狀一個執行環境,包資料複製進這個執行環境,這樣資料就不依賴於閉包內的變數了
return num
})(i)
}
return rst
}
作用域:就是呼叫物件
作用域鏈:呼叫物件鏈
呼叫物件|變數物件:就是函式執行的時候,儲存這個函式內部所有的資料的一個物件,該物件不可訪問,訪問函式中的變數,都是按照這個該函式的呼叫物件鏈【作用域鏈】,一層層向上訪問的,當前呼叫物件內沒有,就訪問上一層的呼叫物件,含是否包含這個屬性,this不包含在呼叫物件裡面
塊級作用域:(function(){
//不給匿名函式設定引用,執行完成就會自動銷燬【作用域鏈】,可以減少閉包占用記憶體;如果把匿名函式的執行結果儲存到外面的全域性變數中,而這個結果恰好是匿名函式內部的一個引用型別的變數,那麼外面的全域性變數就依賴了匿名函式內部的,就無法釋放了,如果不是引用型別的話,返回的時候把簡單型別變數傳給外部,這個傳遞的過程是傳值,所以外部不會對函式體內有依賴,函式是會被銷燬的
})();匿名函式執行完畢,內部的任何變數都會銷燬,外面無法訪問該函式內的任何變數
prototype和constructor:
1.prototype是一個物件,是建構函式的原型,建構函式才有【物件.__proto__才是建構函式的prototype】
2.constructor是一個函式,是物件的建構函式,物件才有;
3.最最容易搞混的就是建構函式,因為既是物件又是函式,作為物件它有自己的建構函式,作為函式它又有自己的原型!!!!!!!!!!!!!!!!!
3.所有es的基礎物件,建構函式都是Object,ie8以及以下的DOM和BOM節點物件最基礎的建構函式不是Object【是COM,用引用技術,造成記憶體洩漏】,ie9以及以上就是原生javascript物件;所有的Object的建構函式都是Function,也就是所有的物件最終的建構函式是Function【dom元素也不例外,dom元素節點第一個建構函式是對應的Node型別的建構函式,比如div的建構函式是HTMLDivElement】
4.因為非DOM和BOM的基礎物件的建構函式是Object【IE9以上的DOM和BOM也是Object類】,因為Object是所有最基本的空物件{}的建構函式,
{}實際是new Object(),本質一樣;所以Object.prototype是所有基礎物件的原型,因為new Object()中,建構函式內部自動會呼叫類似下面的程式碼
var a={};
a.__proto__=Object.prototype;
this=a;
...建構函式的內部邏輯
return this;
類的基礎:詳見koa-static裡面的util.js的Class方法,
大概流程 function Class (parentConstructor,childConstructor){
function resultConstructor (){
parentConstructor.apply(this,arguments);//父類的例項屬性和例項方法繼承:借用建構函式
childConstructor.apply(this,arguments);//自己的例項屬性和例項方法
}
resultConstructor.prototype=parentConstructor.prototype //繼承父類的原型:基礎原型物件
resultConstructor.prototype.constructor=resultConstructor;//需要指自己!!!!!!!!!!這個很關鍵,函式的構造原型上的建構函式就是自己;resultConstructor.constructor是Function類
return resultConstructor
}
Array物件常用方法:push pop shift unhsift reverse sort concat join slice splice forEach map some every filter:其中sort要注意,內部的function返回值作為排序以及,是正負判斷進行排序,不是false和true 【小於0升序】
indexOf lastIndexOf
字串常用方法:
非正則:charAt,substr(startIdx,length)和substring(startIdx,endIdx),indexOf,trim,toUpperCase,toLowerCase
支援正則:search,match(不支援分組,支援g),replace,split
Obejct:
Object.constructor prototype
Object.propertyIsEnumerable ,hasOwnProperty,toString,valueOf
Object.defineProperty(obj,key,{多屬性配置}) defineProperties(obj,{key:{},key:{})
屬性包括:
value:值
writable:能修改
configurable:能否刪除,修改其他屬性特性,就是修改writable enumerable
enmuberable :能for in
Date:
+new Date()==Date.now()
getFullYear,getMonth,getDate,getDay,getHours,getMinutes,getSeconds,getMillionSeconds;getUTCFullYear[GMT不用了]
正則方法:exec(在字串中尋找匹配的內容);test(在字串中尋找是否包含匹配的內容)
其中g對exec的作用不是全域性匹配,是記住上次匹配的下標,下次從原來的地方開始繼續匹配;exec支援分組
正則:
1.字元類:
[...]:包含
[^...]:不包含
.:除了換行符和Unicode的終止字元,其他所有
\w:ASCII[a-zA-Z0-9_] 注意,阿斯克碼是包含下槓的
\W:[^a-zA-Z0-9_],和\w取反
\d:數字
\s:unicode空白字元,一般就是空格
2.重複:
*:0+
+:1+
?:{0,1} 可有可無
{n,m}:
{n,}:
{n}:
重複次數後面再加一個?,表示非貪婪匹配
3.選擇,分組,引用
選擇:|表示從左向右選,只選一個
分組:(),是獨立的一組,結果會出現在匹配項中;其中有個特殊分組(?:內容),(?:)這個表示“只組合”,分組不用於引用,一般不太用到這個
引用:\1 ,和分組對應,引用第一個括號內的內容就是\1,字元類裡面不能放引用
4.邊界匹配,向前宣告(?=)和反向前宣告(?!):比如java(?=Script),匹配javaScript 不匹配javaSc或java等,對後面跟隨的字串做了條件限制
^:開頭,這個要特別注意,千萬別和字元類裡面的^混淆了
$:結尾
\b:邊界, 比如\bJava\b,就表示Java是單獨的詞,千萬別把\b和^$混淆
fsdf(?=...):向前宣告
fsdf(?!...):反向前宣告
5. g全域性匹配,i不計較大小寫,m多行匹配
6. 擴充使用
var reg=/(\d)jeff(id)/;reg.test("d898jeffid"); 然後就可以在RegExp這個建構函式中發現匹配的第一個和第二個組,分別是RegExp.$1和RegExp.$2 RegExp.input是源字串
!!!!!!!!!!!!
"2015-08-55 12:52:33".replace(/(\d{4})\-(\d{2})-(\d{2})\s(\d{2})\:(\d{2})\:(\d{2})/,"$1/$2/$3/$4/$5/$6"),最終變成了'2015/08/55/12/52/33'然後用split來獲得各個"分組"
!!!!!!!!!!!!
DOM:
document.compatMode=="backCompat" :混雜模式
document.referrer cookie url domian
domain 不可以從鬆散變嚴格,但能從嚴格變鬆散:比如document.domian原來是p2p.baidu.com;可以把他設定為baidu.com;但如果原來是baidu.com,那麼就不能再變為p2p.baidu.com
js的不同子域名之間是無法訪問的,同源策列的限制,也就是說p2p.baidu.com和h5.baidu.com之間是存在跨域問題的;想要跨域,可以把它們的domian都設定baidu.com!!!!!!!!!!!
!!!!!!!!!!!!!!!!
跨域:同源策列
頂級域名:baidu.com
二級域名:www.baidu.com
baidu.com和www.baidu.com是不同域名,跨域的
協議(http或https),(主機)域名(www.baidu.com),埠(80或其他埠):三個有一個不同就是跨域
JSONP:
var updateList=function(data){window.isFeedBack=true;...}
var ele=document.createElement("script");ele.src="www.baidu.com?callback=updateList¶m=5" ;
document.body.appendChild(ele);
setTimeout(function(){
if(!window.isFeedBack){
alert("請求失敗,伺服器沒反應");
請求失敗的業務邏輯
}
},50000);//超過50秒就停下使用者請求失敗
//[不需要,和cors搞混了]noded端需要設定,this.set("Access-Control-Allow-Origin", "http:localhost:8080/");//允許特殊域名跨域;
因為返回的是script,所以node端還得新增this.set("Content-Type", "text/javascript");,否則瀏覽器不知道用什麼方式開啟接受的檔案
iframe :
跨域就是建立iframe,把引數傳過去,然後iframe因為和ajax請求同源可以請求資料,拿到資料後再把資料從ifmame傳送給原來的頁面,這裡資料傳送的方法有3種
資料傳輸用location.hash或window.name或window.postMessage
window.name原理:iframe的src修改後,window.name資料不會變,所以把請求的資料儲存到window.name,再把iframe的src指向和本頁同源的空白頁,因為同源,本頁就可以拿iframe的window.name的資料了
postMessage:
A頁面執行:window.postMessage(data,url);
B頁面新增監控:
window.addEventListener("message",function(e){
if(e.origin=="http://www.baidu.com"){//獲取資料
var data=e.data;
....
e.source.postMessage(data,url)
}
});
修改domain:這個是在相同主域名下,但在不同子域名下,比如一個是在h5.baidu.com,另一個在pc.baidu.com下,不同源,可以把document.domain修改為baidu.com,就可以實現跨域
CORS跨域:簡單請求和非簡單請求
請求方法是以下三種方法之一:
HEAD: HEAD和GET本質是一樣的,區別在於HEAD不含有呈現資料,而僅僅是HTTP頭資訊。
GET
POST
HTTP的頭資訊不超出以下幾種欄位:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限於三個值application/x-www-form-urlencoded、multipart/form-data、text/plain 【這三個常用於表單,所以一般的表單都是CORS跨域的簡單請求】
對於簡單請求,瀏覽器直接發出CORS請求。具體來說,就是在頭資訊之中,增加一個Origin欄位。
nodeType:
Element:1
attr:2
text:3
document:9
Node節點的關聯: offsetParent 【position為relative或absolute或fixed祖先節點或body節點,樣式定位也是根據offsetParent來的】,parentNode,childNodes,firstChild lastChild,nextsibling previousSibing
Node節點增刪:document.createElement createTextNode createAttribute createDocumentFragment【虛擬節點,文件碎片節點】;父節點.appendChild,父節點.removeChild,父節點.insertBefore(新節點,插入位置錨點節點),父節點.replaceChild(新節點,老節點);
Node節點屬性修改:getAttribute,setAttribute,removeAttribute
Node節點操作:innerHTML,outerHTML,ele.insertAdjacentHTML()可操作文件節點
Node克隆:ele.cloneNode(true|false),設定true就是深度克隆(子節點也克隆);ie下克隆的時候會把事件都克隆進去,所以需要提前把事件移除;
型別基礎:最基礎是Node類,Element Attr Document CharacterData 繼承自Node;
Node -- Element -- HTMLElement -- HTMLHeadElement HTMLBodyElement HTMLDivElement HTMLInputElement ....
Node -- CharactorData -- Text Comment
Node -- Document -- HTMLDocument 【是document的建構函式】
ele.scrollIntoView():HTML5,滾動到可視區域
createNodeIterator 和createTreeWalker: 遍歷所有頁面元素,DOM2支援這個介面,深度優先
var iterator=document.createNodeIterator(documnet.body);
iterator.nextNode();iterator.nextNode()多次呼叫,會有記憶
document.createDocumentFragment【dom的type是11】:文件碎片,在記憶體中不再dom樹中;建立臨時節點,不會造成repaint和reflow,插入文件樹後才會成為真正的dom節點;
一般建立一個新節點,createElement和createDocumentFragment效能上區別,因為都沒有新增到DOM樹;
當請求把一個DocumentFragment節點插入文件樹時,插入的不是DocumentFragment自身,而是它的所有子孫節點
var li="查詢獲取文件中已經存在的節點";
var newFrag = document.createDocumentFragment();
newFrag.appendChild(li);
li.innerHTML=...;//操作li節點
最後document.body.appendChild(newFrag);//就會把newFrag文件碎片的所有子元素依次全部插入到body中,這個
document.createElement【dom的type是1】和createTextNode
//下面三個集合都是動態集合,哪怕已經儲存在了變數裡面,每次訪問變數都會重新查詢
NodeList【實時更新立即反應】: childNodes,document.querySelectAll()
NamedNodeMap:getAttribute獲取,類似NodeList,也是動態更新的,對這些返回內容的處理是很消耗效能的,最好是透過createDocumentFragment建立好節點然後統一插入
HTMLCollection:getElementsByTagName()、getElementsByClassName()、getElementsByName();children、document.links、document.forms
document.documentElement:指向html元素
document.body:指向body
很多相容性問題,比如scrollTop,scrollLeft都是透過document.documentElement.scrollTop||document.body.scrollTop來實現的
!!!!!!!!!!!!!!
元素寬高核心是:scrollHeight[實際攤開來高度] offsetHeight【元素可視區域包含邊框高度】 clientHeight【可視區域不包含邊框高度】,scrollLeft[橫向滾動了多少]
文件和元素,都擁有上面的幾個屬性,只是文件的滾動需要相容,有時候是document.body,有時候是document.documentElement
關於介面的寬高和位置:
screen:height,width,availHeight(減去螢幕上的“系統工作列”高度,不是瀏覽器工作列),availWidth 整個顯示器,和瀏覽器大小縮放無關
(document.body||documentElement).scrollTop scrollLeft:文件滾動位置
(document.body).scrollWidth scrollHeight:文件寬高【包含滾動距離】
(document.body).offsetWidth offsetHeight:文件可視寬高【不包含滾動距離,但包含邊線寬高(比如滾動時最右側有一個滾動欄,那個欄的寬度也算進去)】
(document.body).clientWidth clientHeight:文件可視寬高【不包含滾動距離,不包含邊線寬高(比如滾動時最右側有一個滾動欄,那個欄的寬度也算進去)】
關於元素的寬高和位置
!!!
位置核心函式:ele.getBoundingClientRect ele.scrollIntoView()
判斷元素是否在可視區域內:在IE中,預設座標從(2,2)開始計算,導致最終距離比其他瀏覽器多出兩個畫素,我們需要做個相容。
ele.getBoundingClientRect()返回{top,bottom,left,right,x,y,height,width},是相對於檢視視窗的資訊
getBoundingClientRect的相容問題:IE和Idge瀏覽器不支援x、y屬性;IE9版本以下的瀏覽器不支援width、height屬性。沒關係,只要有top left bottom right即可其他都可以計算得到
用這個實現懶載入無限滾動
元素節點的位置:DOM2 支援
ele.offsetTop offsetLeft:border到offsetParent節點【上層的第一個position為absolute或relative,就是offsetParent節點】的距離:ele.offsetParent
ele.scrollTop scrollLeft:節點滾動位置【節點設定固定寬高和滾動邊框,自然就會產生滾動位置,注意和文件的滾的位置做區分】
ele.scrollHeight scrollWidth:實際高度【就是把滾動都攤開來,實際的寬高】
ele.offsetHeight offsetWidth:包含border的寬高
ele.clientHeight clientWidth:包含border的寬高
位置和z-index,盒模型
DOM1 DOM2 DOM3的相容性支援
事件:IE9自持DOM3,ie78支援DOM2,ie6以及以下支援DOM0【只有onclick之類的事件】
DOM0:onclick
DOM2:addEventListener:
事件模組:HTMLEvents MouseEvents UIEvents;DOM3中還新增了MutationEvents
事件介面:Event MouseEvent UIEvent
事件型別:laod change upload unload abort submit scroll resize focus blur ; click mousedown mouseup mouseover mousemove mouserout
其中 blur focuse unload load這四個事件不冒泡!!!!!!!!!!,不能用事件代理!!!!!!!!!!!!!
事件相容:
HTMLEvent:
document.addEventListener和document.attachEvent
e和window.event[ie的event內的this是window,而]
e.currentTarget 等價於this; ie9之前沒有這個屬性,ie的this是window物件,繫結事件的時候可以用bind this :觸發事件的當前所在的dom節點
e.target ;event.srcElement :觸發事件的源頭的元素是那個
e.stopPropagation ;event.cancleBubble=true
e.preventDefault ; event.returnValue=false
MouseEvent:
e.clientX clientY :不考慮滾動位置,相對於客戶端瀏覽器視窗
e.screenX screenY :相對於顯示器
relatedTarget: ie中有fromElement和toElement【事件只有一個,離開某個元素的時候有toElement,進入某個元素的時候有fromElement;都等價於relatedTarget】
ie下,元素刪除後,事件不會刪除,記憶體洩露,所以得刪除事,對於那些頻繁更新innerHTML或outerHTML或使用insertAdjacentHTML方法的,尤其要注意!!!!!!!!!!!
document.getElementById("btn1").insertAdjacentHTML("afterEnd",'<br><input name=\"txt1\">');
ie8以及以下只支援事件冒泡
事件流:事件捕獲,處於目標階段,事件冒泡
DOM3:ie9+支援DOM3
鍵盤事件:keyup keydown keypress事件,以及e.keyCode,13表示enter
backspace:8
tab:9
enter:13
DOM變動監聽事件【有很多,這裡只寫一部分】:DOM3新增,就是Mutation事件: DOMNodeInserted 和 DOMNodeRemoved,DOMAttrModified
DOMNodeInserted,DOMNodeInsertedIntoDocument:元素插入後觸發
DOMNodeRemoved,DOMNodeRemovedFromDocument:元素刪除的時候觸發
DOMAttrModified :屬性修改觸發的事件
new MutationObserver(callback).observer(ele,{childList,attributes,subtree})//用於水印防篡改,比如把水印對應的變數儲存在window上,只要水印對應的html屬性被修改了,直接在callback中重寫水印
HTML5事件:
contextmenu事件:自定義“滑鼠右鍵點選元素”選單展示事件。 ele.addEventListener("contextmenu",function(e){e.preventDefault(); 自定義邏輯})
beforeunload:一般再window上新增該事件,頁面離開,重新整理或關閉之前呼叫;window.addEventListener("beforeunload",function(e){e.returnValue="";});//目前個性化訊息提示以及被大多數瀏覽器廠商禁用了
裝置事件:
移動端:
橫豎屏旋轉:window.orientation,手機橫豎屏旋轉;【orientationchange事件|MozOrientation事件|deviceorientation事件:一個事件,為了相容多個裝置才用到的】
觸控事件:touchstart touchmove touchend touchcancel
事件屬性:
e.target altKey,shiftKey,screenX【螢幕中的位置,有的時候文件只佔螢幕一半】,clientX【文件視覺視窗中的位置】,pageX【在頁面中的位置,包含滾動距離】,identifier
e.touches【整個螢幕上的接觸點陣列】 targetTouches【當前觸發元素上的接觸點陣列】 changeTouches【上次觸控到現在的觸控,改變的那些touch觸點】
e.bubbles:冒泡型別
e.cancelable:e.preventDefault()是否可用
手勢事件:gesture事件
gesturestart[手勢開始:一個手指已經按螢幕上,另一個手指剛接觸螢幕時觸發],gestureend【任意一個手指從螢幕上移開,就觸發】, gesturechange【任意一個手指觸點位置發生變化就觸發】
viewport:!!!!!!!!!!!!
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
可以透過這個設定來改變viewport,達到自適應
width:寬度設定
user-scalable:是否開啟縮放,yes|no
initial-scale:初始縮放
maximum-scale:最大縮放
minimum-scale:表示最小的縮放比例
自定義事件:DOM3級才可以使用 ; document.createEvent,是全域性註冊,對所有元素都有效
//非IE瀏覽器用下面的
var evt=document.createEvent("MouseEvent"):滑鼠2次點選事件:自定義事件不會自己觸發,需要自己再js邏輯中主動呼叫
evt.initMouseEvent("click",true,true,document.defaultView,....)
上面的自定義事件,其實就是把自定義事件繫結到已有的時間上去,因為自定義事件肯德是基於已有的事件,比如2次點選事件,肯定是基於點選事件,
所以只要在點選事件中判斷場景邏輯【和上次點選事件時間間隔小於100ms且在同一個dom節點,就執行document.getElementById("jef").dispatch(evt)即可】
//這些都是基於DOM原生事件的擴充事件
自定義滑鼠事件:document.createEvent("MouseEvent").initMouseEvent;
自定義鍵盤事件【有相容性問題,所以寫了2個】:document.createEvent("KeyEvents").initKeyEvent||document.createEvent("KeyboardEvent").initKeyboardEvent
自定義通用事件:document.createEvent("Events").initEvent(type,bubble,cancelable)
自定義Mutation事件:document.createEvent("MutationEvents").initMutationEvent
ele.dispatch(evt)呼叫事件
//自定義DOM事件
document.createEvent("CustomEvent").initCustomEvent(type,bubbles,cancelable,detail);自定義事件的type不是“click”之類的原生事件型別
//IE瀏覽器有自己的自定義事件
evt=document.createEventObject()
evt.screenX=....,只能自己一個個手動新增引數,不像上面的,可以在init函式里面設定;
document.querySelector(".jef").fireEvent(evt);用fireEvent方法,非IE瀏覽器用的是ele.dispatch(evt)
效能問題:onunload事件,離開之氣前把所有的事件全部移除,尤其是ie下
ajax:
XMLHttpRequest和 ActiveXObject
xhr.timeout=1000[毫秒,ie8+支援]
xhr.open(type,url,true非同步|false同步);:開啟
xhr.setRequestHeader("content-type",value):設定請求頭,可以多次呼叫裡設定多個請求頭
xhr.send(data|null):傳送資料,post請求資料放裡面,get請求資料不需要放,get請求的資料放在url後面
xhr.abort():停止,在readyState==4之前都可以停止
xhr.onreadystatechange=function(){
xhr.readyState==0 1 2 3 4
0:未open
1:open但未send
2:send但未response
3:部分response,正在接收資料
4:完成response
xhr.status==200 返回成功
}
xhr.upload.addEventListener("precess",function(){...})//監聽上傳進度
MIME【說穿了其實指的就是檔案字尾名,用什麼方式開啟檢視;字尾和下發的http header中content-type做對比,對的上就開啟,對不上就不開啟】
DOM:1 2 3 【ie9】
ES:3 5【ie9】 6
BOM:沒有規則,一般就是history,location,screen,navigator;XMLHttpRequest ActiveXObject cookie 【可有的說是bom,有的說是dom,個人覺得是dom,因為是document.cookie】
下面都是全相容的屬性
navigator.userAgent plugins cookieEnabled platform【win32系統】
history.go back forward pushState replaceState
screen【螢幕顯示器,不是dom,不是瀏覽器】.height width availHeight【height-系統部件高度(也就是工作列高度)】 availWidth【width-系統部件寬度(一般window下沒有系統部件寬度,其他系統或許會有)】
html5中給history新增了pushState replaceState
history.pushState({page: 1,這個物件是用來存放該頁面的特定資料的}, 'title 1', '?page=1');
window.onpopstate=function(e){//事件,history物件出現變化時,就會觸發popstate事件
history.state屬性返回的就是上次history.pushState方法的第一個物件引數。
}
或者window.addEventListener('popstate', function(event) {}
頁面第一次載入的時候,在load事件發生後,Chrome和Safari瀏覽器(Webkit核心)會觸發popstate事件,而Firefox和IE瀏覽器不會。
單頁面引用程式的模仿瀏覽器前進回退功能:https://www.gxlcms.com/ajax-71289.html
方法1:使用hash,監控hash變化
hash修改:不會重新整理頁面但會改變瀏覽器的histroy
window.onhashchange 事件監控hash變化;location.hash獲取當前hash
方法2:使用history.pushState方法,replaceState方法;以及window.onpopstate事件來完成前進後退,pushState和replaceState需要瀏覽器支援html5
前進的時候用pushState,後退的時候用
標誌性:ie9:dom3 + es5
瀏覽器核心引擎:
opera:
webkit:safari,chrome
KHTML:
Gecko:Firefox,Netscape
IE:
如何判斷:必須按照下面的先手順序
opear:window.opera
webkit:AppWebKit判斷ua
khtml:KHTML判斷ua
Gecko:Gecko判斷ua
IE:MSIE判斷ua
Math:
ceil:向上舍
floor:向下舍
round:四捨五入
random:隨機,隨機0.***小數
Number:
toFixed
toString(2),轉化成2進位制數字對應的字串
window.parseInt parseFloat ,解析的是字串
表單:
form.reset():重置
blur,change,focus事件
input:text元素:透過<input type="text" size="25" maxlength="50"> 顯示25個字元,最多輸入50個字元
text型別的input有select事件:
selectionStart,selectionEnd:選擇內容的開始下標和結束下標;Ie9+都支援!!!!
ie8雖然不支援,但是ie8有document.selection,是全域性的,和時間無關,就是獲取選中的那部分文件
高階瀏覽器也有:document.getSelection().anchorNode.textContent,獲取選中文字
表單序列化: 發給伺服器的時候,瀏覽器會自動序列化表單,流程如下
1.表單欄位的名稱和value進行url編碼,使用&分隔資料
2.禁用表單欄位不上傳
3.只傳送勾選的核取方塊或但單選框,不勾選的不發
4.不傳送type為reset和button這類按鈕,因為不是資料
6.說白了就是隻傳送有用的資料,然後把資料轉化成key和value的形式,類似name=value&name=value%....
canvas: html5中新增的
2D上下文:
<canvas id="cav"></canvas>
var ele=document.getElementById("cav")
var ctx=ele.getContext("2d");//也可以用ele.getContext("3d")
var url=ele.toDataURL("image/png");url是base64字串,可以直接用於img的src
ctx.fillStyle:設定填充內容,可以設定漸變物件或模式物件
漸變物件:ctx.createLinearGradient(), 返回一個CanvasGradient的例項物件
ctx.createRadialGradient:放射漸變物件
ctx.strokeStyle:設定描邊內容
//矩形
ctx.clearRect(0,0,cutWidth,cutHeight); fillRect執行填充,strokeRect執行描邊
ctx.drawImage(img,startX,startY,cutWidth,cutHeight,0,0,cutWidth,cutHeight);
繪製路徑:
ctx.beginPath(),moveTo lineTo arc或arcTo畫圓弧,rect畫矩形路徑
fill()執行填充,stroke()執行描邊
ctx.isPointInPath():判斷某個點是否在路徑上
fillText,strokeText
ctx.save和restore,來儲存和返回之前的儲存
3D上下文:WebGL,基於canvas,這個太複雜了,直接用執行緒的影像引擎 three.js製作3D動畫
Electron.js[ɪˈlektrɒn] :可以使用前端+node製作桌面應用
cocos Creator:遊戲引擎 ,製作2d遊戲 ,目前不太擅長3D遊戲
HTTP請求頭:
Accept:瀏覽器能處理的內容:application/json
content-type:請求內容的資料格式,text/plain application/x-www-form-url application/x-www-form-urlencoded multipart/form-data application/json
Accept-Encoding:瀏覽器能處理的壓縮方式,gzip
Connection:連線型別,colse,keep-alive之類的
Cookie:當前頁面的Cookie,自動帶上的
Host:請求頁面所在的域
Referer:請求頁面的URI地址
User-Agent:ua
JS高階技巧:
0.高階函式:函式作為引數傳入或者函式內返回函式
1.懶載入
2.函式繫結,call,bind,apply
3.函式柯里化【目的是程式碼解耦,把各自的邏輯拆分到不同的函式】:是把接受多個引數的函式變換成接受一個單一引數(最初函式的第一個引數)的函式,並且返回接受餘下的引數而且返回結果的新函式的技術
普通: function add(x, y) {return x + y }
柯里化函式:
function curryingAdd(x) {
return function (y) {
return x + y
}
}
傳入callback,從而減少函式引數,就是把多個引數的函式轉化為多個函式巢狀呼叫,把引數一個個獨立出來
4.Object.preventExtentions():防止新增屬性;
Object.seal()密封:就是把configurable設定為false,不能刪除,也不能用Object.defineProperty來修改屬性設定
Object.freeze()冰凍: 不能做任何修改
5.資料分塊 ,防止單個資料處理太久或者超出瀏覽器限制
6.函式節流:onresize事件,或者連續在input框內輸入內容,不斷連續傳送ajax是沒有必要的,用setTimeout和clearTimeout來減少計算
7.觀察者模式:subject就是被觀察者,subject.subscribe()裡面的函式就是觀察者;
8.web worker:來多執行緒處理資料【js是單執行緒的,有的瀏覽器支援web worker 多執行緒處理資料】; 主要是同源限制和dom限制
8.1 同源限制:分配給 Worker 執行緒執行的指令碼檔案,必須與主執行緒的指令碼檔案同源。
8.2 DOM 限制:Worker 執行緒所在的全域性物件,與主執行緒不一樣,無法讀取主執行緒所在網頁的 DOM 物件,也無法使用document、window、parent這些物件。但是,Worker 執行緒可以navigator物件和location物件。
8.3 通訊聯絡 : Worker 執行緒和主執行緒不在同一個上下文環境,它們不能直接通訊,必須透過訊息完成。
8.4 指令碼限制 : Worker 執行緒不能執行alert()方法和confirm()方法,但可以使用 XMLHttpRequest 物件發出 AJAX 請求。
8.5 檔案限制: Worker 執行緒無法讀取本地檔案,即不能開啟本機的檔案系統(file://),它所載入的指令碼,必須來自網路
用法:注意,和window.postMessage的跨域通訊做區分
//主執行緒上
w=new Worker("demo_workers.js");
worker.onmessage = function (event) {
console.log('Received message ' + event.data);
doSomething();
}
worker.postMessage('Work done!');
w.terminate();//終止
//子執行緒上【可以多個子執行緒,然後主執行緒和子執行緒之間透過onmessage和postMessage通訊】
self.addEventListener('message', function (e) {
self.postMessage('You said: ' + e.data);
}, false);
self.close()//用於在 Worker 內部關閉自身
//被觀察者
var subject = {
eventTypes : [], //被觀察者的所有事件,[{key:'',actionList:[]}],裡面的actionList是訂閱這個事件的觀察者列表
//釋出
publish: function(actionType, newVal) {
(this.eventTypes || []).forEach(function(evt) {
if (evt.key == actionType) {
(evt.actionList || []).forEach(function(action) {
action(newVal);
});
}
});
},
//訂閱:key是訂閱的事件,callback就是觀察者
subscribe: function(key, callback) {
var tgIdx;
var hasExist = this.eventTypes.some(function(unit, idx) {
tgIdx = (unit.key === key) ? idx : -1;
return (unit.key === key)
});
if (hasExist) {
if (Object.prototype.toString.call(this.eventTypes[tgIdx].actionList) === "[object Array]") {
this.eventTypes[tgIdx].actionList.push(callback);
} else {
this.eventTypes[tgIdx].actionList = [callback];
}
} else {
this.eventTypes.push({
key: key,
actionList: [callback]
});
}
},
//取消訂閱:函式沒寫完,key是事件型別,name是觀者者名稱【其實就是函式名稱】,這裡是把key這個事件整體刪除了,如果設定了name的話,只要刪除裡面的actionList裡面對應的function即可
remove: function(key,name) {
var removeIdx;
this.eventTypes.forEach(function(evt, idx) {
removeIdx = evt.key === key ? idx : -1;
return evt.key === key
});
if (removeIdx !== -1) {
this.eventTypes.splice(removeIdx, 1);
}
}
};
subject.subscribe("click",function(){});// function(){}就是觀察者,這個觀察者訂閱這個事件,一旦subject.pushlish("事件名稱",val)觸發事件,所有的觀察者都能獲得通知以及釋出者提供給的資料,執行function
BOM介面:
window.performance:相容ie9+和android4.0+;可以統計頁面載入效能+頁面是否透過back按鈕返回【window.performance.navigation.type】
type的值對應的含義:
0:網頁透過點選連結、位址列輸入、表單提交、指令碼操作等方式載入,相當於常數performance.navigation.TYPE_NAVIGATE。
1:網頁透過“重新載入”按鈕或者location.reload()方法載入,相當於常數performance.navigation.TYPE_RELOAD。
2:網頁透過“前進”或“後退”按鈕載入,相當於常數performance.navigation.TYPE_BACK_FORWARD。
255:任何其他來源的載入,相當於常數performance.navigation.TYPE_RESERVED。
performance.navigation.redirectCount:表示網頁經過重定向的次數。
HTML5:常用的且支援ie9+的標籤
1.canvas :功能型別:畫布
2.video,audio :資源型別
3.aside,header,footer,nav,section,article:語義化
CSS3:裝置和平臺區分,佈局,動畫,特效樣式【4大類】
多媒體查詢【針對不同的媒體裝置用不同的表現方式】:@media ,用於設定android,iphone,pc或者寬度限制的情況下,例如@media screen and (min-width: 480px) {寬度大於480的裝置上用到的css}
可以用and來新增限制條件
//樣式特效
邊框:border-radius,box-shadow,
漸變:linear-gradient,背景顏色中可使用
旋轉變換【2D和3D】: transform:translate【平移】,rotate【旋轉】,scale【縮放】,skew【座標軸傾斜】,matrix【包含以上所有功能的綜合屬性】
//動畫
過度動畫: transition 【屬性名稱,過度時間,過度方式(線性過度),延遲多久開始】:e.addEventListener("transitionend", function() {})//監控動畫,每部可以透過e.target來判斷是那個元素,就可以判斷是那個動畫了
.originstyle{
width:100px;
}
.animat{
width:200px
transition: width 2s linear|ease-in|ease-out|ease-in-out 1s;
}
原來有一個originstyle的class,然後新增animat;這個裡面的動畫就會按照transition的描述效果轉變
自定義動畫【有from和to,可以設定時間百分比,更加自由】: keyframes 【定義動畫名稱和大概的變化】+animation【名稱(和keyframes對應),時間,過渡方式,延遲,播放次數,是否下一個週期逆回放,是否執行】
@-webkit-keyframes haha1 {
0% {
-webkit-transform: rotate3d(0, 0, 0, 0deg);
}
50% {
-webkit-transform: rotate3d(0, -0.5, 0, 180deg);
}
100% {
-webkit-transform: rotate3d(0, -1, 0, 360deg);
}
}
.img{
width: 200px;
height: 200px;
border-radius: 50%;
-webkit-animation: haha1 3s linear infinite;//這裡需要相容寫法哈我這裡沒處理
}
object.addEventListener("animationend", myScript); //監控animation事件,透過e.target目標不同,來判斷是那個動畫
//佈局
inline-block
響應式設定:max-width,min-width,百分比寬度
width:calc(100% -50px) 意思是總寬度減去50px後的寬度
flex-box:彈性盒子,用於彈性佈局!!!!!!!
普通盒模型:content+padding+border+margin:設定的width就是content
box-sizing屬性[不包含margin,是css的3屬性]:
#example1 {
box-sizing: border-box;//
預設content-box :設定的width是content的width
border-box:設定的width是content+padding+border的總寬度,不是content的寬度
}
語法糖:對某個語言增加某種語法,對語言本身沒有影響,只是增加它的可閱讀性和可使用性
https://www.w3cschool.cn/escript6/escript6-6frp37f9.html學習到了generator函式,到了throw函式還沒學
ES6: 解構,擴充套件運算(整合interator介面的資料都可以,所以除了object[純物件],number,bool,null,undefined,其他基本都可以),預設值,常量和區域性變數,字串處理
es6核心概念:Proxy,Promise ,Iterator ,Generator,async,Class,Module
Proxy:代理, new Proxy(obj, {
get: function (target, propKey, receiver) {
console.log(`getting ${propKey}!`);
return Reflect.get(target, propKey, receiver);
},
set: function (target, propKey, value, receiver) {
console.log(`setting ${propKey}!`);
return Reflect.set(target, propKey, value, receiver);
}
});
除了set,get,還有其他各種攔截方式,分別針對js物件的各種行為
相當於給一個物件obj設定代理,任何屬性的獲取和設定,都要先透過這個函式,這個其實類似於Object.defineProterty,在裡面設定get和set,所有的行為也是會透過defineProterty中的get和set
不同在於defineProterty是針對單個屬性設定的攔截,而Proxy是對所有屬性無差別攔截,當然攔截裡面也可以再細分針對不同屬性做出不同攔截
//遍歷字串和其他複雜資料型別,統一用for of
Iterator:它是一個遍歷器介面,只要給某個資料型別部署這個介面,那麼它就可以用這個介面裡面的方法【只要是for of和...】
裡面有很多方法,object沒有包含這個介面,除了string的其他4種基礎資料型別也沒有,剩下的幾乎全有
支援Iterator的原生資料型別:String,Array,Map,Set,TypedArray,函式的 arguments 物件,NodeList 物件
雖然物件沒有繼承Iterator,但可以取巧來遍歷物件:for (var key of Object.keys(someObject)){console.log(key,someObject[key])}
<!-- async 函式【es2017】就是將 Generator 函式的星號( * )替換成 async ,將 yield 替換成 await ,用async函式【語法】代替Generator函式【語法】>
Generator函式【主要用在後端開發,協程】: 首先,他是一個Iterator物件【遍歷器物件】的生成函式,就是呼叫Generator函式會生成一個遍歷器物件
【ES6 規定這個遍歷器是 Generator 函式的例項,雖然沒有用new;所以這個物件繼承Generator的prototype
帶*函式,裡用yeid來表示各種停頓狀態;用next()一次次分步執行;
1.呼叫 Generator 函式後,該函式並不執行,返回的也不是函式執行結果,而是一個指向內部狀態的指標物件,也就是上一章介紹的遍歷器物件(Iterator Object)!!!!
2.第一次呼叫next(),遇到第一個yield就停止,返回的是第一個遇到的yield後面的值【其實就是執行到yield後面緊跟的表示式就停止了】;
3.第二次呼叫next(),執行的是第一個yield和第二個yield之間的語句+第二個yield後面的那個表示式【這個作為返回語句】
4.yield和後面的表示式是一個整體,下次條用next()如果賦值了,那麼從原來停止的那個yield表示式後會被這個值替代,如果沒有賦值,那就用undefined來替代上一步的那個yield表示式整體
5.這裡有一個細節,非常關鍵,如果碰到y= yield(x+5);第一next(),遇到yield就自動停止在了x+5這個表示式的計算,而不會執行下面的y=...;
y= yield(x+5);這裡是包含2個計算的,第一步是x+5,第二部才是把x+5賦值給y,賦值語句計算是從右向左傳遞計算的;第一個next執行,停頓在了x+5這個yield表示式,
接下來要遇到下一個next()執行,才能讓y被賦值,而下一個y賦值的值就是yield表示式的值,而此時yield表示式的值是從next函式的引數中獲取的。
因為yield表示式本身沒有返回值,或者說總是返回 undefined 。 next 方法可以帶一個引數,該引數就會被當作上一個 yield 表示式的返回值。
執行next()返回的物件的value是yield後面的表示式的值,yield本身沒有任何返回值,只能透過next(值),來給yield賦值
核心是理解yield
0.遍歷器物件呼叫next()返回資料【就是yeid表示式的值】,和函式內部的yeid後表示式賦值,是兩回事,千萬別搞混
1.它是暫停的意思,他後面接一個表示式,執行next(),返回的是一個{value:當前 yield 表示式的值,done:是否結束},
2.yeid停頓是按照語句來停頓的,下一句語句裡如果包含yeid,那它就會在下一句包含yeid的語句之前暫停【以語句為單位,語句是以;為結束的】
3.每次執行next(),裡面如果賦值了
最後一個yield後面如果沒有return,那執行最後的哪個next()返回的就是{value:undefined,done:true}
Promise: 本質上來說,Promise建構函式建立一個promise物件只是用來規範非同步操作的流程,把非同步操作和回撥函式賦值拆分成2斷操作,promise物件構建的時候裡面寫ajax,
並把ajax的成功和失敗的回撥函式賦值給預設的resolve和reject;物件建立,就是執行ajax然後獲取對應狀態的過程,這個物件再用then函式來存放成功和失敗的回撥函式
相當於新增了then的時候,如果ajax請求已經有結果了,就會執行裡面對應的狀態的函式,沒有呼叫then的時候,promise物件就算獲取了ajax資料,也只是改變了狀態,並且被阻塞,
因為then還沒有呼叫
本質一句話:用Promise建構函式去封裝非同步,把非同步的回撥函式獨立出來儲存到promise的介面;然後接下來的透過then定義和執行回撥函式都是同步的過程。
new Promise(function(reject,resolve){
var param={};
傳送ajax請求;
//在ajax的回撥函式里面寫下面的內容
if(請求成功){reject(返回資料)}else{resolve(返回的資料)}
});
特別注意,promise的狀態,無法獲取,只能在對應的resolve,reject繫結的函式中,才能確定她的狀態是fulfiled,reject,pending
pending,reject,fulfiled三種狀態,只執行一遍,一旦出結果,接下來即使再新增非同步函式監聽,還是出相同的結果,這個和事件的非同步不一樣
promise物件的then方法來自定義resove和reject的回撥函式【成功和失敗】
p=Promise.all(p1,p2).then(回撥函式):所有都fulfilled,才執行回撥函式
p=Promise.any(p1,p2).then(回撥函式):只要引數例項有一個變成 fulfilled 狀態,包裝例項就會變成 fulfilled 狀態
Promise.race(p1,p2).then(回撥函式):只要一個例項率先改變狀態, p 的狀態就跟著改變。那個率先改變的 Promise 例項的返回值,就傳遞給 p 的回撥函式。
【es2020才加入】Promise.allSettled().then():等到所有這些引數例項都返回結果,不管是 fulfilled 還是 rejected ,包裝例項才會結束
Set:無重複的類陣列物件;就是和陣列差不多,但是裡面沒有重複的資料
去除陣列重複資料然後再轉回陣列:[...new Set(array)]
Map: 也是個類陣列物件,new Map([[1,2],[3,"4"]]),因為物件的屬性只能是字串,map的屬性可以是“物件”等其他型別
【如果是作為key,這個key是引用地址,所以即使2個內容相同的物件作為key,也是兩個key,引用地址相同才是同一個key】,
不僅限於字串,size獲取大小,set,get函式來設定和獲取屬性,還有has,delete,clear等方法
物件:
Object.setPrototypeOf(obj, proto):把proto設定為obj的原型物件
物件方法簡寫:
var obj={
getName(){}等價於 getName:function(){}
}
函式:
1.箭頭函式【可以和解構賦值一起使用】: item => item+5 :一個引數的箭頭函式
() => 5; 沒有引數的箭頭函式
(num1, num2) => num1 + num2; 多個引數的箭頭函式
(num1, num2) => {num1=3;num2=num1+num2} 多個引數和多條語句的箭頭函式【這裡要特別注意,箭頭函式後面的第一個大括號是解釋為程式碼塊,而不是物件,
所以如果要返回物件,需要用()來包裹物件,或者乾脆用{}包裹物件】
2.擴充套件運算:function add(...values) {} ;values就是arguments的意思,可以有任意個數的引數,配合函式里面使用for of,就可以直接遍歷任意長度的引數
嚴格模式use 'strict'可以再函式第一行使用,只針對這個函式使用嚴格模式【包括函式的引數宣告】
es6規定:只要函式引數使用了預設值、解構賦值、或者擴充套件運算子,那麼函式內部就不能顯式設定為嚴格模式,否則會報錯,不建議用嚴格模式
function foo(){},如何獲取函式名稱 foo.name就能得到“foo”字串
陣列:
擴充套件運算【用於引數宣告和函式執行】:arr=[1,2,3];console.log([...arr]);就是自動打出1,2,3
用於陣列克隆;例如arr=[1,2,3];arr1=[...arr];實現了陣列克隆,如果用ES5,那就是arr1=arr.concat();es5物件克隆是obj={age:24};obj1=Object.assign({},obj);
arr.concat和Object.assign都只是第一層的淺複製,用深複製:JSON.stringify(JSON.parse(obj));
用於陣列連線:arr=[1,2,3];arr1=[4,5];arr2=[...arr1,...arr2];
用於字串轉陣列:str="jeffrey";arr=[...str];這個是很變態的方法,最後得到["j","e","f","f","e","r","y"]!!!!!!!!!!!!
Array.from(arrayLike):把類物件陣列arrayLike轉換成真正的陣列,Map,argumets,Set,NodeList等,等價於[...arrayLike]
變數:
let:塊級作用域 (if,while,for for in等語句裡面)【js本來只有全域性作用域和函式作用域這個2個】
const:常量,不變的
頂層物件:不同宿主環境不同,瀏覽器裡是window; Node 和 Web Worker 沒有window;一般再最外層,用this就可以獲取頂層物件
解構賦值 【解構失敗的變數就是undefined】:
字串解構:let [a,b,v,b]="jeffrey";逐個賦值
陣列解構:let [a,b,c]=[1,2,3];就是分別給三個物件賦值
高階用法就是: [a,b,c]=變數或函式();
物件解構:let {name,age}={name:'jeff',age:24};直接獲得name="jeff";age=24;這種是最常見的
高階用法就是{name,age}=變數或函式();
函式引數解構:function add([x, y]){return x + y;}add([2,3]);等於把2賦給x,把3賦給y
解構用於變數交換:let x=1,y=2;[x,y]=[y,x];
混雜結構:比如一個JSON資料,jsonData={age:24,list:[2,3],persion:{sex:"male"}};
用結構方法:{age,list,persion}=jsonData;提取資料快到起飛,
更加方面的是陣列結構提取json,連屬性名稱都不用,方便到哭:
var jsonData=[{name:"jeff"},56,[4,5]];var [person,a,[b,c]];而且解除只要資料個數對可以無線疊加,例如上面這個,還可能夠繼續解除
var jsonData=[{name:"jeff"},56,[4,5]];var [{name},a,[b,c]],直接把name都拿出來了
!!!不支援正則結構的時候,一般用"55,656_1234".replace(/\d{2},\d{3}\_\d{4}/g,"$1-$2-$3"),返回"55-656-1234";做到獲取特定數值,然後再用"55-656-1234".split("-")獲取各個正則對於的引數,類似下面
正則解構【這個是最強的功能,沒有之一】: let {groups: {one, two}} = /^(?<one>.*):(?<two>.*)$/u.exec('foo:bar'); ;把"foo"賦值給one,"bar"賦值給two :整個太難記,還是用原生好
預設值:
let [x=1,y=2]=[3,4];
let {age=24,name="fds"}={age:25,name:"fdd"};
function getAge (age=25,{name="fs",age=24}){}
遍歷:任何部署了 Iterator 介面的物件,都可以用 for...of 迴圈遍歷: 字串,陣列,物件,Map,Set,
函式每部的arguments,
Generator 函式,
nodeList(用querySelectorAll(".classNameA"),返回的結果)從此都用這個函式
Iterator 介面的物件包含的功能:for...of ;擴充套件運算...(例如conosle.log(...[1,2,3]),分別打出1,2,3)
字串模板:`chenjiajie${age}fdsds`可以再字串中寫入變數,非常方便,字串和變數,不用再用+這麼麻煩連線了
正則:let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u; '2015-01-02'.replace(re, '$<day>/$<month>/$<year>') //最終格式變成'02/01/2015' 這個超級實用
但原來的es5的用法也超級好用,例如:"2012-01-23:15-22-24".replace(/(\d{4})-(\d{2})-(\d{2})\:(\d{2})-(\d{2})-(\d{2})/,"$1年$2月$3日:$4時$5時$分")格式轉換成2012年01月23日15時22分24秒
核心:類和模組的內部,預設就是嚴格模式,所以不需要使用 use strict 指定執行模式。只要你的程式碼寫在類或模組之中,就只有嚴格模式可用。
ES6 不會把類的宣告提升到程式碼頭部,所以先使用類再定義類是會報錯的;
Class: 有例項屬性,例項方法,靜態方法,沒有靜態屬性,更沒有私有屬性和私有方法
只是一個語法糖,方便程式設計師理解和書寫,Class裡面定義的方法和屬性都是enumerable【不可列舉的】
Object.getPrototypeOf 方法可以用來從子類上獲取父類。
屬性表示式:讓變數成為屬性
let methodName = 'getArea';
class Square {
[methodName]() {
// ...
}
}
//如果Class內部想要引用自己,可以先用下面的方式,這個Me就是在自己Class內部對自己的引用,在Class外部是無法引用的
const MyClass = class Me {
getClassName() {
return Me.name;
}
};
父類的靜態方法,可以被子類繼承:靜態方法內部的this,指向的是這個類本身,而不是例項物件
類相當於例項的原型,所有在類中定義的方法,都會被例項繼承。如果在一個方法前,加上 static 關鍵字,就表示該方法不會被例項繼承,而是直接透過類來呼叫,這就稱為“靜態方法”。
super: 【用在子類中引用父類】
1.super 在建構函式中作為函式呼叫,指向父類的constructor且預設在super執行之前會預設執行super=super.bind(this);來繫結this; super() 只能用在子類的建構函式之中
在建構函式中作為物件賦值,super相當於this,但是super.屬性讀取的時候,又是按照指向父類的原型物件來讀取資料的
2.super 作為物件時,在普通方法中,指向父類的原型物件【prototype】;在靜態方法中,指向父類自身。
子類的 proto 屬性,表示建構函式的繼承,總是指向父類。
子類 prototype 屬性的 proto 屬性,表示方法的繼承,總是指向父類的 prototype 屬性
ES6 可以自定義原生資料結構(比如 Array 、 String 等)的子類,這是 ES5 無法做到的。
繼承:
class ColorPoint extends Point {
}
// 等同於
class ColorPoint extends Point {
constructor(...args) {
super(...args);
}
}
但是如果子類要寫自己的例項屬性,就必須按照下面的格式寫建構函式,然後再super(父類引數)【這裡的引數是用父類需要的引數】後面寫this.屬性=...來新增子類自己的例項屬性
在 ES6 之前,社群制定了一些模組載入方案,最主要的有CommonJS和AMD兩種。前者用於伺服器,後者用於瀏覽器。ES6 在語言標準的層面上,實現了模組功能,而且實現得相當簡單,完全可以取代 CommonJS 和 AMD 規範,成為瀏覽器和伺服器通用的模組解決方案。
CommonJS:同步,模組是物件,用require 【"執行時載入",因為只有執行時才能得到這個物件,導致完全沒辦法在編譯時做“靜態最佳化”。】
AMD:seaJs,非同步載入
ES模組化:用import+export;以後瀏覽器會慢慢全部支援這個;ES6 的模組自動採用嚴格模式,不管你有沒有在模組頭部加上 "use strict"; 。
import { stat, exists, readFile } from 'fs';【“編譯時載入”或者靜態載入】
嚴格模式主要有以下限制。
變數必須宣告後再使用
函式的引數不能有同名屬性,否則報錯
不能使用 with 語句!!!!!!!!!!!!!!!!!!!!
不能對只讀屬性賦值,否則報錯
不能使用字首 0 表示八進位制數,否則報錯
不能刪除不可刪除的屬性,否則報錯
不能刪除變數 delete prop ,會報錯,只能刪除屬性 delete global[prop]
eval 不會在它的外層作用域引入變數
eval 和 arguments 不能被重新賦值
arguments 不會自動反映函式引數的變化
不能使用 arguments.callee!!!!!!!!!!!!!!!!!
不能使用 arguments.caller!!!!!!!!!!!!!!!!!
禁止 this 指向全域性物件!!!!!!!!!!!!!!!!!!!!!
不能使用 fn.caller 和 fn.arguments 獲取函式呼叫的堆疊!!!!!!!!!!!!!!!!!!!!
增加了保留字(比如 protected 、 static 和 interface )
方法1【推薦】:import和export用{ firstName, lastName, year }格式
方法2:如果import是整體存在,就用 import * as 別名 from ..., export還是老樣子
方法3:如果用了export default 方法名稱;那麼必須用import “隨意名稱” 來引入,這個引入不能加括號{},但可以用任意名稱代替import的那個函式
require是CMD的方案:require匯入,module.exports匯出
import和export是es6模組化的方案:
核心:ES6的import可以匯入CMD的模組,但是CMD的require方式無法匯入ES6模組;除非你在自己的ES6模組的尾部在加一個module.exports={...};就是給ES6的模組新增了CMD的匯出方式
所以import的時候
1.先確定模組是否是es6模式的模組,如果是cmd模組,就得用import 模組名 from ...;和export default的模組的引用方法是一樣的
2.確定是es6模組,那麼得先看對方的export的格式,如果是default,那還是用import 模組名 from ...來引用
3.確定是es6模組,模組不是export default的方式,那麼就用import * as 別名 from ...全域性引用;或者{ firstName, lastName, year }部分引用,最好使用部分,因為只會載入裡面的一部分
引用的時候就透過“別名.內部方法”來呼叫
//該檔案內部的所有變數,外部無法獲取。如果你希望外部能夠讀取模組內部的某個變數,就必須使用 export 關鍵字輸出該變數
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;
或者定義好變數後直接export { firstName, lastName, year };【推薦】
改名export {
v1 as changedName1,
v2 as changedName2
}
瀏覽器載入 ES6 模組:<script type="module" src="./foo.js"></script> 屬於非同步載入
CommonJS 模組輸出的是一個值的複製,ES6 模組輸出的是值的引用。
CommonJS 模組是“執行的時候載入”,ES6 模組是“編譯時輸出介面”,所以es6是部分載入, CommonJS是全部載入
Node.js 要求 ES6 模組採用 .mjs 字尾檔名。也就是說,只要指令碼檔案裡面使用 import或者 export 命令,那麼就必須採用 .mjs字尾名。Node.js 遇到 .mjs檔案,就認為它是 ES6 模組,預設啟用嚴格模式,不必在每個模組檔案頂部指定 "use strict"。
如果不希望將字尾名改成 .mjs ,可以在專案的 package.json 檔案中,main是cmd入口,module是es6入口
"main": "lib/index.js", CMD載入入口
"module": "es/index.js", ES6模組載入入口
如果這時還要使用 CommonJS 模組,那麼需要將 CommonJS 指令碼的字尾名都改成 .cjs 。如果沒有 type 欄位,或者 type 欄位為 commonjs ,則 .js 指令碼會被解釋成 CommonJS 模組。
總結為一句話: .mjs 檔案總是以 ES6 模組載入, .cjs 檔案總是以 CommonJS 模組載入, .js 檔案的載入取決於 package.json 裡面 type 欄位的設定。
Node.js 對 ES6 模組的處理比較麻煩,因為它有自己的 CommonJS 模組格式,與 ES6 模組格式是不相容的。目前的解決方案是,將兩者分開,ES6 模組和 CommonJS 採用各自的載入方案。
//package.json:知識點,預設JSON中的"main"屬性對應的地址是入口檔案地址;但如果又exports欄位且裡面的某個屬性別名是.,例如"export":{".":"adf.js"};那麼模組的入口地址就是adf.js
package.json 檔案的 exports 欄位可以指定指令碼或子目錄的別名
正常來說,es6模組用import載入export輸出,commonJS模組用require載入module.exports輸出;如果 import 命令載入 CommonJS 模組,只能整體載入,不能只載入單一的輸出項。最怕用import {}來載入commonJS模組,會報錯;
所以import之前,要確保它是es6的標準模組。雖然es6模組能相容載入cmd模組,但是cmd的require命令不能載入es6模組
Node.js 的 import 命令只支援載入本地模組( file: 協議)和 data: 協議,不支援載入遠端模組。另外,指令碼路徑只支援相對路徑,不支援絕對路徑(即以 / 或 // 開頭的路徑)
Node 的` import ``命令是非同步載入,這一點與瀏覽器的處理方法相同。
ES6 模組應該是通用的,同一個模組不用修改,就可以用在瀏覽器環境和伺服器環境。為了達到這個目標,Node 規定 ES6 模組之中不能使用 CommonJS 模組的特有的一些內部變數。
commonJS執行原理:
1.CommonJS 模組的重要特性是載入時執行,即指令碼程式碼在require的時候,就會全部執行
學習地址:https://cn.vuejs.org/v2/guide/syntax.html:看到style和Class
VUE學習:Vue 元件不需要任何 polyfill,並且在所有支援的瀏覽器 (IE9 及更高版本) 之下表現一致。必要時,Vue 元件也可以包裝於原生自定義元素之內。
VUE功能: 1.資料和dom展示自動繫結,修改資料時候dom自動更新[基礎]
2.DOM屬性,事件,是否展示【過度動畫】;內容文字4大塊控制
3.V-model:html互動元素【input等可改變內容的元素】,和data雙向繫結【打他修改,互動元素的內容也會變(基礎);但互動元素修改,data也自動邊(這個本來需要自己監聽事件然後手動修改data)】
4.元件化+元件通訊
5.建立流程【具體看流程圖】:資料監聽【Proxy或者Object.definePropertyies等】,模板渲染【根據模板建立虛擬dom】,根據模板建立dom然後把資料掛載到dom上實現資料繫結【data改變,dom更新】
6.生命週期:beforeCreate,created,beforeMount mounted;vue關聯的函式上別用箭頭函式
7.模板渲染語法:mustache,{{name}},括號裡面可以是表示式,但不能是js其他語句,例如if,else,for迴圈;同時模板內很多全域性變數都不能訪問:其實模板內最好只放資料,其他邏輯都在外面做好
8.某個標籤設定v-html,相當於設定innerHtml,許可權較大,容易造成xss攻擊
9.指令: v-bind(縮寫是:),v-on(縮寫是@),v-if,v-for :這些指令都有對應的修飾符,比如v-on:submit.prevent,就是觸發submit事件的時候呼叫preventDefault函式
v-bind:<a v-bind:[attributeName]="url"> ... </a>,2.6版本開始,支援變數名和表示式書寫動態屬性
10.事件修飾符:修飾符可以串聯,比如@click.stop.prevent=...
.stop :不冒泡
.prevent :阻止預設事件
.capture 【事件捕獲模式,按照事件捕獲先處理外面繫結這個元素,再向裡面傳遞】,
.self:點選自己,不是冒泡點選
.once:支觸發一次
.passive: 用於滾動時候提高效能,v-on:scroll.passive="onScroll" ;.passive 和 .prevent 一起使用,因為 .prevent 將會被忽略,同時瀏覽器可能會向你展示一個警告
順序很重要,v-on:click.prevent.self 會阻止所有的點選,而 v-on:click.self.prevent 只會阻止對元素自身的點選。
Vue深入:模板解析【涉及AST】,資料繫結,虛擬DOM[VNode],diff演算法[深度優先遍歷,同層對比]
vue2.X的天坑:vue無法檢測陣列的長度,因為是用defineProperties來監控屬性的,length無法監控
偵聽和計算屬性:methoded,computed,watch
10.computed和method,同樣用於計算屬性,method每次執行都會重新計算,重新渲染;
mothods無快取,computed擇會快取,computed裡面是屬性是依賴於其他屬性的,只要其他依賴的屬性都沒有變動,computed裡面的屬性也就不會變動
例如下面的reversedMessage,computed裡面的reversedMessage獲取的時候,只要它依賴的message沒有變化,那麼每次獲取computed裡面的reversedMessage用於渲染的時候,
和reversedMessage這個屬性繫結的dom就不會重新渲染,但是methods裡面的reversedMessage每次獲取它然後渲染,就是重新渲染
computed: {
// 計算屬性的 getter
reversedMessage: function () {
// `this` 指向 vm 例項
return this.message.split('').reverse().join('')
}
}
methods: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
computed裡面的屬性是依賴其他屬性的,透過其他屬性計算得到的,所以才叫computed,用computed比watch更加好用,多用它;而且computed可以不單單是get,還有set,
也就是說不單單firstName或lastName改變的時候 ,會重新渲染fullName所在的dom,還可以透過修改fullName,來直接修改和他關聯屬性,做到資料聯動更改
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
11.watch,監控屬性,某些屬性變化了,就自動執行函式,函式里面修改和他關聯的操作,開銷比較大,能用computed實現,就別用watch;
和computed的差別是,computed是裡面資料型別簡單的依賴,就是某個資料值依賴於其他資料,其他資料改變,它也跟著變,
但如果某個資料,依賴非常多的資料,涉及非同步操作之類的,複雜的計算,用watch
watch用於觀察和監聽頁面上的vue例項,當然在大部分情況下我們都會使用computed,但如果要在資料變化的同時進行非同步操作或者是比較大的開銷,那麼watch為最佳選擇。watch為一個物件,鍵是需要觀察的表示式,值是對應回撥函式。值也可以是方法名,或者包含選項的物件。直
v-for:<div v-for="item of items"></div> 或<div v-for="item in items"></div>都可以:遍歷數字或者物件內屬性 <div v-for="(value, name) in object">
1.在 v-for 塊中,我們可以訪問所有父作用域的 property。v-for 還支援一個可選的第二個引數,即當前項的索引。
2.當 Vue 正在更新使用 v-for 渲染的元素列表時,它預設使用“就地更新”的策略。如果資料項的順序被改變,Vue 將不會移動 DOM 元素來匹配資料項的順序,而是就地更新每個元素
為了給 Vue 一個提示,以便它能跟蹤每個節點的身份,從而重用和重新排序現有元素,你需要為每項提供一個唯一 key attribute:
<div v-for="item in items" v-bind:key="item.id">
<!-- 內容 -->
</div>
所以,如果不改變順序,可以不用key,來提升效能;如果要改變順序,就必須用key
元件:任何資料都不會被自動傳遞到元件裡,因為元件有自己獨立的作用域。為了把迭代資料傳遞到元件裡,我們要使用 prop,例如下面的【item,index,key】
<my-component
v-for="(item, index) in items" //輸出多個my-component
v-bind:item="item"
v-bind:index="index"
v-bind:key="item.id"
></my-component>
非同步載入元件://然後把<login v-if="true" ></login>插入到當前vue元件或者物件的template裡面,用v-if控制它的動態載入
就是v-if裡面的變數不為ture就不會載入,變數變成ture的時候,就會自動
動態載入這個元件;
{
mounted:{},
components:{
"login": () => import('./components/login'),
"regist": () => import('./components/regist'),
"editor-wrapper": () => import('./components/article-edit'),
"personal-article": () => import('./components/article-list'),
"article-display": () => import('./components/article-display')
}
}
事件: !!!!!!下面好像說得不對,我自己寫js的時候,直接可以正常繫結@click=函式控制代碼,引數中依然可以獲得事件e!!!!!!
在click裡面呼叫函式的方式沒傳入原生事件event,如果不需要,直接不加括號即可
vue中的事件都是vue模仿原生事件,如果想監聽原生click事件,可以用v-on:click.native=""
<button v-on:click="warn($event)">
Submit
</button>
methods: {
warn: function (event) {
// 現在我們可以訪問原生事件物件
if (event) {
event.preventDefault()
}
alert(message)
}
}
表單輸入對應V-model:input textarea select【正常vue都是單向繫結,說到雙向繫結,就是指表單輸入的時候,資料也自動變化】
v-model 會忽略所有表單元素的 value、checked、selected attribute 的初始值而總是將 Vue 例項的資料作為資料來源。你應該透過 JavaScript 在元件的 data 選項中宣告初始值。
text 和 textarea 元素使用 value property 和 input 事件;
checkbox 和 radio 使用 checked property 和 change 事件;
select 欄位將 value 作為 prop 並將 change 作為事件
修飾符: .number:<input v-model.number="age" type="text"> 輸入數字; <input v-model.trim="msg">輸入自動去首尾空格
元件上使用v-model 【還是不太建議,最好是自己寫邏輯,容易讓別人搞混】,
1.首先需要設定元件傳入的值屬性是value
2.在其 input 事件被觸發時,將新的值透過自定義的 input 事件丟擲【很麻煩,而且還是預設邏輯必須寫,不如自己寫邏輯】
v-model其實就是個語法糖,
<input v-model="userName" />其實就是
<input :value="userName" @input="userName = $event.target.value" />的簡寫
元件:
Vue.component('button-counter', obj);裡面的obj的資料結構和new Vue(obj)的一樣
元件定義好以後,每次在html中使用<button-counter></button-counter>,都會自動建立一個例項,所以它們是相互獨立的
//全域性元件
元件的定義:Vue.component('component-a', obj):全域性元件【因為全域性,所以不設定el】
元件使用: <div id="app"><component-a></component-a></div>,
//區域性元件
元件定義:ComponentA=require("...");ComponentB=require(...);require返回的是一個Object物件,例如Login={data(){},computed:function(){},methods:{funcA:function(){}},template:require("..templatePath")}
new Vue({
el: '#app',
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
基礎元件的自動化全域性註冊:絕大部分頁面要用到的基礎元件,放在公共js裡面,然後用vue元件語法進行全域性定義,
好處是,當前頁面載入了,去下一個頁面就不需要載入這個元件對於的js了,因為在公共模組裡面了
如果基礎元件都各自打在自己頁面的js裡面,就不存在公共的抽離了。
自定義事件定義和執行:<my-component v-on:my-event="doSomething"></my-component> ; this.$emit('my-event')
不要寫成<my-component v-on:myEvent="doSomething"></my-component> this.$emit('myEvent'),因為myEvent會被自動轉小寫myevent
導致this.$emit('myEvent')事件觸發失敗,得用this.$emit('myevent')!!!!!!!!!!!!
元件作用域:父級模板裡的所有內容都是在父級作用域中編譯的;子模板裡的所有內容都是在子作用域中編譯的。
所以子模板要訪問父模板的資料正常來說是不可能的,只能透過父模板傳遞給子模版屬性,然後子模版透過props中對應的屬性才能訪問
//插槽定義+元件使用的時候內部插槽內容如何填入
插槽:slot和slot-scope全部棄用,改成統一的v-slot,詳細可以看具名插槽,插槽內部是無法訪問元件的具體詳細的,所以需要給插槽傳遞資料
<span>
<slot v-bind:user="user">
{{ user.lastName }}
</slot>
</span>
動態插槽,其實就是給插槽的名字改成變數,
<base-layout>
<template v-slot:[dynamicSlotName]>
...
</template>
</base-layout>
插槽定義:
1.比如某個component名稱是v-component;
那麼component內容定義的時候,就可以帶入插槽<div v-bind:href="url" class="nav-link"> <v-slot></v-slot> </div>,
使用的時候<v-component>jeffreychen</v-component>,這個Jeffreychen就會自動替換component中的v-slot,這個是最基本的
2.如果一個元件裡面帶了多個插槽【用name來區分】,雖然元件定義的時候引入插槽很容易,例如
元件v-component的定義如下:
<div class="container">
<slot name="header"></slot>
<span>452</span>
<slot name="footer"></slot>
</div>
但元件使用的時候,如何區分插槽呢?用法如下
<v-component>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<template v-slot:default>
<span>default Content</span>
</template>
<template v-slot:footer>
<span>55556666</span>
</template>
</v-component>
但是這個v-slot:default有啥作用,假如v-component定義的時候沒有設定v-slot的name就會使用default
<div class="container">
<slot ></slot>
<span>452</span>
<slot name="footer"></slot>
</div>
動態元件:
<component v-bind:is="currentTabComponent"></component>
只要修改is後面的名稱,就可以修改成對應的元件currentTabComponent是可以動態改變的,是個元件名稱
動態元件快取:元件切換的時候,原來的元件會被快取起來
<keep-alive> <component v-bind:is="currentTabComponent"></component> </keep-alive>
非同步元件: 某個頁面不一定會載入,只有特殊情況偶爾才會載入的元件,就做成非同步元件,非同步下載這個元件
{//父元件物件
components:{
"login": () => import('../../components/login'),
"regist": () => import('./components/regist'),
"article-edit": () => import('../../components/article-edit'),
"article-list": () => import('../../components/article-list'),
"article-display": () => import('../../components/article-display'),
"search-list": () => import('./components/search-list'),
"user-pop": () => import('../../components/user-pop')//通用的右上角的個人登陸狀態按鈕元件
},
}
然後在組建呼叫的時候用v-if即可,例如 <async-webpack-example v-if="needLoad"></async-webpack-example> needLoad是變數,控制這個元件什麼時候載入,它在store裡面被設定為true的時候,元件就非同步載入了
元件之間的相互訪問和原生dom訪問:推薦透過vuex來管理元件之間的通訊,而不是用下面的訪問方式,vuex便於管理
訪問上層元件:
this.$root:根元件
this.$parent:父元件
訪問子元件:【非同步載入的元件,不能透過ref來訪問】
首先給子元件定義的時候新增 ref="name1",然後在父元件上可以透過this.$refs["name1"]來訪問這個子元件
注意:非萬不得已別用$refs,$refs 只會在元件渲染完成之後生效,並且它們不是響應式的。
這僅作為一個用於直接操作子元件的“逃生艙”——你應該避免在模板或計算屬性中訪問 $refs
注意: 多看深入響應式原理:已經看懂了,很簡單
0.Vue用到了Object.defineProperty ,它是 ES5 中一個無法 shim 的特性,這也就是 Vue 不支援 IE8 以及更低版本瀏覽器的原因。
0.Vue 不能檢測陣列和物件的變化,所以傳入的時候,屬性得定義好,新增的不能被監控;Vue 無法檢測 property 的新增或移除
所以,唯一的解決辦法就是,把整個陣列或者整個物件替換成新的陣列或物件【指標是新的,這樣才能觸發data和template的重新繫結】
0.如果出現max stack size exceeded錯誤,大多數是元件或者邏輯遞迴無限迴圈導致的,元件迴圈引用要特別注意
1.元件裡面的data是一個function,function裡面返回一個物件{data:{}},這樣保證每個例項呼叫的時候,返回的data都是獨立的object
如果data是一個object,那麼所有元件就會共用這個object,無法做到相互獨立。
2.每個元件只有1個根元素
3.父元件傳遞屬性給子元件,子元件透過 props: ['屬性名']來接受父元件的資料傳遞
子元件屬性props是從父元件那邊獲得的,子元件的props中定義的屬性名,不能和例項屬性重名【例如data,computed,methods】
//父元件
new Vue({
el: '#blog-posts-events-demo',
data: {
posts: [/* ... */],
postFontSize: 1
}
})
<div id="blog-posts-events-demo">
<div >
<blog-post
v-bind:post="post" 【傳遞post資料給子元件】
></blog-post>
</div>
</div>
//子元件
Vue.component('blog-post', {
props: ['post'],
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<button>
Enlarge text
</button>
<div v-html="post.content"></div>
</div>
`
})
4.注意在 JavaScript 中物件和陣列是透過引用傳入的,所以對於一個陣列或物件型別的 prop
來說,在子元件中改變變更這個物件或陣列本身將會影響到父元件的狀態。
5. this.$el訪問到原生dom,因為vue的dom渲染佇列是非同步的,得用Vue.nextTick裡面的callback來更新原生dom,解決非同步的問題
Vue.nextTick(function () {//意思是等vue的dom渲染完成後,在修改對應的dom,不然就算修改了dom,也可能被vue的非同步的dom渲染給覆蓋
vm.$el.textContent === 'new message'
})
6.data資料結構一開始就定好,一旦和view繫結,再去新增里面的屬性就沒用了
7.需要特別注意的是,html裡面的屬性是不分大小寫的,所以變數attributeName的值,只能是小寫的字串,有大寫的字母也會自動被轉成小寫!!!!!!!!!!!!!!!
8.因為有些表現裡面只允許存放特定的標籤,比如ul裡面只能放li,如果在ul裡面放一個元件,這個元件會被瀏覽器預設為意外的標籤,導致解析出錯,無法正常在table裡面放元件
所以需要is屬性,作用是把這個標籤替換為元件例如:<ul><li is="todoComponent" ></li></ul>,todoComponent的template其實就是li元素,用is就直接把todoComponent替換成了當前的li
因為如果直接用<ul><todoComponent></todoComponent></ul>,瀏覽器預設認為ul裡面必須放li,所以會導致解析出錯;但div這種標籤裡面放元件就完全沒有問題,因為這些標籤裡面沒有限制必須使用什麼標籤
但如國你把這些內容不是寫在html裡面,而是用template字串來實現,就完全沒必要用<li is="todoComponent" ></li>來代替<todoComponent></todoComponent>,模板引擎會自動解決這個問題
特別建議元件的html用template引入,而不是元件中寫在一起
VUEX:vue-tools使用
微信小程式開發:https://www.w3cschool.cn/weixinapp/weixinapp-ft5738rb.html
微信開發主要用js,但還是有如下區別:
1.網頁開發渲染執行緒和指令碼執行緒是互斥的,這也是為什麼長時間的指令碼執行可能會導致頁面失去響應,而在小程式中,二者是分開的,分別執行在不同的執行緒中。
2.小程式邏輯層是在jsCore中執行,所以和瀏覽器不同【BOM,DOM無法使用】;和Node環境也不太一樣【依賴node環境的某些npm也無法使用】
3.小程式的開發需要經過申請小程式帳號、安裝小程式開發者工具、配置專案等等過程方可完成。
css:【css的規範版本,以及各個瀏覽器對css版本的支援!!!!!!!!!!!!!!】
css和模型型別:
0.普通盒模型,就是content padding border margin ;設定的width=content的width;而box-sizing屬性可以設定另一個盒模型,就是border-box,width=content+padding+border
1.box-sizing:content-box和border-box
0.css自適應佈局【2列,3列;寬度固定,不固定】
頁面由3種型別的box組成:每類box指向不同的渲染規則
1. inline box
2. block box
3. run-in box
FC:它是頁面中的一塊渲染區域,並且有一套渲染規則,它決定了其子元素將如何定位,以及和其他元素的關係和相互作用;主要由BFC和IFC,BFC是相互獨立,用處見下面3點
BFC用處:
1.設定塊元素為BFC,讓塊元素垂直margin不和其他塊元素重疊
2.去除因為float定位造成的內容環繞
3.子元素浮動,父元素不設定高度造成父元素高度塌陷,用BRF讓父元素包含子元素
如何觸發BFC:【滿足下列的任意一個或多個條件即可】:脫離文件流,overflow非預設,display特殊值
1、float的值不是none。【脫離文件流】
2、position的值不是static或者relative。【脫離文件流:absolute和fixed】
3、display的值是inline-block;table-cell、table-caption;flex、inline-flex
4、overflow的值不是visible【非預設值】
1.html可以分:替換元素【有src或href替換展示元素內容】和非替換元素
2.行內元素和塊元素【核心是行內和塊的展示,其實和元素無關,展示型別分行內和塊】:行內元素可繼承塊元素,反之不行;塊元素獨立成行,後面不會跟其他任何元素
核心:display:inline和block;inline-block;
3.在css內支援@import url type;可以插入其他css【css檔案中或style標籤中使用】
url表示css地址,type表示css用於那種展示型別,預設是all
//不太建議使用:查詢標籤已經很耗費效能了,再新增屬性就更加耗費效能,一般都用class實現查詢
4.css其實還有一個屬性選擇器,例如a[age]{...};表示查詢素有帶有age屬性的a標籤
a[age="2"]{...},表示查詢帶有age屬性為2的所有a標籤
*[age="2"],表示帶有age屬性的所有標籤
a[age="2"][name="jeff"]:多屬性篩選
5.直屬子元素:例如 p>a{...} ,表示p下的第一級子元素a的樣式,不是孫子或者更加後面的子孫
6.兄弟元素:例如p+ul{...},表示和p相鄰的ul元素的樣式
7.子元素:li:first-child,li:last-child,li:nth-child(2)
特別注意,不是li的子元素,而是li本身作為其他元素的第幾個子元素
8.偽類:css2.1下的a標籤支援:link和:visited兩個【未訪問過(包括錨點點選都沒點過);和訪問過】
a標籤偽類書寫順序:link,visited,focus,hover,active
input有一個focus的偽類
靜態偽類:link,visited
動態偽類:focus,hover,active
動態和靜態偽類可以結合,例如a:link:hover{表示沒點選過且狀態下}
9.偽元素:
例如p:first-letter{段落的第一個字樣式};p:first-line{第一行樣式}【只支援p標籤,且只支援color,font,background,margin屬性】
:before和:after屬性;偽類,放在元素內容的開頭或結尾【css2中的寫法】
::before和::after【和上面功能一樣,這個是css3寫法】
css2寫法相容性好,css3寫法渲染效率高,pc端用css2寫法,移動端建議用css3寫法
詳細寫法: p:after{content:"我是誰,我在哪",...其他樣式};content用於表示內容
10.css元素屬性的繼承+權重的計算:就是層疊的意思,也是層疊樣式表的由來【很關鍵】
權重計算:
css2.1支援新增important,例如 span{font-size:24px !important;}:權重超style
內聯樣式style:1000
id權重:100
class權重:10
標籤或偽類權重:1
萬用字元*權重:0
權重計算方法:疊加算總和,比如 p a{權重是1+1};p.classA{權重是10+1}
如果p,a這種聯合形式的宣告,是不疊加的,因為它們只是簡寫而已,拆分成p和a各自計算權重
繼承:【不同瀏覽器繼承都不太一樣,謹慎使用:因為這樣才有reset.css,讓絕大部分瀏覽器標籤表現一致】
繼承都是子孫繼承父元素,只有一個特例,body的背景會傳遞給html
一般行內元素可以繼承塊元素,反之不行;同時屬性有的可以繼承有的不可以;
很雜,不建議用繼承寫樣式,用到繼承的屬性也就font-size和font-style
11.顏色color:rgb(0-255,20,20)或rgb(20%,20%,20%)
#555555或#222
web安全色指的數web瀏覽去可以正確展示的顏色:
16進位制的安全色編碼是#0369CF【用這6個字母任意組成的6位數,都是安全色】:就是3的倍數
長度:em【相對父元素】;rem【相對html元素】,px【最常用的畫素單位:rem支援ie9+,用於響應式】
響應式:百分比,rem,viewport三種解決方案;特定瀏覽器可用flex或grid
背景:background-color,
background-image[背景圖片url]
background-repeat[背景圖片是否重複],
background-attachment[背景影像是否固定或者隨著頁面的其餘部分滾動。]
background-position[背景圖片位置]/
background-size 背景圖片的尺寸。
//css3
background-origin 背景圖相對於那個區域繪製【padding-box;border-box;content-box;】
background-clip 背景的裁剪區域【padding-box;border-box;content-box;】
設定content-box,就是把padding和border上的背景圖都裁剪掉
例如:background: #fff
url("...")
no-repeat
scroll [設定attachment]
top left / 16px 20px 【前面是position,/後是size】
border-box
padding-box
一般只需要寫:#666 url() no-repeat top left;這幾個就可以了
字型:font-family,font-weight,font-style,font-variant【字型變形,預設nomal】等
組合寫法:font-size和font-family必須要有,其他沒有會自動插入預設
font-style font-variant font-weight font-size/line-height font-family
例如:font:italic small-caps bold 12px/1.2em Arial;
常用:font:italic normal normal 12px/1.0em Georgia,serif;
[多個字型,優先用前面的,前面的沒有就用後面的]
塊元素行內縮排:text-indent【第一行縮排】
例如:p{text-indent:4px;}
text-align:塊元素內的行內元素的水平對齊方式【用於塊元素,針對行內元素】
line-height:塊元素內的行內元素的行高【用於塊元素,針對行內元素】
vertical-align:塊元素內的文字行內元素的垂直對齊方式【預設baseline】
對塊元素的居中不起作用,除非是table中的某些塊元素或inline-block
塊元素內內容垂直居中:height和line-height設定相同
字型間距:word-spacing:normal[預設]
text-transform:uppercase[大寫] lowercase[小寫] capticalize[首字母大寫]
text-decoration:underline overline linethorugh blink [字母裝飾]
text-shadow:文字陰影
white-space:對文字中的”空格,換行,tab"的處理
最常用的就是nowrap【不允許換行】
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
css文字流:正常流,非正常流
和文字流相關概念:替換元素,非替換元素;行內元素,塊元素
盒模型:content+padding+border+margin 總體相加是元素整體所佔的寬高
塊級元素:
正常流下,塊元素所佔的寬高就是盒模型中所佔寬高(content+padding+border+margin)
也等於其父元素的content的width
塊級水平屬性:width,padding,margin,border的left和right
只有width和margin可以設定auto,其他必須是有值【無值就用預設值】
如果width和margin全設定了固定值,但受到限制造成了矛盾,margin-right會自動變成auto來適應!!!!
如果with設定了auto,margin固定,那麼widh寬度就受到margin的影響
margin設定負數,會導致元素超出父元素,雖然總和還是和父元素content一樣
如果替換元素的with設定auto,那麼他的寬度是他的src連結所指元素的原本寬度;
如果設定了替換元素的寬度或高度中的一個,比如設定了寬度,那麼高度就會等比例縮放
塊級垂直屬性:height,padding,margin,border的top和bottom
只有height和margin可以設定auto;但垂直margin設定auto就自動變成0,
無法垂直居中;所以垂直居中的方法,是把塊元素的上下margin設定百分比
垂直間距上下margin會重疊
行內元素:行內元素的水平居中用text-align;垂直需要給父元素新增vertical-align來設定
或者設定line-height設定【內容區高度(等於font-size)和行內框】;
行內框高度是line-height;
行內元素也有border和水平的padding+margin
行內元素和塊元素展現形式的轉變:
display:block,inline,inline-block[對內塊元素,對外行內,支援ie8+]
//脫離文件流[float非none;position為absolute或fixed,都會脫離文件流;脫離文件流是會觸發BFC的]
1.浮動[float]: 根據它的包含塊定位【最近的塊級父元素:相對最近的塊級父元素浮動】!!!!
相當於對內部設定了display:block;但因為脫離文件流導致可以和其他元素同行。
和inline-block有點類似,但也有很多區別
float是脫離文件流的,但inline-block沒有
inline-block對外是行內元素,所以可以用vertical-align設定垂直居中
但float不可以用vertical-align設定,它仍然是塊元素展示,只是脫離文件流
設定了浮動,其他元素會環繞這個元素:
行內元素自帶行內框,塊元素自帶塊級框,但是float以後,不管是什麼元素
都是帶塊級框;display的inline或block也是行內框和塊級框的意思
浮動元素的包含塊概念,就是最近包含它的塊元素;浮動的元素是不能超過包含快的content
清除浮動:clear:left,right,both
2.定位[position]:static【正常文件流】,relative【文件流,偏移】,absolute,fixed
relative:不脫離文件流,只是相對於原來的位置做偏移
absolute:脫離文件流,根據position不是static的元素來作為包含塊|或body,來定位
如果包含塊是塊元素,根據該元素的padding定位!!!
如果包含快是行內元素,根據該元素的內容來定位
和float元素不同的是,position為absolute的元素
它可以定位到包含塊的外面
fixed:脫離文件流,根據window視窗定位
z-index:對非static元素或float元素才有效;【float://或position: absoulte relative fixed 】
z-index有祖先元素的概念【最近的設有z-index的float或relative或absolute或fixed元素,會產生一個層,內部所有元素都再這個層上方】;
比如a屬於祖先元素A,A的z-index【relative或absolute或float】為10
b屬於祖先元素B,B的z-index為100
那麼不管a和b的z-index如何設定,ab重疊的時候
b肯定覆蓋在a上面,因為是先比祖先元素的z-index,
再比它們各自的z-index
內容溢位【overflow】:auto,scroll,hidden
ul|ol列表特定樣式:[基本用不上]
list-style-image:url(...)
list-style-position:
游標:cursor:pointer
輪廓:outerline:width,style,color
多媒體語法:
@media screen {
}
@media print{
}