相信你們也和我同樣,2020年的春節過得很是特別。新型冠狀病毒不只對國家仍是對社會以及對咱們的我的都有很大影響!javascript
不少小夥伴內心確定想着因爲種種緣由,內心開始蠢蠢欲動了...css
筆者經過平時面試總結以及面試別人常提的問題,結合本身認爲很是重要的前端各技術棧的知識點,總結了這篇中高級前端面試。讓須要的小夥伴所閱讀,讓不在大廠的小夥伴提早了解大廠前端面試官常問的各類常見前端問題。html
文章有點長,請各位小夥伴耐心閱讀完。相信認真閱讀者一定或多或少有點感悟!前端
我的理解:vue
DTD(document type definition,文檔類型定義)是一系列的語法規則,用來定義XML或(X)HTML的文件類型。瀏覽器會使用它來判斷文檔類型,決定使用何種協議來解析以及切換瀏覽器模式。(DTD告訴瀏覽器我是什麼文檔類型,瀏覽器會根據這個來判斷用什麼引擎來解析和渲染他們)java
DOCTYPE是用來聲明文檔類型和DTD規範的,一個主要的用途即是文件的合法性驗證。若是文件代碼不合法,那麼瀏覽器解析時會出一些錯誤。(DOCTYPE告訴瀏覽器當前是哪一個文檔類型)node
一、什麼是HTML語義化?jquery
二、爲何要使用語義化標籤?webpack
三、 HTML5新特性有哪些?nginx
一、行內元素的特色?
二、塊級元素的特色?
常見行內元素標籤:
a、br、code、em、img、input...
複製代碼
常見塊級元素標籤:
div、p、dl、dt、form、h1~h6...
複製代碼
漸進加強(Progressive Enhancement):
一開始就針對低版本瀏覽器進行構建頁面,完成基本的功能,而後再針對高級瀏覽器進行效果、交互、追加功能達到更好的體驗。
優雅降級(Graceful Degradation):
一開始就構建站點的完整功能,而後針對瀏覽器測試和修復。好比一開始使用 CSS3 的特性構建了一個應用,而後逐步針對各大瀏覽器進行 hack 使其能夠在低版本瀏覽器上正常瀏覽。
二者區別?
一、廣義:
其實要定義一個基準線,在此之上的加強叫作漸進加強,在此之下的兼容叫優雅降級
二、狹義:
漸進加強通常說的是使用CSS3技術,在不影響老瀏覽器的正常顯示與使用情形下來加強體驗,而優雅降級則是體現html標籤的語義,以便在js/css的加載失敗/被禁用時,也不影響用戶的相應功能。
例子:
.transition { /*漸進加強寫法*/
-webkit-transition: all .5s;
-moz-transition: all .5s;
-o-transition: all .5s;
transition: all .5s;
}
.transition { /*優雅降級寫法*/
transition: all .5s;
-o-transition: all .5s;
-moz-transition: all .5s;
-webkit-transition: all .5s;
}
複製代碼
相同點:
不一樣點:
cookie數據大小不能超過4k;sessionStorage和localStorage的存儲比cookie大得多,能夠達到5M+
cookie設置的過時時間以前一直有效;localStorage永久存儲,瀏覽器關閉後數據不丟失除非主動刪除數據;sessionStorage數據在當前瀏覽器窗口關閉後自動刪除
cookie的數據會自動的傳遞到服務器;sessionStorage和localStorage數據保存在本地
盒子由margin(外邊距)、border(邊框)、padding(內邊距)、content(內容)組成
盒子的寬度 = 內容寬度 + 左填充 + 右填充 + 左邊框 + 右邊框 + 左邊距 + 右邊距
盒子的高度 = 內容高度 + 上填充 + 下填充 + 上邊框 + 下邊框 + 上邊距 + 下邊距
box-sizing: content-box(默認)----指的是標準模型(自己內容寬高度+邊框和內邊距)
box-sizing: border-box-----指的是IE模型(自己內容的寬高度)
dom.style.width/height
複製代碼
這種方式只能取到dom元素內聯樣式所設置的寬高,也就是說若是該節點的樣式是在style標籤中或外聯的CSS文件中設置的話,經過這種方法是獲取不到dom的寬高的
dom.currentStyle.width/height
複製代碼
獲取渲染後的寬高。可是僅IE支持
window.getComputedStyle(dom).width/height
複製代碼
與2原理類似,可是兼容性,通用性更好一些
dom.getBoundingClientRect().width/height
複製代碼
計算元素絕對位置,獲取到四個元素left,top,width,height
擴展:
獲取瀏覽器高度和寬度的兼容性寫法:
var w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
var h = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
複製代碼
想詳細瞭解Flex佈局知識點的小夥伴,請查看 Flex佈局詳解
-webkit-font-smoothing在window系統下沒有起做用,
可是在IOS設備上起做用-webkit-font-smoothing:antialiased是最佳的,灰度平滑
一、CSS選擇器:
二、CSS3屬性選擇器:
a[href$='.pdf']:選擇href屬性中以.pdf結尾的元素
a[href^='www']:選擇href屬性中以www開頭的元素
a[href*='tmc']:選擇href屬性中包含tmc的元素
三、CSS3常見僞類選擇器:
:nth-of-type():
:nth-child():
可繼承的屬性:font-size, font-family, color
不可繼承的樣式:border, padding, margin, width, height
優先級(就近原則):!important > [id > class > tag]
!important比內聯優先級高
1、BFC的概念?
BFC(塊級格式上下文):它是頁面中的一塊渲染區域,有本身的渲染規則,決定了其子元素如何佈局,以及和其餘元素之間的關係和做用
2、BFC的原理?
3、如何建立BFC?
4、BFC的使用場景?
1、清除浮動的方法
方式1、使用overflow 屬性來清除浮動
.parent {
overflow: hidden;
}
複製代碼
缺點:離開這個元素所在區域的會被隱藏(overflow: hidden將超出的分佈隱藏起來)
方式2、使用額外標籤法
.clear {
clear: both;
}
複製代碼
缺點:會增長頁面的標籤,形成結構的紊亂
方式3、使用僞元素來清除浮動【推薦使用】
.clearfix:after { content: ""; // 設置內容爲空 height: 0; // 高度爲0 line-height: 0; // 行高爲0 display: block; // 將文本轉爲塊級元素 visibility: hidden; // 將元素隱藏 clear: both; //清除浮動 } .clearfix { zoom: 1; // 爲了兼容IE } 複製代碼
2、定位 posiiton的值:
過渡
動畫
形狀轉換
選擇器
陰影
文字陰影: text-shadow: 2px 2px 2px #000;(水平陰影,垂直陰影,模糊距離,陰影顏色) 盒子陰影: box-shadow: 10px 10px 5px #999
邊框
背景
文字
漸變
彈性佈局、柵格佈局、多列布局
媒體查詢
1. px:絕對單位,頁面按精確像素展現
2. em:相對單位,基準點爲父節點字體的大小,若是自身定義了font-size按自身來計算(瀏覽器默認字體是16px),整個頁面內1em不是一個固定的值
3. rem:相對單位,可理解爲」root em」, 相對根節點html的字體大小來計算,CSS3新加屬性,chrome/firefox/IE9+支持
4. vw:viewpoint width,視窗寬度,1vw等於視窗寬度的1%
5. vh:viewpoint height,視窗高度,1vh等於視窗高度的1%
6. vmin:vw和vh中較小的那個
7. vmax:vw和vh中較大的那個
8. %:百分比
複製代碼
<meta name="viewport" content="width=device-width, initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> initial-scale:初始的縮放比例 minimum-scale:容許用戶縮放到的最小比例 maximum-scale:容許用戶縮放到的最大比例 user-scalable:用戶是否能夠手動縮放 複製代碼
1、行內元素水平垂直居中方法:
方式1:
text-align:center /*水平居中*/
height = 100px; /*垂直居中 */
line-height = 100px;
複製代碼
方式2:
text-align:center 水平居中
display:table-cell; 垂直居中
vertical-align:middle;
複製代碼
2、塊級元素水平居中方法:
margin:0 auto;只能設置水平居中, 而margin:auto 0 不能設置垂直居中 ,由於margin垂直塌陷問題
方法1:定位+margin
父級元素設置position:relative;
兒子元素設置
width: 100px;
height: 100px;
position:absolute;
top:50%;
left:50%;
margin-top:-50px;
margin-right:-50px;
複製代碼
方式2:定位方法
複製代碼
父級元素設置position:relative;
兒子元素設置
position:absolute;
top:0;
bottom:0;
left:0;
right:0;
margin:auto;
複製代碼
方式3:單元格方法
複製代碼
父級元素
display:table-cell;
text-align:center;
vertical-align:middle;
子元素
display:inline-table
複製代碼
什麼事CSS預處理器?
CSS預處理器是一種語言用來爲CSS增長一些變成的特性,無需考慮瀏覽器兼容問題,例如你能夠在CSS中使用變量,簡單的程序邏輯、函數等在編程語言中的一些基本技巧,可讓CSS更加簡潔,適應性更強,代碼更直觀等諸多好處
基本語法區別
Sass是以.sass爲擴展名,Less是以.less爲擴展名,Stylus是以.styl爲擴展名
變量的區別
Sass 變量必須是以$開頭的,而後變量和值之間使用冒號(:)隔開,和css屬性是同樣的。
Less 變量是以@開頭的,其他sass都是同樣的。
Stylus 對變量是沒有任何設定的,能夠是以$開頭或者任意字符,並且變量之間能夠冒號,空格隔開,可是在stylus中不能用@開頭
三種預處理器都有:嵌套、運算符、顏色函數、導入、繼承、混入。Stylus還有一些高級特性。例如循環、判斷等
使用@media查詢能夠針對不一樣的媒體類型定義不一樣的樣式
@media 能夠針對不一樣的屏幕尺寸設置不一樣的樣式,特別是若是須要設置設計響應式的頁面。
重置瀏覽器大小的過程當中,頁面也會根據瀏覽器的寬度和高度從新渲染頁面。
語法:@media 媒介類型 and | not | only (媒介特性) { css 代碼 } 媒介類型: print: 用於打印機和打印預覽 screen: 用於電腦屏幕、平板電腦、只能手機等 all: 用於全部媒體設備類型 媒介特性: device-height: 定義輸出設備的屏幕可見高度 device-width: 定義輸出設備的屏幕可見寬度 height:定義輸出設備中的頁面可見區域高度。 width:定義輸出設備中的頁面可見區域寬度。 max-device-height:定義輸出設備的屏幕可見的最大高度。 max-device-width:定義輸出設備的屏幕可見的最大寬度。 max-height:定義輸出設備中的頁面可見的最大高度。 max-width:定義輸出設備中的頁面可見的最大寬度。 min-device-height:定義輸出設備的屏幕可見的最小高度。 min-device-width:定義輸出設備的屏幕可見的最小寬度。 min-height:定義輸出設備中的頁面可見的最小高度。 min-width:定義輸出設備中的頁面可見的最小寬度。 複製代碼
1. link屬於html標籤,除了引入css樣式之外還能夠定義RSS等其餘事物,@import是css提供的,只能引入css
2. lilnk在頁面加載的時候會同時加載,@import引用的css要等頁面加載結束後再加載
3. link是html標籤,沒有兼容性,@import只有ie5以上才能識別
複製代碼
display: none與visibility: hidden的區別
display:none 不顯示對應的元素,在文檔佈局中再也不分配空間(迴流+重繪)
visibility:hidden 隱藏對應元素,在文檔佈局中仍保留原來的空間(重繪)
二者的做用不一樣,CSS選擇器找到元素後爲設置該元素的樣式,jQuery選擇器找到元素後添加行爲
jQuery選擇器擁有更好的跨瀏覽器的兼容性
二者選擇器的效率不一樣 CSS選擇器的效率:id選擇器(#myid)、類選擇器(.myclassname)、標籤選擇器(div,h1,p)、相鄰選擇器(h1+p)、子選擇器(ul > li)、後代選擇器(li a)、通配符選擇器(*)、屬性選擇器(a[rel="external"])、僞類選擇器(a:hover,li:nth-child)從高到低依次排列
jQuery選擇器的效率:id選擇器('form')、類選擇器
('[attribute=value]')和僞類選擇器$(':hidden')
$("#aijquery"): //這種方式獲取獲得的就是jquery對象 document.getElementById("aijquery")://這種方法獲取到的就是dom對象 複製代碼
dom對象轉換爲jquery對象:通常狀況下,dom對象直接用$()就能夠轉換成jquery對象,如:
$(document.getElementById("aijquery")) 複製代碼
jquery對象轉換成dom對象,有兩種方法,一種是用jquery的內置函數get,來獲取dom對象,如:
$("#aijquery").get(0) 複製代碼
還有一種方法更簡單,由於jquery對象的屬性是一個集合,因此咱們能夠像數組那樣,取出其中一項就行:
$("#aijquery")[0]; $("div")[5]; //上面這兩種返回的都是dom對象,能夠直接使用js裏的方法 複製代碼
5個簡單數據類型(基本數據類型)+ 1個複雜數據類型
undefined、number、string、null、boolean+object ES6新增Symbol
async function async1() { console.log('async1 start'); await async2(); console.log('async1 end'); } async function async2() { console.log('async2'); } console.log('script start'); setTimeout(function() { console.log('setTimeout'); }, 0) async1(); new Promise(function(resolve) { console.log('promise1'); resolve(); }).then(function() { console.log('promise2'); }); console.log('script end'); 複製代碼
1. 第一步,輸出script start;
雖然有兩個函數聲明,有async關鍵字,可是沒有調用,就不看,直接打印同步代碼console.log(‘script start’)
2. 第二步,輸出async1 start; 由於執行async1這個函數的時候,async表達式定義的函數也是當即執行
3. 第三步,輸出async2;
由於async2是async定義的函數,輸出async2並返回promise對象
4. 第四步,輸出promise1;
由於執行到new promise,promise是當即執行,就先打印promise1
5. 第五步,輸出script end;
由於上一步先打印了promise1,而後執行到resolve的時候,而後跳出promise繼續向下執行,輸出script end
6. 第七步,輸出async1 end;
由於await定義的這個promise已經執行完,而且返回結果,因此繼續執行async1函數後的任務,就是console.log(‘async1 end’)
7. 第六步,輸出promise2;
由於前面的nue promise放進resolve回調,因此resolve被放到調用棧執行
8. 第八步,輸出setTimerout; setTimeout被放在最後被調用
複製代碼
document.querySelectorAll('*') 複製代碼
[...document.querySelectorAll('*')] 複製代碼
[...document.querySelectorAll('*')}.map(ele => ele.tagName) 複製代碼
new Set([...document.querySelectorAll('*').map(ele=>ele.tagName)).size 複製代碼
1、typeof
console.log(typeof 1); // number console.log(typeof true); // boolean console.log(typeof 'mc'); // string console.log(typeof function(){}); // function console.log(typeof []); // object console.log(typeof {}); // object console.log(typeof null); // object console.log(typeof undefined); // undefined 複製代碼
優勢:可以快速區分基本數據類型 缺點:不能將Object、Array和Null區分,都返回object
複製代碼
2、instanceof
console.log(1 instanceof Number); // false console.log(true instanceof Boolean); // false console.log('str' instanceof String); // false console.log([] instanceof Array); // true console.log(function(){} instanceof Function); // true console.log({} instanceof Object); // true 複製代碼
優勢:可以區分Array、Object和Function,適合用於判斷自定義的類實例對象 缺點:Number,Boolean,String基本數據類型不能判斷
複製代碼
3、Object.prototype.toString.call()
var toString = Object.prototype.toString; console.log(toString.call(1)); //[object Number] console.log(toString.call(true)); //[object Boolean] console.log(toString.call('mc')); //[object String] console.log(toString.call([])); //[object Array] console.log(toString.call({})); //[object Object] console.log(toString.call(function(){})); //[object Function] console.log(toString.call(undefined)); //[object Undefined] console.log(toString.call(null)); //[object Null] 複製代碼
優勢:精準判斷數據類型 缺點:寫法繁瑣不容易記,推薦進行封裝後使用
複製代碼
如何建立Ajax XMLHttpRequest對象的工做流程 ==========兼容性寫法=========== var xmlHttp = null; if(window.XMLHttpRequset) { // IE7+,Firefox,Chrome,Safari,Opera xmlHttp = new XMLHttpRequset(); } else { // IE5,IE6 xmlHttp = new ActiveXObject("Microsoft.XMLHTTP") } 兼容性處理 事件的觸發條件 xmlHttp.onreadystatechange = function() { if(xmlHttp.readyState == 4 && xmlHttp.status == 200) { responseText、responseXML } } 事件的觸發順序 ======================注意================= 若是是POST請求則須要添加頭 xmlHttp.setRequestHeader("Content-type": "application/x-www-form-urlencoded") 複製代碼
undefined是訪問一個未初始化的變量時返回的值,而null是訪問一個還沒有存在的對象時所返回的值。
undefined看做是空的變量,而null看做是空的對象
實現 (5).add(3).minus(2),使其輸出結果爲6
有題目分析可得,該表達式屬於鏈式調用方法。以數組爲例:
arr.push() 爲何arr有push方法?
由於arr是Array的實例,push是Array原型上的方法,全部實例arr能夠調用原型上的方法;故,咱們只須要在數字Number的原型上添加add和minus方法便可。
~ function () { function add(number) { if (typeof number !== 'number' || Number.isNaN(number)) { throw new Error('請輸入數字~'); } return this + n } function minus(number) { if (typeof number !== 'number' || Number.isNaN(number)) { throw new Error('請輸入數字~'); } return this - n } Number.prototype.add = add Number.prototype.minus = minus }() console.log((5).add(3).minus(2)) // 6 複製代碼
注意:this的指向始終指向最後誰調用了this所在的函數,this就指向誰!
基本概念:DOM事件的級別(事件的本質在於信息的傳遞)
DOM0:element.onlick = function(){} 一是在標籤內寫onclick事件 二是在JS寫onclick=function(){}函數 DOM2:element.addEventListener('click', function(){},false) 三個參數分別表示爲:事件名、事件處理的函數、爲true則表示在捕獲階段調用,爲false則表示在冒泡階段調用 DOM3:element.addEventListener('keyup',function(){},false) DOM事件模型:(冒泡、捕獲...) 冒泡事件是從內向外;捕獲是從外向內======document->html->body->div DOM事件流 一個完整的事件流分爲三個階段:捕獲-》目標階段-》冒泡=========事件經過捕獲到達目標元素再從目標元素經過冒泡上傳到元素 描述DOM事件捕獲的具體流程 捕獲:window->document->html->body->......->目標元素 冒泡:相反 Event事件的用 event.preventDefault() // 阻止默認行爲 event.stopPropagation() // 阻止冒泡行爲 event.stopImmediatePropagation() // 在調用完stopPropagation函數以後,就會當即中止對後續節點的訪問,可是會執行完綁定到當前節點上的全部事件處理程序;而調用stopImmediatePropagation函數以後,除了全部後續節點,綁定到當前元素上的、當前事件處理程序以後的事件處理程序就不會再執行了 event.currentTarget // 指的是綁定了事件監聽的元素(能夠理解爲觸發事件元素的父級元素) event.target // 表示當前被點擊的元素 自定義事件(CustomEvent) var eve = new Event('custom'); eve.addEventListener('custom',function(){ console.log('custom') }) eve.dispatchEvent(eve) 複製代碼
1、深拷貝
1.1 最簡單的方法就是JSON.parse(JSON.stringify())
可是這種拷貝方法不能夠拷貝一些特殊的屬性(例如正則表達式,undefine,function)
1.2 用遞歸去複製全部層級屬性
複製代碼
function deepCopyTwo(obj) { let objClone = Array.isArray(obj) ? [] : {}; if (obj && typeof obj == 'object') { for (const key in obj) { //判斷obj子元素是否爲對象,若是是,遞歸複製 if (obj[key] && typeof obj[key] === "object") { objClone[key] = deepCopyTwo(obj[key]); } else { //若是不是,簡單複製 objClone[key] = obj[key]; } } } return objClone; } 複製代碼
2、淺拷貝
Object.assign(target, ...sources)
複製代碼
function simpleClone(obj) { var result = {}; for (var i in obj) { result[i] = obj[i]; } return result; } 複製代碼
想詳細瞭解,請點擊查看 對象深淺拷貝
想詳細瞭解,請點擊查看 一步步教你實現Promise/A+ 規範 完整版
this表示當前對象,this的指向是根據調用的上下文來決定的,默認指向window對象,指向window對象時能夠省略不寫
全局環境: this始終指向的是window對象
局部環境: 在全局做用域下直接調用函數,this指向window 對象函數調用,哪一個對象調用就指向哪一個對象 使用new實例化對象,在構造函數中的this指向實例化對象 使用call或apply改變this的指向
總結:this始終指向最後一個調用它的函數的對象
1. 箭頭函數不能被直接命名,不過容許它們賦值給一個變量
2. 箭頭函數不能用作構造函數,你不能對箭頭函數使用new關鍵字
3. 箭頭函數也沒有prototype屬性箭頭函數綁定了詞法做用域,不會修改this的指向(**最大特色**)
4. 箭頭函數的做用域不能經過.call、.apply、.bind等語法來改變,這使得箭頭函數的上下文將永久不變
複製代碼
1. let/const
2. 多行字符串/模板變量
3. 解構賦值
4. 塊級做用域
5. 函數默認參數
6. 箭頭函數
複製代碼
當你的簡寫箭頭函數返回值爲一個對象時,你須要用小括號括起你想返回的對象。不然,瀏覽器會把對象的{}解析爲箭頭函數函數體的開始和結束標記。
// 正確的使用形式 **var** objectFactory = () => ({ modular: 'es6' }) 複製代碼
/** * 函數柯里化 * 柯里化(Currying)是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,而且返回接受餘下的參數且返回結果的新函數的技術。 */ // 通用版 function curry(fn, args) { var length = fn.length; var args = args || []; return function() { newArgs = args.concat(Array.prototype.slice.call(arguments)) console.log(newArgs) if(newArgs.length < length) { return curry.call(this, fn, newArgs); } else { return fn.apply(this, newArgs); } } } function multiFn(a, b, c) { console.log(a * b * c) return a * b * c; } var multi = curry(multiFn); multi(2)(3)(4) // multi(2, 3, 4) // multi(2)(3, 4) // multi(2, 3)(4) 複製代碼
單線程,只有一個線程,只能作一件事
緣由:避免DOM渲染的衝突
解決方案:異步
實現方式:event-loop
複製代碼
事件輪詢-----JS異步的解決方案
JS實現異步的具體解決方案
一、同步代碼,直接執行
二、異步代碼先放在 異步隊列 中
三、待同步函數執行完畢,輪詢執行異步隊列 中的函數
複製代碼
1、具體實現步驟:
1. 首先函數接受不定量的參數,第一個參數爲構造函數,接下來的參數被構造函數使用
2. 而後內部建立一個空對象 obj
3. 由於 obj 對象須要訪問到構造函數原型鏈上的屬性,因此咱們經過 setPrototypeOf 將二者聯繫起來。這段代碼等同於 obj.__proto__ = Con.prototype
4. 將 obj 綁定到構造函數上,而且傳入剩餘的參數
5. 判斷構造函數返回值是否爲對象,若是爲對象就使用構造函數返回的值,不然使用 obj,這樣就實現了忽略構造函數返回的原始值
複製代碼
2、 new操做符的特色
1. new經過構造函數Test建立處理的實例能夠訪問構造函數中的屬性也能夠訪問構造函數原型鏈上的屬性,因此:經過new操做符,實例與構造函數經過原型鏈鏈接了起來
2. 構造函數若是返回原始值,那麼這個返回值毫無心義
2. 構造函數若是返回對象,那麼這個返回值會被正常的使用,致使new操做符沒有做用
複製代碼
3、new操做符的幾個做用:
1. new操做符返回一個對象,因此咱們須要在內部建立一個對象
2. 這個對象,也就是構造函數中的this,能夠訪問到掛載在this上的任意屬性
3. 這個對象能夠訪問到構造函數原型鏈上的屬性,因此須要將對象與構造函數連接起來
4. 返回原始值須要忽略,返回對象須要正常處理
複製代碼
/** * 建立一個new操做符 * @param {*} Con 構造函數 * @param {...any} args 忘構造函數中傳的參數 */ function createNew(Con, ...args) { let obj = {} // 建立一個對象,由於new操做符會返回一個對象 Object.setPrototypeOf(obj, Con.prototype) // 將對象與構造函數原型連接起來 // obj.__proto__ = Con.prototype // 等價於上面的寫法 let result = Con.apply(obj, args) // 將構造函數中的this指向這個對象,並傳遞參數 return result instanceof Object ? result : obj } 複製代碼
相同點: 三個函數的做用就是改變this的指向,將函數綁定到上下文中; 不一樣點: 三個函數的語法不一樣
fun.call(thisArg[, arg1[, arg2[, ...]]]) fun.apply(thisArg, [argsArray]) var bindFn = fun.bind(thisArg[, arg1[, arg2[, ...]]]) bindFn() 複製代碼
擴展 :手寫三個函數的源碼
手寫apply源碼
Function.prototype.apply = function(content = window) { content.fn = this; let result; // 判斷是否有第二個參數 if(arguments[1]) { result = content.fn(...arguments[1]); } else { result = content.fn(); } delete content.fn; return result; } 複製代碼
手寫call源碼
/** * 完整版 步驟: * 將函數設爲對象屬性 * 執行&刪除這個函數 * 指定this到函數並傳入給定參數執行函數 * 若是不傳參數,默認指向window * */ Function.prototype.call = function(content = window) { // 判斷是不是underfine和null // if(typeof content === 'undefined' || typeof content === null){ // content = window // } content.fn = this; let args = [...arguments].slice(1); let result = content.fn(...args); delete content.fn; return result; } 複製代碼
手寫bind源碼
/** * bind() 方法 * 會建立一個新函數。當這個新函數被調用時,bind() 的第一個參數將做爲它運行時的 this,以後的一序列參數將會在傳遞的實參前傳入做爲它的參數。(來自於 MDN ) */ Function.prototype.bind = function(content) { if(typeof this != 'function') { throw Error('not a function'); } let _this = this; let args = [...arguments].slice(1); return function F() { // 判斷是否被當作構造函數使用 if(this instanceof F) { return _this.apply(this, args.concat([...arguments])) } return _this.apply(content, args.concat([...arguments])) } } 複製代碼
// 第一種:字面量 var o1 = {name: "o1"} var o2 = new Object({name: "o2"}) // 第二種:經過構造函數 var M = function(name){this.name = name} var o3 = new M("o3") // 第三種:Object.create() var p = {name: "p"} var o4 = Object.create(p) 複製代碼
想詳細瞭解的,請查看MVVM詳解
1、什麼是vdom?
Virtual DOM 用JS模擬DOM結構
複製代碼
2、爲什麼要用vdom?
1. DOM操做很是很是「rang貴」,將DOM對比操做放在JS層,提升效率
2. DOM結構的對比,放在JS層來作(圖靈完備語言:能實現邏輯代碼的語言)
複製代碼
3、vdom核心函數有哪些
核心函數: h('標籤名', {...屬性名...}, [...子元素...]) h('標籤名', {...屬性名...}, '.........') patch(container, vnode) patch(vnode, newVnode) 複製代碼
Vue項目中實現路由按需加載(路由懶加載)的3中方式:
1. vue異步組件
2. es6提案的import()
3. webpack的require.ensure()
複製代碼
1、Vue異步組件技術: { path: '/home', name: 'Home', component: resolve => reqire(['path路徑'], resolve) } 2、es6提案的import() const Home = () => import('path路徑') 3、webpack提供的require.ensure() { path: '/home', name: 'Home', component: r => require.ensure([],() => r(require('path路徑')), 'demo') } 複製代碼
想詳細瞭解的小夥伴,請查看個人 從零開發一套完整的vue項目開發環境
Proxy的優勢:
1. 能夠直接監聽對象而非屬性,並返回一個新對象
2. 能夠直接監聽數值的變化
3. 能夠劫持整個對象,並返回一個新對象
複製代碼
Proxy的缺點:
Proxy是es6提供的新特性,兼容性很差,因此致使Vue3一致沒有正式發佈讓讓廣大開發者使用
複製代碼
Object.defineProperty的優勢:
E9如下的版本不兼容
複製代碼
Object.defineProperty的缺點:
1. 只能劫持對象的屬性,咱們須要對每一個對象的每一個屬性進行遍歷,沒法監控到數組下標的變化,致使直接經過數組的下標給數組設置值,不能實時響應
複製代碼
想詳細瞭解的小夥伴,請查看個人 從零實現一套屬於本身的UI框架-發佈到npm
props 和 $emit
父組件向子組件傳遞數量經過props傳遞
子組件向父組件傳遞經過$emit派發事件
parent
中央數據總線EventBus
ref 和 refs
Provide 和 inject
listeners
Vuex
生命週期:Vue實例從開始建立、初始化數據、編譯模板、掛載DOM-》渲染、更新-》渲染、卸載等一系列過程,稱爲Vue的生命週期
vue.js的生命週期一共有10個: beforeCreate:實例初始化以後,this指向建立實例,不能訪問到data、computed、watch、method上訂單方法和數據 created:實例建立完成,可訪問data、computed、watch、method上的方法和數據,未掛載到DOM,不能訪問到$el屬性,$ref屬性內容爲空數組 beforeMount:在掛載開始以前被調用,beforeMount以前,會找到對應的template,並編譯成render函數 mounted:實例掛載到DOM上,此時能夠經過DOMAPi獲取到DOM節點,$ref屬性能夠訪問 beforeUpdate:響應式數據更新時調用,發生在虛擬DOM打補丁以前 updated:虛擬DOM從新渲染和打補丁以後調用,組件DOM已經更新,可執行依賴於DOM的操做 activated:keep-alive開啓時調用 deactivated:keep-alive關閉時調用 beforeDestroy:實例銷燬以前調用。實例仍然徹底可用,this仍能獲取到實例 destroy:實例銷燬後調用,調用後,Vue實例指示的全部東西都會解綁定,全部的事件監聽器會被移除,全部的子實例也會被銷燬 複製代碼
問題:渲染真實的DOM開銷是很大的,修改了某個數據,若是直接渲染到真實dom上會引發整個DOM樹的重繪和重排。
Virtual Dom 根據真實DOM生成的一個Virtual DOM,當Virtual DOM某個節點的數據改變後生成一個新的Vnode,而後Vnode和oldVnode做對比,發現有不同的地方就直接修改在真實的DOM上,而後使oldVnode的值爲Vnode.
注意:在採起diff算法比較的時候,只會在同層級進行,不會跨層級比較。
當數據發生改變時,set方法會讓調用Dep.notify()方法通知全部訂閱者Watcher,訂閱者就會調用patch函數給真實的DOM打補丁,更新響應的試圖。
想詳細瞭解的小夥伴,請查看個人 從零實現一套屬於本身的UI框架-發佈到npm
1、導航守衛大致分爲三類:
1. 全局守衛鉤子
2. 獨享守衛鉤子
3. 路由組件守衛鉤子
複製代碼
2、全局守衛鉤子(在路由切換全局執行)
全局守衛鉤子函數有三種:
const router = new VueRouter({....}) // 全局前置守衛 router.beforeEach((to, from, next) => { // do something }) // 全局解析守衛 router.beforeResolve((to, from, next) => { // do something }) // 全局後置守衛 router.afterEach((to, from) => { // do something }) 注意: to:route即將進入的路由 from:route即將離開的路由 next:function這個是必需要調用的 next()接受參數: next():直接執行下一個鉤子,若是執行完了導航狀態爲comfirmed狀態 next(false):中斷當前導航,回到from的位置 next('/hello')或next({path:'/hello'}):路由到任意地址,能夠攜帶參數等 next(error):會回到router.onError(callback) 複製代碼
3、獨享守衛鉤子
獨享守衛是定義在單獨的某一個路由裏的
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // do something }, beforeLeave: (to, from, next) => { // do something } } ] }) 複製代碼
4、路由組件守衛鉤子
路由組件便是在vue-router中註冊的組件叫路由組件
beforeRouteEnter(to, from, next) {}
beforeRouteUpdate(to, from, next) {}
beforeRouteLeave(to,from, next){}
複製代碼
Vuex 是一個專爲 Vue 應用程序開發的狀態管理模式。每個 Vuex 應用的核心就是 store(倉庫)。
1. Vuex 的狀態存儲是響應式的;當 Vue 組件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麼相應的組件也會相應地獲得高效更新
2. 改變 store 中的狀態的惟一途徑就是顯式地提交 (commit) mutation,這樣使得咱們能夠方便地跟蹤每個狀態的變化
複製代碼
Vuex主要包括如下幾個核心模塊:
1. State:定義了應用的狀態數據
2. Getter:在 store 中定義「getter」(能夠認爲是 store 的計算屬性),就像計算屬性同樣,getter 的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變纔會被從新計算
3. Mutation:是惟一更改 store 中狀態的方法,且必須是同步函數
4. Action:用於提交 mutation,而不是直接變動狀態,能夠包含任意異步操做
5. Module:容許將單一的 Store 拆分爲多個 store 且同時保存在單一的狀態樹中
複製代碼
vue.js是採用數據劫持結合發佈者-訂閱者模式的方式,經過Object.defineProperty()來劫持各個屬性的setter和getter,在數據變更時發佈消息給訂閱者,觸發相應的監聽回調
Vue是一個典型的MVVM框架,模型(Model)只是普通的javascript對象,修改它則試圖(View)會自動更新。這種設計讓狀態管理變得很是簡單而直觀
複製代碼
Vue實現這種數據雙向綁定的效果,須要三大模塊:
1. Observer:可以對數據對象的全部屬性進行監聽,若有變更可拿到最新值並通知訂閱者.
2. Compile:對每一個元素節點的指令進行掃描和解析,根據指令模板替換數據,以及綁定相應的更新函數。
3. Watcher:連接Observer和Compile的橋樑,可以訂閱並收到每一個屬性變更的通知,執行指令綁定的相應的回調函數,從而更新試圖。
複製代碼
Observer(數據監聽器)
Observer的核心是經過Object.defineProprtty()來監聽數據的變更,這個函數內部能夠定義setter和getter,每當數據發生變化,就會觸發setter。這時候Observer就要通知訂閱者,訂閱者就是Watcher
Watcher(訂閱者)
Watcher訂閱者做爲Observer和Compile之間通訊的橋樑,主要作的事情是:
1.在自身實例化時往屬性訂閱器(dep)裏面添加本身
2.自身必須有一個update()方法
3.待屬性變更dep.notice()通知時,能調用自身的update()方法,並觸發Compile中綁定的回調
Compile(指令解析器)
Compile主要作的事情是解析模板指令,將模板中變量替換成數據,而後初始化渲染頁面視圖,並將每一個指令對應的節點綁定更新函數,添加鑑定數據的訂閱者,一旦數據有變更,收到通知,更新試圖
複製代碼
若小夥伴想詳細瞭解Vue的MVVM源碼實現,請查看 MVVM原理
若小夥伴想詳細瞭解React生命週期,請查看 React生命週期
使用Redux應該遵循原則:
整個應用共享的state應該存儲在store的狀態數中,store是惟一的
state不能直接修改,只能經過action表達修改的意圖,調用dispatch()修改state
state的修改規則reducers必須是一個純函數,不能有反作用
Redux提供的API 一、createStore createStore方法的做用就是建立一個Redux store來存放應用中全部的state createStore(reducer, [preloadState], [enhancer]) createStore方法接受三個參數,後面兩個是可選參數 reducer: 參數的類型必須是function preloadState: 這個參數表明初始化的state(initialState), 能夠是任意類型的參數 enhancer: 這個參數表明添加的各類中間件,參數的類型必須是function createStore提供的方法: 一、getState() 返回當前的state 二、dispach(action) 參數action必須是一個對象,且必須含有type字段 三、subscribe(listener) 事件監聽 二、combineReducers combineReducers主要是把多個reducer合併成一個,而且返回一個新的reducer函數,該函數接收的參數也是兩個state和action 三、compose 主要是在中間件時候使用,合成函數 compose(applyMiddleware(thunk), window.devToolsExtension ? window.devToolsExtension() : undefined ) 四、applyMiddleware 五、bindActionCreator bindActionCreator的主要做用就是將aciton與dispatch函數綁定,生成直接能夠出發action的函數 複製代碼
1、HTTP/0.9
只有一個命令GET
沒有HEADER等描述數據的信息
服務器發送完畢,就關閉TCP鏈接
2、HTTP/1.0
增長了不少命令
增長status code和header
多字符集支持、多部分發送、權限、緩存等
3、HTTP/1.1
持久鏈接
pipeline
增長host和其餘命令
4、HTTP2
全部數據以二進制傳輸(之前是以字符串)
同一個鏈接裏面發送多個請求再也不須要按照順序來
頭信息壓縮以及推送等提升效率的功能
HTTP1.0定義了三種請求方法:GET(查)、POST(增)、HEAD
HTTP1.1新增了五種請求方法:OPTIONS、PUT(改)、DELETE(刪)、TRACE、CONNECT
複製代碼
HTTP協議定義Web客戶端如何從Web服務器請求Web頁面,以及服務器如何把Web頁面傳送給客戶端。
客戶端向服務器發送一個請求報文,請求報文:【請求方法、URL、協議版本、請求頭部和請求數據】
服務器以一個狀態行做爲響應,響應的內容:【協議的版本、成功或失敗代碼、服務器信息、響應頭部和響應數據】
複製代碼
客戶端鏈接到Web服務器
發送HTTP請求
服務器接受請求並返回HTTP響應
釋放鏈接TCP鏈接
客戶端(瀏覽器)解析HTML內容
簡單快速
靈活
無鏈接
無狀態
支持B/S、C/S模式
請求報文{ 請求行、請求頭、空行、請求體 } 請求行:{http方法、頁面地址、http協議、http版本} 響應報文{ 狀態行、響應頭、空行、響應體 }
GET---獲取資源
POST---傳輸資源
PUT---更新資源
DELETE---刪除資源
HEAD---獲取報文首部
複製代碼
GET在瀏覽器回退時時無害的,而POST會再次提交請求
GET請求會被瀏覽器主動緩存,而POST不會,除非手動設置
GET請求參數會被完整的保留在瀏覽器歷史記錄裏,而POST中的參數不會被保留
GET請求在URL中傳送的參數是有長度的限制,而POST沒有限制
GET請求參數會暴露,不安全
GET參數經過URL傳遞,POST放在Requset Body中
複製代碼
1xx:指示信息類,表示請求已接受,繼續處理
2xx:指示成功類,表示請求已成功接受
3xx:指示重定向,表示要完成請求必須進行更近一步的操做
4xx:指示客戶端錯誤,請求有語法錯誤或請求沒法實現
複製代碼
5xx:指示服務器錯誤,服務器未能實現合法的請求
200 OK:客戶端請求成功
206 Partial Content:客戶發送了一個帶有Range頭的GET請求,服務器完成了它(當時音頻或視頻文件很大時返回206)
301 Moved Permanently:所請求的頁面已經轉移至新的URL
302 Found:所請求的頁面已經臨時轉移至新的URL
303 Not Modified:客戶端有緩衝的文檔併發出看一個條件性的請求,服務器告訴客戶,原來緩衝的文檔還能夠繼續使用
403 Forbidden:對請求頁面的訪問被禁止
404 Not Found:請求資源不存在
500 Internal Server Error:服務器發生不可預期的錯誤原來緩衝的文檔還能夠繼續使用
503 Server Unavailable:請求未完成,服務器臨時過載或宕機,一段時間後可恢復正常
複製代碼
HTTP協議採用」請求-應答「模式,當使用普通模式,既非Keep-Alive模式時,每一個請求/應答客戶和服務器都要新建一個鏈接,完成以後當即斷開鏈接(HTTP協議爲無鏈接的協議)
當使用Keep-Alive模式(又稱持久鏈接、鏈接重用)時,Keep-Alive功能使客戶端到服務器端的連接持續有效,當出現對服務器的後續請求時,Keep-Alive功能避免了創建或者從新創建鏈接
注意:keep-alive是1.1版本纔有
複製代碼
管線化技術:客戶端能夠發送屢次請求到服務器,而不須要等待上一次請求獲得響應的時候才能進行下一次請求。實現並行發送請求 管線化機制經過持久鏈接完成,僅HTTP/1.1支持此技術 只有GET和HEAD請求能夠進行管線化,而POST則有所限制
從輸入URL到頁面加載的主幹流程以下:
1. 首先,在瀏覽器地址中輸入url
2. 瀏覽器先查看**瀏覽器緩存**-系統緩存-路由器緩存,若是緩存中有,會直接在屏幕中顯示頁面內容。若沒有,則跳到第三步操做
3. 瀏覽器向DNS(Domain Name System)服務器請求解析該URL中的域名對應的IP地址
4. 解析出IP地址後,根據該IP地址和默認端口80,和服務器創建TCP鏈接
5. 瀏覽器發出讀取文件(URL中域名後面部分對應的文件)的HTTP請求,該請求報文做爲TCP三次握手的第三個報文的數據發送給服務器
6. 服務器對瀏覽器請求作出響應,並把對應的html文本發送給瀏覽器
7. 釋放TCP鏈接
8. 瀏覽器將該html文本並顯示內容
複製代碼
其中,步驟2的具體過程是:
1. **瀏覽器緩存**:瀏覽器會記錄DNS一段時間,所以,只是第一個地方解析DNS請求;
2. **操做系統緩存:**若是在瀏覽器緩存中不包含這個記錄,則會使系統調用操做系統,獲取操做系統的記錄(保存最近的DNS查詢緩存);
3. **路由器緩存**:若是上述兩個步驟均不能成功獲取DNS記錄,繼續搜索路由器緩存;
4. **ISP緩存:**若上述均失敗,繼續向ISP搜索。
複製代碼
DOM結構中的各個元素都有本身的盒子(模型),這些都須要瀏覽器根據格式的樣式來計算並根據計算結果將元素放到它該出現的位置,這個過程稱爲reflow
當各個盒子的位置、大小以及其餘屬性,如顏色、字體大小等都肯定下來後,瀏覽器因而便把這些元素都按照各自的特性繪製了一遍,因而頁面的內容出現了,這個過程稱之爲repaint
// 觸發Reflow
當你增長、刪除、修改DOM節點時,會致使Reflow或Repaint
當你移動DOM的位置,或是搞個動畫的時候
當你修改CSS樣式的時候
當你Resize窗口的時候(移動端沒有這個問題),或是滾動的時候
當你修改網頁的默認字體時
// 觸發Repaint
DOM改動
CSS改動
// 如何防止重排Reflow和重繪Repaint?
複製代碼
1. -webkit-:webkit核心瀏覽器,Chrome
2. -moz-:Gecko核心瀏覽器,fixfox
3. -o-:Opera核心瀏覽器,Opera
4. -ms-:微軟的IE瀏覽器
複製代碼
1. JSONP(只支持GET請求)
2. window + hash
3. window + domain
4. window + name
5. postMessage
6. WebSocket
7. CORS(Cross-origin resource sharing) 跨域資源共享(全部的HTTP請求)
8. nginx反向代理
複製代碼
資源壓縮合並、減小HTTP請求
非核心代碼異步加載---------》異步加載的方式---------》異步加載的區別
利用瀏覽器緩存---------》緩存的分類-----------》緩存的原理【重點】
利用CDN
預解析DNS
<meta http-equiv="x-dns-prefetch-control" content="no"> <link rel="dns-prefetch" href="//host_name_to_prefetch.com"> 複製代碼
1. 即時運行錯誤:代碼錯誤;捕獲方式:try...catch...、window.onerror
2. 資源加載錯誤;object.onerror(不會冒泡 )、performance.getEntries、Error事件捕獲
複製代碼
1. CSRF:(稱爲跨站請求僞造)(Cross-site request forgery)縮寫CSRF
2. CSRF預防措施:Token驗證、Refer驗證(頁面來源)、隱藏令牌
3. XSS縮寫(cross-site scripting)跨域腳本攻擊
複製代碼
同源策略限制從一個源加載的文檔或腳本如何與來自另外一個源的資源進行交互。這是一個用於隔離潛在惡意文件的關鍵的安全機制
源======協議+域名+端口(默認爲80)源不同就是跨域了
不一樣源之間不能執行如下狀況,如下狀況都是同源時執行:
1. Cookie、LocalStorage和indexDB沒法讀取
2. DOM沒法得到
3. AJAX請求不能發送
複製代碼
1. 不一樣瀏覽器的標籤默認的margin和padding不同。*{margin:0;padding:0;}
2. IE6雙邊距bug:塊屬性標籤float後,又有橫行的margin狀況下,在IE6顯示margin比設置的大。hack:display:inline;將其轉化爲行內屬性。
3. 設置較小高度標籤(通常小於10px),在IE6,IE7中高度超出本身設置高度。hack:給超出高度的標籤設置overflow:hidden;或者設置行高line-height 小於你設置的高度。
4. Chrome 中文界面下默認會將小於 12px 的文本強制按照 12px 顯示,可經過加入 CSS 屬性 -webkit-text-size-adjust: none; 解決。
5. 超連接訪問事後hover樣式就不出現了,被點擊訪問過的超連接樣式再也不具備hover和active了。解決方法是改變CSS屬性的排列順序:L-V-H-A ( love hate ): a:link {} a:visited {} a:hover {} a:active {}
複製代碼
很是喜歡的一段話:在咱們20歲的時候用30歲的心態來作事,那麼當咱們30歲的時候就能夠享受別人40歲的成功!~💪💪💪
若是本文對你有幫助得話,給本文點個贊❤️❤️❤️
歡迎你們加入,一塊兒學習前端,共同進步!