+-
假如数组里有n个对象,把这n个对象里对象的属性或属性值有改变的对象单独拎出来,除了把新旧数组遍历循环对比,请问还有其他效率更高更优雅的方法吗?
可以参考vue的思想,劫持对象,触发set方法时把该对象提出来。
const temp = [
{
name: 1,
children: ['1-1', '1-2'],
},
{
name: 2,
children: ['2-1', '2-2'],
},
{
name: 3,
children: ['3-1', '3-2'],
},
]
const useObjObserver = (obj) => {
const effects = new Map()
const baseState = new Map()
const INTERNAL_PAERNT_KEY = '__PARENT'
const INTERNAL_FIELD_NAME = '__FIELD'
const collectFieldNameToRoot = (obj) => {
let path = [obj[INTERNAL_FIELD_NAME]]
let parent = obj[INTERNAL_PAERNT_KEY]
while (parent && parent[INTERNAL_FIELD_NAME]) {
path.push(parent[INTERNAL_FIELD_NAME])
parent = parent[INTERNAL_PAERNT_KEY]
}
return path.reverse().join('.')
}
const handler = {
get(target, key, receiver) {
if (typeof target[key] === 'object' && target[key] !== null) {
target[key][INTERNAL_PAERNT_KEY] = target
target[key][INTERNAL_FIELD_NAME] = key
return new Proxy(target[key], handler)
}
return Reflect.get(target, key, receiver)
},
set(obj, prop, value) {
const path = collectFieldNameToRoot(obj)
effects.set(path, value)
if (!baseState.has(path)) {
baseState.set(path, obj[prop])
}
obj[prop] = value
return true
},
}
const observedObj = new Proxy(obj, handler)
const applyChange = () => {
effects.clear()
baseState.clear()
}
const findChange = () => {
const ans = []
for (const key of effects.keys()) {
const base = baseState.get(key)
const effect = effects.get(key)
if (base !== effect) {
ans.push(key)
}
}
return ans
}
return { observedObj, findChange, applyChange }
}
const { observedObj, findChange, applyChange, revoke } = useObjObserver(temp)
observedObj[0].name = '3'
observedObj[1].children[0] = '1-3'
console.log(findChange()) //[ '0', '1.children' ]
//应用变更
applyChange()
console.log(findChange()) //[]
//重新赋值,但是前后的值没有变
observedObj[2].children[1] = '3-2'
console.log(findChange()) //[]
//前后的值改变
observedObj[2].children[1] = '3-3'
console.log(findChange()) //[ '2.children' ]