我正在研究一个ngrx选择器,它将状态树的一部分转换为视图模型。举个简单的例子,在我的状态树中,我有一个manager
数组。因此,我对状态树进行了以下设置,并查看了模型 -
export interface Manager {
id: string,
name: string
}
export interface AppState {
managers: Manager[]
}
export interface ManagersVM {
byId: {[key: string]: Manager},
allIds: string[]
}
export const defaultManagersVM: ManagersVM {
byId: {},
allIds: []
};
然后在我的选择器中,我有:
export const selectManagersVM = createSelector(selectManagers, (data) => {
let mgrsVM: ManagersVM = { ...defaultManagersVM };
for(let mgr of data.managers) {
mgrsVM.byId[mgr.id] = mgr;
mgrsVM.allIds.push(mgr.id);
}
})
我遇到的问题是:
行let mgrsVM: ManagersVM = { ...defaultManagersVM };
似乎没有制作defaultManagersVMs属性的副本。 (运行选择器后,一个console.log的defaultManagersVM显示它现在有一个非空的byId和allIds)。我的印象是新定义的对象中的传播操作符会创建一个副本,但这看起来是错误的。如何确保defaultManagersVM不会在我的选择器中发生变异。
答案 0 :(得分:1)
扩展运算符does not make a deep copy of nested objects,JavaScript默认没有此功能。一个选项是使用外部库(即Lodash,它支持深度克隆)。
或者,如果您需要一些其他库未涵盖的特定功能,您可以编写自己的递归深度克隆功能。
答案 1 :(得分:0)
这是一个递归的 deepClone 方法,我选择了某个似乎可以完成工作的方法
export function deepClone(state) {
if (Array.isArray(state)) {
const newState = [];
for (let index = 0; index < state.length; index++) {
const element = state[index];
newState[index] = deepClone(element);
}
return newState;
}
if (typeof state === 'object') {
const newState = {...state};
Object.keys(newState).forEach(key => {
if (newState.hasOwnProperty(key)) {
const val = newState[key];
newState[key] = deepClone(val);
}
});
return newState;
}
return state;
}
您可能还想将 deepFreeze 应用于任何不应变异的内容。你得到一个错误,但至少它是在突变点。 p>
export function deepFreeze (o) {
Object.freeze(o);
Object.getOwnPropertyNames(o).forEach((prop) => {
if (o.hasOwnProperty(prop)
&& o[prop] !== null
&& (typeof o[prop] === 'object')
&& !Object.isFrozen(o[prop])) {
deepFreeze(o[prop]);
}
});
return o;
}