代码实现
function observer(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
const target = Array.isArray(obj) ? [...obj] : {...obj};
Object.keys(obj).forEach((item) => {
const value = target[item];
if (value && typeof value === 'object') {
target[item] = observer(value);
return;
}
Object.defineProperty(target, item, {
get() {
console.log(value);
return value;
},
set(val) {
console.log('val :', val);
}
});
});
return target;
}
const test = {
target: {age: 2},
arr: [1, 2, 3],
name: 'test',
method: function () {}
};
const result = observer(test);
console.log('result', result);
console.log('result.name :', result.name);
console.log('result.target.age :', result.target.age);
console.log('result.arr[0] :', result.arr[0]);
执行结果
result {
target: { age: [Getter/Setter] },
arr: [ [Getter/Setter], [Getter/Setter], [Getter/Setter] ],
name: [Getter/Setter],
method: [Getter/Setter]
}
test
result.name : test
2
result.target.age : 2
1
result.arr[0] : 1
优化代码 解决循环引用问题
function observer(obj, caches = []) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
const hit = caches.filter((i) => i.original === obj)[0];
if (hit) {
// 解决循环引用问题
return hit.copy;
}
const target = Array.isArray(obj) ? [...obj] : {...obj};
caches.push({original: obj, copy: target}); // 解决循环引用问题
Object.keys(obj).forEach((item) => {
const value = target[item];
if (value && typeof value === 'object') {
target[item] = observer(value, caches);
return;
}
Object.defineProperty(target, item, {
get() {
console.log(value);
return value;
},
set(val) {
console.log('val :', val);
}
});
});
return target;
}
const test = {
target: {age: 2},
arr: [1, 2, 3],
name: 'test',
method: function () {}
};
test.test = test; // 循环引用
const result = observer(test);
console.log('result', result);
console.log('result.test :', result.test);
console.log('result.name :', result.name);
console.log('result.target.age :', result.target.age);
console.log('result.arr[0] :', result.arr[0]);
// result <ref *1> {
// target: { age: [Getter/Setter] },
// arr: [ [Getter/Setter], [Getter/Setter], [Getter/Setter] ],
// name: [Getter/Setter],
// method: [Getter/Setter],
// test: [Circular *1]
// }
// result.test : <ref *1> {
// target: { age: [Getter/Setter] },
// arr: [ [Getter/Setter], [Getter/Setter], [Getter/Setter] ],
// name: [Getter/Setter],
// method: [Getter/Setter],
// test: [Circular *1]
// }
// test
// result.name : test
// 2
// result.target.age : 2
// 1
// result.arr[0] : 1