前言:
在 React源碼解析之updateClassComponent(下) 中提到了PureComponent
的淺比較:javascript
//若是是純組件的話,用**淺比較**來比較 props/state
if (ctor.prototype && ctor.prototype.isPureReactComponent) {
return (
//淺等於的判斷
!shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
);
}
複製代碼
接下來就看下shallowEqual()
的源碼html
1、shallowEqual
做用:PureComponet
作淺比較的核心function
java
源碼:react
import is from './objectIs';
const hasOwnProperty = Object.prototype.hasOwnProperty;
/**
* Performs equality by iterating through keys on an object and returning false
* when any key has values which are not strictly equal between the arguments.
* Returns true when the values of all keys are strictly equal.
*/
//true 爲不要更新
//false 爲要更新
function shallowEqual(objA: mixed, objB: mixed): boolean {
//同 Object.js()
//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#Description
//不要更新
if (is(objA, objB)) {
return true;
}
//只要有一個不是 object或爲 null 則返回 false,要更新
if (
typeof objA !== 'object' ||
objA === null ||
typeof objB !== 'object' ||
objB === null
) {
return false;
}
const keysA = Object.keys(objA);
const keysB = Object.keys(objB);
//兩個 object 的key 數不同,則返回 false,要更新
if (keysA.length !== keysB.length) {
return false;
}
// Test for A's keys different from B.
//每個 value 去一一比較是不是淺相等
//能執行到這裏,說明二者 key 的長度是相等的
for (let i = 0; i < keysA.length; i++) {
if (
//不經過原型鏈查找是否有本身的屬性
!hasOwnProperty.call(objB, keysA[i]) ||
//判斷兩值是否相等
!is(objA[keysA[i]], objB[keysA[i]])
) {
//只要沒有屬性/兩個value不等,則返回 false,須要更新
return false;
}
}
//默認返回 true,不須要更新
return true;
}
export default shallowEqual;
複製代碼
解析:
(1) 關於PureComponet
與Component
的區別,請看:
zh-hans.reactjs.org/docs/react-…git
(2) is()
即Object.is()
,React 直接將其實如今代碼內部了:github
/**
* inlined Object.is polyfill to avoid requiring consumers ship their own
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
*/
function is(x: any, y: any) {
return (
(x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare
);
}
export default is;
複製代碼
關於Object.is()
的做用及用法,請看:
developer.mozilla.org/zh-CN/docs/…web
(3) 注意下返回的true/false
由於是 return !shallowEqual()
,因此true
表示不更新,false
表示要更新api
(4) 主要分四種狀況
① 非對象類型的比較,直接使用is(objA, objB)
判斷ruby
② 到 ④ 是對象類型的比較:app
② objA/objB
中,只要有一個不是object
或爲null
則返回false
③ objA/objB
的keyLength
不同,則返回false
,此舉的目的是簡單比較,優化性能
④ 循環比較objA/objB
的每個value
,判斷是否淺相等
針對 ④ 的例子:
對象的value
是非對象類型:
const a={c:1,d:2}
const b={c:1,d:2}
Object.is(a,b) //false
hasOwnProperty.call(b, 'c') //true
Object.is(a['c'], b['c']) //true
複製代碼
對象的value
是對象類型:
const a={c:{e:3},d:2}
const b={c:{e:3},d:2}
hasOwnProperty.call(b, 'c') //true
//能夠看到,只能用於淺比較
Object.is(a['c'], b['c']) //false
複製代碼
能夠看到,Object.is()
是PureComponet
作淺比較的根本函數。
GitHub:
github.com/AttackXiaoJ…
(完)