React Native 性能優(yōu)化組件-PureComponent

背景

React 使用了 PureComponent,在 shouldComponentUpdate 進(jìn)行淺比較瞳抓,這里到底什么是淺比較呢长赞?

shallowEqual

在React里,shouldComponentUpdate源碼為:

if (this._compositeType === CompositeTypes.PureClass) {  
  shouldUpdate = !shallowEqual(prevProps, nextProps) || !shallowEqual(inst.state, nextState);
}

可以看到PureComponent就是對props跟state的前后狀態(tài)做了一個淺比較惠爽。

看看shallowEqual的源碼:

const hasOwn = Object.prototype.hasOwnPropertyfunctionis(x, y) {
  if(x === y) {
    returnx !==0 || y !==0 ||1/ x ===1/ y  
} else {
    returnx !== x && y !== y  
  }
}
export default function shallowEqual (objA, objB) {
  if ( is(objA, objB )) 
    return true
  i f( typeofobjA !=='object' || objA === null || typeofobjB !=='object' || objB   ===null) {
    return false
}
const keysA = Object.keys ( objA )
const keysB = Object.keys ( objB )
if  (  keysA.length !== keysB.length)
  return false
for ( leti =0; i < keysA.length; i++) {
    if ( !hasOwn.call ( objB, keysA[i] )  || !is(objA[keysA[i]], objB[keysA[i]])) {
      return false
    }  
  }
return true
}

Object.is()

在解析 shallowEqual的源碼之前添吗,先來認(rèn)識一下 Object.is()沥曹,這個函數(shù)是用來比較兩個值是否相等。

為什么要用這個來比較而不是 == 或者 === 呢根资?

==

首先先看 ==架专,由于 JS 是弱類型的,如果使用 == 進(jìn)行比較玄帕,== 操作符會自動將 0部脚,‘’(空字符串),null裤纹,undefined 轉(zhuǎn)成布爾型 false委刘,這樣就會出現(xiàn)

0==' '// true
null==undefined// true
[1] ==true// true

這顯然是不符合預(yù)期的丧没。所以 JS 為我們提供了全等操作符 ===,它不會進(jìn)行類型轉(zhuǎn)換锡移,也就是說如果兩個值一樣呕童,必須符合類型也一樣。但是淆珊,它還是有兩種疏漏的情況

+0 === -0//true夺饲,但我們期待它返回falseNaN===NaN//false,我們期待它返回true

