文章大部份內容是作一些知識點的總結,不會面面俱到,對於一些具體的實現步驟和底層原理的代碼並不會貼出來,否則篇幅實在是太長啦css
不過沒必要擔憂,相關知識點的詳細講解會貼出文章連接供你們參考,這些都是博主日常寫的筆記和看過的一些優秀的博文,但願可以幫助你查漏補缺,梳理起你的前端知識體系~html
文章內容較多,建議先 mark 再看喲。前端
<meta charset="UTF-8" >
複製代碼
<meta http-equiv="expires" content="Wed, 20 Jun 2019 22:33:00 GMT">
複製代碼
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
複製代碼
標準模型:寬高計算不包含 padding 和 border ;經過 box-sizing: content-box; 來設置(瀏覽器默認)。vue
IE模型:寬高計算包含 padding 和 border ;經過 box-sizing: border-box; 來設置。html5
特色:node
建立方式:react
做用:webpack
div.parent {
position: relative;
}
div.child {
width: 100px;
height: 100px;
position: absolute;
top: 50%;
left: 50%;
margin-left: -50px;
margin-top: -50px;
}
或
div.child {
width: 100px;
height: 100px;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
}
複製代碼
div.parent {
display: flex;
justify-content: center;
align-items: center;
}
或
div.parent{
display:flex;
}
div.child{
margin:auto;
}
或
div.parent {
position: relative;
}
div.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
或
div.parent {
display: grid;
}
div.child {
justify-self: center;
align-self: center;
}
複製代碼
更多佈局類型可參考:乾貨!各類常見佈局實現+知名網站實例分析git
更多內容可參考:7 種方法解決移動端 Retina 屏幕 1px 邊框問題es6
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
複製代碼
overflow: hidden;
text-overflow: ellipsis; // 超出顯示'...'
display: -webkit-box; // 將元素做爲彈性伸縮盒子模型顯示 。
-webkit-line-clamp: 2; // 用來限制在一個塊元素顯示的文本的行數
-webkit-box-orient: vertical; // 設置或檢索伸縮盒對象的子元素的排列方式
複製代碼
一、
.clearfix:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
二、clear:both
三、overflow:hidden
複製代碼
.sector {
width: 0;
height: 0;
border-width: 50px;
border-style: solid;
border-color: red transparent transparent;
border-radius: 50px;
}
複製代碼
tips: NaN 也屬於 number 類型,而且 NaN 不等於自身。
console.log(typeof 1); // number
console.log(typeof 'a'); // string
console.log(typeof true); // boolean
console.log(typeof undefined); // undefined
console.log(typeof function fn(){}); // function
console.log(typeof {}); // object
console.log(typeof null); // object
console.log(typeof []); // object
console.log(typeof new Error()); // object
複製代碼
tips:typeof 對於基本類型,除了 null 均可以顯示正確的類型;對於對象,除了函數都會顯示 object
var number = 1; // [object Number]
var string = '123'; // [object String]
var boolean = true; // [object Boolean]
var und = undefined; // [object Undefined]
var nul = null; // [object Null]
var obj = {a: 1} // [object Object]
var array = [1, 2, 3]; // [object Array]
var date = new Date(); // [object Date]
var error = new Error(); // [object Error]
var reg = /a/g; // [object RegExp]
var func = function a(){}; // [object Function]
function checkType() {
for (var i = 0; i < arguments.length; i++) {
console.log(Object.prototype.toString.call(arguments[i]))
}
}
checkType(number, string, boolean, und, nul, obj, array, date, error, reg, func)
複製代碼
更多內容可參考:JavaScript溫故而知新——類型判斷
更多內容可參考:JavaScript溫故而知新——原型和原型鏈
更多內容可參考:JavaScript溫故而知新——執行環境和做用域
經典面試題:改造下面的代碼,使之輸出0 - 9
for (var i = 0; i< 10; i++){
setTimeout(() => {
console.log(i);
}, 1000)
}
方法1、利用 setTimeout 函數的第三個參數,會做爲回調函數的第一個參數傳入
for (var i = 0; i < 10; i++) {
setTimeout(i => {
console.log(i);
}, 1000, i)
}
方法2、使用 let 變量 的特性
for (let i = 0; i < 10; i++) {
setTimeout(() => {
console.log(i);
}, 1000)
}
等價於
for (let i = 0; i < 10; i++) {
let _i = i;// const _i = i;
setTimeout(() => {
console.log(_i);
}, 1000)
}
方法3、利用函數自執行的方式,把當前 for 循環過程當中的 i 傳遞進去,構建出塊級做用域。
for (var i = 0; i < 10; i++) {
(i => {
setTimeout(() => {
console.log(i);
}, 1000)
})(i)
}
複製代碼
this 的指向取決於函數以哪一種方式調用:
具體可參考:JavaScript溫故而知新——函數的4種調用方式
function a() {
return () => {
return () => {
console.log(this)
}
}
}
console.log(a()()())
複製代碼
箭頭函數實際上是沒有 this 的,這個函數中的 this 只取決於他外面的第一個不是箭頭函數的函數的 this。在這個例子中,由於調用 a 符合前面代碼中的第一個狀況,因此 this 是 window。而且 this 一旦綁定了上下文,就不會被任何代碼改變。
Function.prototype.call2 = function(context) {
var context = context || window;
context.fn = this;
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
var result = eval('context.fn(' + args + ')');
delete context.fn
return result;
}
Function.prototype.apply = function (context, arr) {
var context = Object(context) || window;
context.fn = this;
var result;
if (!arr) {
result = context.fn();
}
else {
var args = [];
for (var i = 0, len = arr.length; i < len; i++) {
args.push('arr[' + i + ']');
}
result = eval('context.fn(' + args + ')')
}
delete context.fn
return result;
}
複製代碼
實現細節可參考:JavaScript溫故而知新——call()和apply()的實現
Function.prototype.bind2 = function (context) {
if (typeof this !== "function") {
throw new TypeError("error");
}
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
// 經過一個空函數做一箇中轉,避免綁定函數的 prototype 的屬性被修改
var fNOP = function () {};
var fBound = function () {
var bindArgs = Array.prototype.slice.call(arguments);
return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
}
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
}
複製代碼
實現細節可參考:JavaScript溫故而知新——bind()方法的實現
new 操做符作了什麼?
function objectFactory() {
var obj = new Object(),
Constructor = [].shift.call(arguments);
obj.__proto__ = Constructor.prototype;
var ret = Constructor.apply(obj, arguments);
return typeof ret === 'object' ? ret : obj;
};
複製代碼
實現細節可參考:JavaScript溫故而知新——new操做符的實現
function instance_of(L, R) {
//L 表示左表達式,R 表示右表達式
var O = R.prototype; // 取 R 的顯示原型
L = L.__proto__; // 取 L 的隱式原型
while (true) {
if (L === null) return false;
if (O === L)
// 這裏重點:當 O 嚴格等於 L 時,返回 true
return true;
L = L.__proto__;
}
}
複製代碼
// 數組淺拷貝:slice()、concat()
// 對象淺拷貝:Object.assign()、ES6的擴展運算符
複製代碼
// 遞歸實現
function clone(source) {
var target = {};
for(var i in source) {
if (source.hasOwnProperty(i)) {
if (typeof source[i] === 'object') {
target[i] = clone(source[i]); // 若是是引用類型,則繼續遍歷
} else {
target[i] = source[i];
}
}
}
return target;
}
複製代碼
固然這只是簡單的實現,沒有考慮到特殊的狀況,如對象或數組中的函數,正則等特殊類型的拷貝等。
// JSON.parse(JSON.stringify)
var arr = [
{ value: 1 },
{ value: 2 },
{ value: 3 }
];
var copyArr = JSON.parse(JSON.stringify(arr))
copyArr[0].value = 0;
console.log(arr); // [{value: 1}, { value: 2 }, { value: 3 }]
console.log(copyArr); // [{value: 0}, { value: 2 }, { value: 3 }]
複製代碼
上面這種方法簡單粗暴,缺點是不能拷貝函數。
瞭解深拷貝更多實現細節,能夠參考:深拷貝的終極探索(90%的人都不知道)
funtion debounce(fn) {
// 建立一個標記用來存放定時器的返回值
let timeout = null;
return function() {
// 每次觸發事件時都取消以前的延時調用方法
clearTimeout(timeout);
// 而後又建立一個新的 setTimeout, 這樣就能保證 1000ms 間隔內若是重複觸發就不會執行 fn 函數
timeout = setTimeout(() => {
fn.apply(this, arguments);
}, 1000);
};
}
複製代碼
function throttle(fn) {
// 經過閉包保存一個標記
let canRun = true;
return function(){
// 每次開始執行函數時都先判斷標記是否爲 true,不爲 true 則 return
if (!canRun) return;
// 上一次定時器執行完後 canRun 爲 true,因此要先設置爲false
canRun = false;
setTimeout(() => {
fn.apply(this, arguments);
// 最後在 setTimeout 執行完畢後再把標記設置爲true(關鍵)表示能夠執行下一次循環了。當定時器沒有執行的時候標記永遠是 false,在開頭被 return 掉
canRun = true;
}, 1000)
}
}
複製代碼
// 組合繼承
function SuperType(name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
SuperType.prototype.sayName = function() {
console.log(this.name);
}
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function() {
console.log(this.age);
}
複製代碼
ajax('XXX1', () => {
// callback 函數體
ajax('XXX2', () => {
// callback 函數體
ajax('XXX3', () => {
// callback 函數體
})
})
})
複製代碼
優勢:解決了同步的問題
缺點:回調地獄,不能用 try catch 捕獲錯誤,不能 return
ajax('XXX1')
.then(res => {
// 操做邏輯
return ajax('XXX2')
}).then(res => {
// 操做邏輯
return ajax('XXX3')
}).then(res => {
// 操做邏輯
})
複製代碼
優勢:解決了回調地獄的問題
缺點:沒法取消 Promise ,錯誤須要經過回調函數來捕獲
function *fetch() {
yield ajax('XXX1', () => {})
yield ajax('XXX2', () => {})
yield ajax('XXX3', () => {})
}
let it = fetch()
let result1 = it.next()
let result2 = it.next()
let result3 = it.next()
// 配合 co 庫使用
const co = require('co')
function *fetch() {
yield ajax('XXX1', () => {})
yield ajax('XXX2', () => {})
yield ajax('XXX3', () => {})
}
co(fetch()).then(data => {
//code
}).fetch(err => {
//code
})
複製代碼
優勢:能夠控制函數的執行,配合自動執行器 co 模塊 簡化了手動執行的步驟
缺點:不配合 co 函數庫的話使用起來比較麻煩
// async實際上是一個語法糖,它的實現就是將 Generator 函數和自動執行器(co),包裝在一個函數中
async function test() {
// 如下代碼沒有依賴性的話,徹底可使用 Promise.all 的方式
// 若是有依賴性的話,其實就是解決回調地獄的例子了
await fetch('XXX1')
await fetch('XXX2')
await fetch('XXX3')
}
read().then((data) => {
//code
}).catch(err => {
//code
});
複製代碼
優勢:代碼清晰,不用像 Promise 寫一大堆 then 鏈,處理了回調地獄的問題
缺點:await 將異步代碼改形成同步代碼,若是多個異步操做沒有依賴性而使用 await 會致使性能上的下降。
對於這個問題首先要弄明白 JS 的事件循環(Event Loop)機制,推薦你們先看一下這篇文章:這一次,完全弄懂 JavaScript 執行機制
console.log('script start') //1. 打印 script start
setTimeout(function() {
console.log('settimeout') // 4. 打印 settimeout
}) // 2. 調用 setTimeout 函數,並定義其完成後執行的回調函數
console.log('script end') //3. 打印 script start
// 輸出順序:script start->script end->settimeout
複製代碼
console.log('script start')
let promise1 = new Promise(function (resolve) {
console.log('promise1')
resolve()
console.log('promise1 end')
}).then(function () {
console.log('promise2')
})
setTimeout(function() {
console.log('settimeout')
})
console.log('script end')
// 輸出順序: script start->promise1->promise1 end->script end->promise2->settimeout
複製代碼
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end')
}
async function async2() {
console.log('async2')
}
console.log('script start');
async1();
console.log('script end')
// 輸出順序:script start->async1 start->async2->script end->async1 end
複製代碼
promise 的使用(有關 Promise 的詳細用法,可參考 阮一峯老師的ES6文檔)
var promise = new Promise((resolve,reject) => {
if (操做成功) {
resolve(value)
} else {
reject(error)
}
})
promise.then(function (value) {
// success
},function (value) {
// failure
})
複製代碼
簡單實現
function myPromise(constructor) {
let self = this;
self.status = "pending" // 定義狀態改變前的初始狀態
self.value = undefined; // 定義狀態爲resolved的時候的狀態
self.reason = undefined; // 定義狀態爲rejected的時候的狀態
function resolve(value) {
if(self.status === "pending") {
self.value = value;
self.status = "resolved";
}
}
function reject(reason) {
if(self.status === "pending") {
self.reason = reason;
self.status = "rejected";
}
}
// 捕獲構造異常
try {
constructor(resolve,reject);
} catch(e) {
reject(e);
}
}
複製代碼
添加 then 方法
myPromise.prototype.then = function(onFullfilled,onRejected) {
let self = this;
switch(self.status) {
case "resolved":
onFullfilled(self.value);
break;
case "rejected":
onRejected(self.reason);
break;
default:
}
}
var p = new myPromise(function(resolve,reject) {
resolve(1)
});
p.then(function(x) {
console.log(x) // 1
})
複製代碼
有關 Promise 原理的更多細節推薦 Promise實現原理(附源碼),這篇文章講的很仔細,比較好理解。
(function(){
return {
data:[]
}
})()
複製代碼
define('./index.js',function(code){
// code 就是index.js 返回的內容
})
複製代碼
define(function(require, exports, module) {
var indexCode = require('./index.js');
});
複製代碼
var fs = require('fs');
複製代碼
import a from 'a';
複製代碼
1xx:指示信息 —— 表示請求已接受,繼續處理
2xx: 成功 —— 表示請求已被成功接受
3xx:重定向 —— 要完成請求必須進行更進一步操做
4xx:客戶端錯誤——請求有語法錯誤或請求沒法實現
5xx:服務端錯誤——服務器未能實現合法的請求
三次握手和四次揮手能夠模擬成對講機通話的過程
A: 你好,我是A
B:收到,我是B
A:好的,咱們能夠開始通話啦
複製代碼
A:我已經沒什麼話說了,結束通話吧
B:稍等,我還有最後一句話要說
B:我已經說完啦
A:好的,你能夠關掉對講機了,不用回覆了(而後A等待2MSL無回覆,也關掉對講機)
複製代碼
更詳細的內容可參考:面試 -- 網絡 TCP/IP
HTTPS 仍是經過了 HTTP 來傳輸信息,可是信息經過 TLS 協議進行了加密。
TLS 中的加密:
HTTPS 握手過程:
捕獲階段 —— window 往事件觸發處傳播,遇到註冊的捕獲事件會觸發
目標階段 —— 傳播到事件觸發處時觸發註冊的事件
冒泡階段 —— 從事件觸發處往 window 傳播,遇到註冊的冒泡事件會觸發
複製代碼
window對象 => document對象 => html標籤 => body標籤 => ... => 目標元素(冒泡反之)
複製代碼
event.preventDefault() // 阻止默認事件,例如a標籤的跳轉行爲
event.stopPropagation() // 阻止冒泡
event.stopImmediatePropagation() // 事件響應優先級:例如同一元素綁定不一樣事件時,觸發a事件不讓b事件觸發
event.currentTarget // 當前綁定事件的元素
event.target // 當前被點擊的元素
複製代碼
同源策略:
跨域的幾種解決方法:
<script>
標籤沒有跨域限制的特色,經過 <script>
標籤指向一個須要訪問的地址並提供一個回調函數來接收數據。<script src="http://domain/api?param1=a¶m2=b&callback=jsonp"></script>
<script>
function jsonp(data) {
console.log(data)
}
</script>
複製代碼
封裝一個 jsonp 方法
function jsonp({url, params, cb}) {
return new Promise((resolve, reject) => {
//建立script標籤
let script = document.createElement('script');
//將回調函數掛在 window 上
window[cb] = function(data) {
resolve(data);
//代碼執行後,刪除插入的script標籤
document.body.removeChild(script);
}
//回調函數加在請求地址上
params = {...params, cb}
let arrs = [];
for(let key in params) {
arrs.push(`${key}=${params[key]}`);
}
script.src = `${url}?${arrs.join('&')}`;
document.body.appendChild(script);
});
}
//使用
function sayHi(data) {
console.log(data);
}
jsonp({
url: 'http://localhost:3000/say',
params: {
//code
},
cb: 'sayHi'
}).then(data => {
console.log(data);
});
複製代碼
Access-Control-Allow-Origin
就能夠開啓 CORS。 該屬性表示哪些域名能夠訪問資源,若是設置通配符則表示全部網站均可以訪問資源。a.test.com
和b.test.com
,只須要給頁面添加 document.domain = 'test.com'
表示二級域名都相同就能夠實現跨域。# 在A中發送數據
window.postMessage('data', 'http://B.com');
# 在窗口B中監聽
window.addEventListener('message', function(event){
console.log(event.origin);
console.log(event.source);
console.log(event.data);
}, false)
複製代碼
# 使用場景:當頁面A經過iframe或frame嵌入了跨域的頁面B
# 在A中的代碼:
var B = document.getElementByTagName('iframe');
B.src = B.src + '#' + 'data';
# 在B中的代碼:
window.onhashchange = function () {
var data = window.location.hash;
}
複製代碼
requestAnimationFrame
重繪和迴流更詳細的內容可參考:你真的瞭解迴流和重繪嗎
緩存的原理 —— 將請求來的資源存放到本地磁盤當中,下次獲取資源則直接在磁盤當中讀取而再也不去向服務器發送請求。
緩存的分類:
Expires
和 Cache-Control
。強緩存表示在緩存期間不須要請求,state code 爲 200Expires: Wed, 22 Oct 2018 08:41:00 GMT
// Expires 是 HTTP / 1.0 的產物,表示資源會在 Wed, 22 Oct 2018 08:41:00 GMT 後過時,須要再次請求。
// 而且 Expires 受限於本地時間,若是修改了本地時間,可能會形成緩存失效。
Cache-control: max-age=30
// Cache-Control 出現於 HTTP / 1.1,優先級高於 Expires 。該屬性表示資源會在 30 秒後過時,須要再次請求。
複製代碼
Last-Modified
和 If-Modified-Since
—— 表示本地文件最後修改日期,If-Modified-Since
會將 Last-Modified
的值發送給服務器,詢問服務器在該日期後資源是否有更新,有更新的話就會將新的資源發送回來。(可是若是在本地打開緩存文件,就會形成 Last-Modified
被修改,因此在 HTTP / 1.1 出現了 ETag
。)ETag
和 If-None-Match
—— ETag
相似於文件指紋,If-None-Match
會將當前 ETag
發送給服務器,詢問該資源 ETag
是否變更,有變更的話就將新的資源發送回來。而且 ETag
優先級比 Last-Modified
高瞭解更多有關瀏覽器緩存機制可參考:深刻理解瀏覽器的緩存機制。
XSS
CSRF
關於 Web 安全更多內容可參考:【面試篇】寒冬求職之你必需要懂的Web安全
<link rel="dns-prefetch" href="//host_name_to_prefetch.com" />
複製代碼
<link rel="preload" href="http://example.com" />
複製代碼
<link rel="prerender" href="http://example.com" />
複製代碼
圖片優化:
其餘文件優化:
head
中使用 Webpack 優化項目:
錯誤監控:
performance.getEntries()
能夠獲取已經加載完成的資源進而監控加載失敗的資源錯誤上報:
顧名思義,即 Model-View-ViewModel 模式
優勢:
缺點:
Vue 採用數據劫持結合發佈—訂閱模式的方法,經過 Object.defineProperty() 來劫持各個屬性的 setter,getter,在數據變更時發佈消息給訂閱者,觸發相應的監聽回調。
模擬實現可參考 面試題:你能寫一個Vue的雙向數據綁定嗎?,這裏就不貼代碼了。
在遍歷子節點的時候還有一個列表對比的算法,是針對帶有 key
而且新舊列表同時存在的節點作處理的。當子節點僅僅只是發生位置改變的狀況,若是按照同層對比,它們就會被替換掉,形成較大的 DOM 開銷,而列表對比算法會經過對比新舊節點列表的順序來移動節點進行 DOM 的更新,在一些場合下就能夠起到必定的性能優化的做用。
對於 Virtual Dom 詳細的代碼實現可參考:深度剖析:如何實現一個 Virtual DOM 算法
本質:監聽 URL 的變化,而後匹配路由規則,而且無需刷新頁面。
實現方式:
詳細內容可參考:面試官: 你瞭解前端路由嗎?
Proxy的優點:
Object.defineProperty的優點以下:
指建立初始化數據、編譯模板、掛載 DOM、渲染、更新、卸載一系列的過程。
props
、 $emit
或本組件值的變化來執行回調進行後續操做,無緩存性,頁面從新渲染時值不變化也會執行。推薦使用惟一標識做爲 key 的緣由:
nextTick
可讓咱們在下次 DOM 更新循環結束以後執行延遲迴調,用於得到更新後的 DOM。
props
/ $emit
$children
/ $parent
—— 父組件中用 this.$children
獲取到子組件實例數組,子組件中可使用 this.$parent
獲取父組件實例對象。
#app
上獲取 $parent
獲得的是 new Vue()
的實例,在這之上再獲取 $parent
則是 undefined
;而底層子組件獲取 $children
獲得的是空數組。provide
/ inject
—— vue2.2 新增的 api ,父組件經過 provide
屬性來提供變量,而後在子組件中用 inject
來注入變量。ref
/ $refs
—— ref
在普通 DOM 元素上使用,引用的就是 DOM 元素;若是在子組件上,引用的是組件實例$attrs
/ $listeners
—— vue2.4新增,能夠進行跨級的組件通訊eventBus
// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()
// A.vue
<template>
<div>
<button @click="sendFirstName"></button>
</div>
</template>
<script>
import {EventBus} from './event-bus.js'
export default {
data(){
return{
firstName:'leborn'
}
},
methods:{
sendFirstName(){
EventBus.$emit('getFirstName', {
firstName:this.firstName
})
}
}
}
</script>
// B.vue
<template>
<div>姓名: {{name}}</div>
</template>
<script>
import { EventBus } from './event-bus.js'
export default {
data() {
return {
name: ''
}
},
mounted() {
EventBus.$on('getFirstName', param => {
this.name = param.firstName + 'james';
})
}
}
</script>
複製代碼
代碼層面:
Webpack 層面優化:
基礎的Web技術優化:
詳細內容可參考:Vue 項目性能優化 — 實踐指南(網上最全 / 詳細)
class ExampleComponent extends React.Component {
// 用於初始化 state
constructor() {}
// 用於替換 `componentWillReceiveProps` ,該函數會在初始化和 `update` 時被調用
// 由於該函數是靜態函數,因此取不到 `this`
// 若是須要對比 `prevProps` 須要單獨在 `state` 中維護
static getDerivedStateFromProps(nextProps, prevState) {}
// 判斷是否須要更新組件,多用於組件性能優化
shouldComponentUpdate(nextProps, nextState) {}
// 組件掛載後調用
// 能夠在該函數中進行請求或者訂閱
componentDidMount() {}
// 用於得到最新的 DOM 數據
getSnapshotBeforeUpdate() {}
// 組件即將銷燬
// 能夠在此處移除訂閱,定時器等等
componentWillUnmount() {}
// 組件銷燬後調用
componentDidUnMount() {}
// 組件更新後調用
componentDidUpdate() {}
// 渲染組件函數
render() {}
// 如下函數不建議使用
UNSAFE_componentWillMount() {}
UNSAFE_componentWillUpdate(nextProps, nextState) {}
UNSAFE_componentWillReceiveProps(nextProps) {}
}
複製代碼
緣由:在 setState 函數實現中,會根據 isBatchingUpdates 這個變量來決定是否同步更新 this.state。isBatchingUpdates 默認是 false 表示 setState 會同步更新 this.state。但 React 在調用事件處理函數時會調用一個 batchedUpdates 函數,將 isBatchingUpdates 改成 true,此時 setState 不會同步更新 this.state
class Example extends React.Component {
constructor() {
super();
this.state = {
val: 0
};
}
componentDidMount() {
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 1 次 log
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 2 次 log
setTimeout(() => {
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 3 次 log
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 4 次 log
}, 0);
}
render() {
return null;
}
};
複製代碼
輸出:0 0 2 3
前端的知識點實在是太多太雜了,對於一些沒有涉及到的內容,例如 webpack,babel 什麼的後續可能會補上。本篇文章若是能幫助到你的話點贊就完事兒了,沒能幫到你也敬請見諒哈~
最後建議你們在看一些技術文章的時候能夠本身一邊作作總結,否則很容易過目即忘的,沒錯博主就是如此,而後文章若是有不嚴謹的地方,歡迎你們評論區指出。