前言:
在 React源碼解析之updateClassComponent(下) 中提到了
PureComponent
的淺比較:
//如果是純元件的話,用**淺比較**來比較 props/state
if (ctor.prototype && ctor.prototype.isPureReactComponent) {
return (
//淺等于的判斷
!shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
);
}
複制
接下來就看下
shallowEqual()
的源碼
一、shallowEqual
作用:
PureComponet
做淺比較的核心
function
源碼:
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
的差別,請看:
https://zh-hans.reactjs.org/docs/react-api.html#reactpurecomponent
(2)
is()
即
Object.is()
,React 直接将其 實作在代碼内部了:
/**
* 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()
的作用及用法,請看:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/is
(3) 注意下傳回的
true/false
因為是 return
!shallowEqual()
,是以
true
表示不更新,
false
表示要更新
(4) 主要分四種情況
① 非對象類型的比較,直接使用
is(objA, objB)
判斷
② 到 ④ 是對象類型的比較 :
②
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:
https://github.com/AttackXiaoJinJin/reactExplain/blob/master/react16.8.6/packages/shared/shallowEqual.js
(完)