摘要:面試中,經(jīng)常遇到的一個(gè)簡(jiǎn)單算法題查找兩個(gè)單鏈表的公共節(jié)點(diǎn)最近在讀源碼的時(shí)候發(fā)現(xiàn)一個(gè)樹中對(duì)該算法的運(yùn)用見函數(shù),在此做簡(jiǎn)單的記錄。地址在樹中獲取當(dāng)前實(shí)例節(jié)點(diǎn)的父節(jié)點(diǎn)實(shí)例組件對(duì)應(yīng)的,比如的表示為類組件,其為對(duì)應(yīng)元素。
面試中,經(jīng)常遇到的一個(gè)簡(jiǎn)單算法題:查找兩個(gè)單鏈表的公共節(jié)點(diǎn)
最近在讀react源碼的時(shí)候發(fā)現(xiàn)一個(gè)react樹中對(duì)該算法的運(yùn)用(見getLowestCommonAncestor函數(shù)),在此做簡(jiǎn)單的記錄。
git地址
在react樹中獲取當(dāng)前實(shí)例節(jié)點(diǎn)的父節(jié)點(diǎn)實(shí)例
//HostComponent組件對(duì)應(yīng)的DOM,比如App的tag=3, 表示為類組件,其child為tag=5對(duì)應(yīng)div元素。 function getParent(inst) { do { inst = inst.return; // TODO: If this is a HostRoot we might want to bail out. // That is depending on if we want nested subtrees (layers) to bubble // events to their parent. We could also go through parentNode on the // host node but that wouldn"t work for React Native and doesn"t let us // do the portal feature. } while (inst && inst.tag !== HostComponent); if (inst) { return inst; } return null; }getLowestCommonAncestor
獲取節(jié)點(diǎn)A與B的最近的公共祖先節(jié)點(diǎn)
算法題:找到兩個(gè)鏈表的公共節(jié)點(diǎn)
export function getLowestCommonAncestor(instA, instB) { //獲取子節(jié)點(diǎn)A在樹中的深度 let depthA = 0; for (let tempA = instA; tempA; tempA = getParent(tempA)) { depthA++; } //獲取子節(jié)點(diǎn)B在樹中的深度 let depthB = 0; for (let tempB = instB; tempB; tempB = getParent(tempB)) { depthB++; } // If A is deeper, crawl up. // 如果A的高度高,那么A節(jié)點(diǎn)先往上走depthA - depthB個(gè)節(jié)點(diǎn),最后同時(shí)走,直到父節(jié)點(diǎn)是同一個(gè) while (depthA - depthB > 0) { instA = getParent(instA); depthA--; } // 如果B的高度高,那么B節(jié)點(diǎn)先往上走depthB - depthB個(gè)節(jié)點(diǎn),最后同時(shí)走,直到父節(jié)點(diǎn)是同一個(gè) // If B is deeper, crawl up. while (depthB - depthA > 0) { instB = getParent(instB); depthB--; } // Walk in lockstep until we find a match. // 現(xiàn)在,指針?biāo)幍奈恢玫母叨纫恢拢梢酝瑫r(shí)往上查找,直到找到公共的節(jié)點(diǎn) let depth = depthA; while (depth--) { if (instA === instB || instA === instB.alternate) { return instA; } instA = getParent(instA); instB = getParent(instB); } return null; }isAncestor
判斷A節(jié)點(diǎn)是否是B節(jié)點(diǎn)的祖先節(jié)點(diǎn)
export function isAncestor(instA, instB) { while (instB) { if (instA === instB || instA === instB.alternate) { return true; } instB = getParent(instB); } return false; }getParentInstance
對(duì)getParent的export封裝:
export function getParentInstance(inst) { return getParent(inst); }traverseTwoPhase
對(duì)inst及其以上的樹執(zhí)行冒泡捕獲的操作,執(zhí)行fn。類似事件的冒泡捕獲
export function traverseTwoPhase(inst, fn, arg) { const path = []; //將inst的父節(jié)點(diǎn)入棧,數(shù)組最后的為最遠(yuǎn)的祖先 while (inst) { path.push(inst); inst = getParent(inst); } let i; //從最遠(yuǎn)的祖先開始向inst節(jié)點(diǎn)捕獲執(zhí)行fn for (i = path.length; i-- > 0; ) { fn(path[i], "captured", arg); } //從inst節(jié)點(diǎn)開始向最遠(yuǎn)的祖先節(jié)點(diǎn)冒泡執(zhí)行fn for (i = 0; i < path.length; i++) { fn(path[i], "bubbled", arg); } }traverseEnterLeave
當(dāng)關(guān)注點(diǎn)從from節(jié)點(diǎn)移出然后移入to節(jié)點(diǎn)的時(shí)候,在from執(zhí)行執(zhí)行類似移入移出的操作,from節(jié)點(diǎn)
export function traverseEnterLeave(from, to, fn, argFrom, argTo) { const common = from && to ? getLowestCommonAncestor(from, to) : null; const pathFrom = []; while (true) { if (!from) { break; } if (from === common) { break; } const alternate = from.alternate; if (alternate !== null && alternate === common) { break; } pathFrom.push(from); from = getParent(from); } const pathTo = []; while (true) { if (!to) { break; } if (to === common) { break; } const alternate = to.alternate; if (alternate !== null && alternate === common) { break; } pathTo.push(to); to = getParent(to); } //以上代碼將from節(jié)點(diǎn)到from與to節(jié)點(diǎn)的最近公共祖先節(jié)點(diǎn)(不包括公共祖先節(jié)點(diǎn))push到pathFrom數(shù)組 //以上代碼將to節(jié)點(diǎn)到from與to節(jié)點(diǎn)的最近公共祖先節(jié)點(diǎn)(不包括公共祖先節(jié)點(diǎn))push到pathTo數(shù)組 // 以下代碼用于對(duì)pathFrom冒泡,執(zhí)行fn for (let i = 0; i < pathFrom.length; i++) { fn(pathFrom[i], "bubbled", argFrom); } // 以下代碼用于對(duì)pathTo捕獲,執(zhí)行fn for (let i = pathTo.length; i-- > 0; ) { fn(pathTo[i], "captured", argTo); } }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/102128.html
摘要:對(duì)于同一層級(jí)的一組子節(jié)點(diǎn),它們可以通過唯一進(jìn)行區(qū)分。基于以上三個(gè)前提策略,分別對(duì)以及進(jìn)行算法優(yōu)化。鏈表的每一個(gè)節(jié)點(diǎn)是,而不是在之前的虛擬節(jié)點(diǎn)。是當(dāng)前層的第一個(gè)節(jié)點(diǎn)。再次提醒,是的一層。 文章首發(fā)于個(gè)人博客 這是我 Deep In React 系列的第二篇文章,如果還沒有讀過的強(qiáng)烈建議你先讀第一篇:詳談 React Fiber 架構(gòu)(1)。 前言 我相信在看這篇文章的讀者一般都已經(jīng)了解...
摘要:因?yàn)榘姹緦⒄嬲龔U棄這三生命周期到目前為止,的渲染機(jī)制遵循同步渲染首次渲染,更新時(shí)更新時(shí)卸載時(shí)期間每個(gè)周期函數(shù)各司其職,輸入輸出都是可預(yù)測(cè),一路下來(lái)很順暢。通過進(jìn)一步觀察可以發(fā)現(xiàn),預(yù)廢棄的三個(gè)生命周期函數(shù)都發(fā)生在虛擬的構(gòu)建期間,也就是之前。 showImg(https://segmentfault.com/img/bVbweoj?w=559&h=300); 背景 前段時(shí)間準(zhǔn)備前端招聘事項(xiàng)...
摘要:異步實(shí)戰(zhàn)狀態(tài)管理與組件通信組件通信其他狀態(tài)管理當(dāng)需要改變應(yīng)用的狀態(tài)或有需要更新時(shí),你需要觸發(fā)一個(gè)把和載荷封裝成一個(gè)。的行為是同步的。所有的狀態(tài)變化必須通過通道。前端路由實(shí)現(xiàn)與源碼分析設(shè)計(jì)思想應(yīng)用是一個(gè)狀態(tài)機(jī),視圖與狀態(tài)是一一對(duì)應(yīng)的。 React實(shí)戰(zhàn)與原理筆記 概念與工具集 jsx語(yǔ)法糖;cli;state管理;jest單元測(cè)試; webpack-bundle-analyzer Sto...
摘要:目前,前端領(lǐng)域中勢(shì)頭正盛,使用者眾多卻少有能夠深入剖析內(nèi)部實(shí)現(xiàn)機(jī)制和原理。當(dāng)發(fā)現(xiàn)節(jié)點(diǎn)已經(jīng)不存在,則該節(jié)點(diǎn)及其子節(jié)點(diǎn)會(huì)被完全刪除掉,不會(huì)用于進(jìn)一步的比較。 目前,前端領(lǐng)域中 React 勢(shì)頭正盛,使用者眾多卻少有能夠深入剖析內(nèi)部實(shí)現(xiàn)機(jī)制和原理。本系列文章希望通過剖析 React 源碼,理解其內(nèi)部的實(shí)現(xiàn)原理,知其然更要知其所以然。 React diff 作為 Virtual DOM 的加速...
showImg(https://segmentfault.com/img/bVbw3tK?w=1240&h=827); 前端工程師這個(gè)崗位,真的是反人性的 我們來(lái)思考一個(gè)問題: 一個(gè)6年左右經(jīng)驗(yàn)的前端工程師: 前面兩年在用jQuery 期間一直在用React-native(一步一步踩坑過來(lái)的那種) 最近兩年還在寫微信小程序 下面一個(gè)2年經(jīng)驗(yàn)的前端工程師: 并不會(huì)跨平臺(tái)技術(shù),他的兩年工作都是Reac...
閱讀 3722·2021-10-12 10:11
閱讀 1989·2019-08-30 15:53
閱讀 1594·2019-08-30 13:15
閱讀 2310·2019-08-30 11:25
閱讀 1806·2019-08-29 11:24
閱讀 1656·2019-08-26 13:53
閱讀 3528·2019-08-26 13:22
閱讀 1770·2019-08-26 10:24