所以施符,Object.is() 修復(fù)了 `=== 這兩種判斷不符合預(yù)期的情況往声,

function (x, y){
  // SameValue algorithm
  if(x === y) {
    // 處理為+0 != -0的情況
    returnx !==0 || 1/ x ===1/ y;    
  } else {
    // 處理 NaN === NaN的情況
    return x !== x && y !== y;    
  }
};

這樣就使得 Object.is() 總是返回我們需要的結(jié)果。 它在下面6種情況下戳吝,會返回 true

  • 兩個值都是 undefined
  • 兩個值都是 null
  • 兩個值都是 true 或者都是 false
  • 兩個值是由相同個數(shù)的字符按照相同的順序組成的字符串
  • 兩個值指向同一個對象
  • 兩個值都是數(shù)字并且
    • 都是正零 +0
    • 都是負(fù)零 -0
  • 都是 NaN
  • 都是除零和 NaN 外的其它同一個數(shù)字

可以看出Object.is 可以對基本數(shù)據(jù)類型: null,undefined,number,string,boolean做出非常精確的比較浩销,但是對于引用數(shù)據(jù)類型是沒辦法直接比較的。

剖析 shallowEquall

// 用原型鏈的方法
const hasOwn = Object.prototype.hasOwnProperty
// 這個函數(shù)實際上是 Object.is() 的 polyfill
functionis (x, y) {
  if (x === y) {
    returnx !==0 || y !==0 ||1/ x === 1/ y  
  } else {
    returnx !== x && y !== y  
  }
} 
export default function shallowEqual (objA, objB) {
  // 首先對基本數(shù)據(jù)類型的比較
  if (is(objA, objB))
    return true
  // 由于 Obejct.is() 可以對基本數(shù)據(jù)類型做一個精確的比較听哭, 所以如果不等
  // 只有一種情況是誤判的慢洋,那就是 object, 所以在判斷兩個對象都不是 object
  // 之后,就可以返回 false 了
  if (typeofobjA !== 'object' || objA === null || typeofobjB !== 'object' || objB ===null ) {
    return false
  }
  // 過濾掉基本數(shù)據(jù)類型之后陆盘,就是對對象的比較了
  // 首先拿出 key 值普筹,對 key 的長度進(jìn)行對比 
  const keysA = Object.keys( objA)
  const keysB = Object.keys(objB)  
  // 長度不等直接返回 false 
  if (keysA.length !== keysB.length)
    return false
  // key 相等的情況下,在去循環(huán)比較
  for  (let i =0; i < keysA.length; i++) {
    // key值相等的時候
    // 借用原型鏈上真正的 hasOwnProperty 方法礁遣,判斷ObjB里面是否有A的key的key值
    // 屬性的順序不影響結(jié)果也就是 {name:'daisy', age:'24'} 跟 {age:'24'斑芜,name:'daisy' } 是一樣的
    // 最后肩刃,對對象的value進(jìn)行一個基本數(shù)據(jù)類型的比較祟霍,返回結(jié)果
    if( !hasOwn.call(objB, keysA[i])  || !is(objA[keysA[i]], objB[keysA[i]])){
      return false
     }  
  }
  return true
}

總結(jié)

回到最開始的問題,淺比較為什么沒辦法對嵌套的對象比較盈包?

由上面的分析可以看到沸呐,當(dāng)對比的類型為Object的時候并且key的長度相等的時候,淺比較也僅僅是用Object.is()對Object的value做了一個基本數(shù)據(jù)類型的比較呢燥,所以如果key里面是對象的話崭添,有可能出現(xiàn)比較不符合預(yù)期的情況,所以淺比較是不適用于嵌套類型的比較的叛氨。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末呼渣,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子寞埠,更是在濱河造成了極大的恐慌屁置,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仁连,死亡現(xiàn)場離奇詭異蓝角,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門使鹅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來揪阶,“玉大人,你說我怎么就攤上這事患朱÷沉牛” “怎么了?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵裁厅,是天一觀的道長蕴茴。 經(jīng)常有香客問我,道長姐直,這世上最難降的妖魔是什么倦淀? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮声畏,結(jié)果婚禮上撞叽,老公的妹妹穿的比我還像新娘。我一直安慰自己插龄,他們只是感情好愿棋,可當(dāng)我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著均牢,像睡著了一般糠雨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上徘跪,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天甘邀,我揣著相機(jī)與錄音,去河邊找鬼垮庐。 笑死松邪,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的哨查。 我是一名探鬼主播逗抑,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼寒亥!你這毒婦竟也來了邮府?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤溉奕,失蹤者是張志新(化名)和其女友劉穎褂傀,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體腐宋,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡紊服,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年檀轨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片欺嗤。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡参萄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出煎饼,到底是詐尸還是另有隱情讹挎,我是刑警寧澤,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布吆玖,位于F島的核電站筒溃,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏沾乘。R本人自食惡果不足惜怜奖,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望翅阵。 院中可真熱鬧歪玲,春花似錦、人聲如沸掷匠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽讹语。三九已至钙皮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間顽决,已是汗流浹背短条。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留擎值,地道東北人慌烧。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓逐抑,卻偏偏與公主長得像鸠儿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子厕氨,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執(zhí)行單位為行(line)进每,也就是一...
    悟名先生閱讀 4,148評論 0 13
  • 說在前面 關(guān)于 react 的總結(jié)過去半年就一直碎碎念著要搞起來,各(wo)種(tai)原(lan)因(le)命斧。心...
    陳嘻嘻啊閱讀 6,864評論 7 41
  • 前言 影響性能最大的因素是界面的重繪和重排版田晚,React 背后的 Virtual DOM 就是盡可能地減少重繪與重...
    yuzhiyi_宇閱讀 2,655評論 0 1
  • 3. JSX JSX是對JavaScript語言的一個擴(kuò)展語法, 用于生產(chǎn)React“元素”国葬,建議在描述UI的時候...
    pixels閱讀 2,823評論 0 24
  • 無話可說的婚姻贤徒,無疑是悲哀的芹壕。明明家里還有一個人,可你跟他卻沒有話可說接奈,你們各干各的踢涌,互不打擾,原本應(yīng)該溫暖的家序宦,...
    無為無殤閱讀 526評論 0 3