const isObject = target => typeof target === 'object' && target !== null;
const produce = (target, action) => {
const copy = Array.isArray(target) ? [...target] : {...target};
let temp = copy;
const handler = {
get(target, key) {
const value = temp[key];
if (Array.isArray(target)) {
if (typeof target[key] === 'function') {
return value.bind(temp);
} else if (key === 'length') {
return value;
}
}
// 自上而下逐层浅拷贝
temp[key] = isObject(value)
? Array.isArray(value)
? [...value]
: {...value}
: value;
temp = temp[key];
if (isObject(value)) {
return new Proxy(value, handler);
}
return value;
},
set(target, key, value) {
temp[key] = value;
temp = copy;
return true;
},
deleteProperty(target, key) {
delete temp[key];
temp = copy;
return true;
}
};
const proxy = new Proxy(target, handler);
action(proxy);
return copy;
};
const arr = [1, 2, 3, {a: {b: 2, d: 1}, c: {}}];
const clone = produce(arr, draft => {
draft[2] = 2;
draft.shift();
draft.push(4);
draft[2].a.b = 'b';
delete draft[2].a.d;
});
// clone: [2,2,{"a":{"b":"b"},"c":{}},4]
// clone[2].c === arr[3].c : true