我在合并两个对象时遇到一些问题,这些对象具有退化为值的属性获取器/设置器。如何预防呢?我必须手动克隆它吗?
下面是我的pb的一个虚构示例:
function Factory1() {
const p = {};
return {
get prop1 () { return p.prop; },
set prop1 (value) { p.prop = value; }
};
}
function Factory2() {
const p = {};
return {
get prop2 () { return p.prop; },
set prop2 (value) { p.prop = value; }
}
}
const obj1 = Factory1();
const obj2 = Factory2();
const obj3a = {...Factory1(), ...Factory2()};
const obj3b = Object.assign(Factory1(), Factory2());
console.log('obj1.prop1 =>', Object.getOwnPropertyDescriptor(obj1, 'prop1'));
console.log('obj2.prop2 =>', Object.getOwnPropertyDescriptor(obj2, 'prop2'));
console.log('spread prop1 =>', Object.getOwnPropertyDescriptor(obj3a, 'prop1'));
console.log('spread prop2 =>', Object.getOwnPropertyDescriptor(obj3a, 'prop2'));
console.log('assign prop1 =>', Object.getOwnPropertyDescriptor(obj3b, 'prop1'));
console.log('assign prop2 =>', Object.getOwnPropertyDescriptor(obj3b, 'prop2'));
一个简单的例子:
function Factory1() {
return {
get prop1 () { return 42; }
};
}
const obj1 = Factory1();
const obj2 = Object.assign({}, Factory1())
console.log('obj1.prop1 =>', Object.getOwnPropertyDescriptor(obj1, 'prop1'));
// result
// obj1.prop1 => { get: [Function],
// set: undefined,
// enumerable: true,
// configurable: true }
console.log('obj2.prop1 =>', Object.getOwnPropertyDescriptor(obj2, 'prop1'));
// result
// obj2.prop1 => { value: 42,
// writable: true,
// enumerable: true,
// configurable: true }
根据要求,我将尝试说明我要面对的代码类型。当然,这是在多个模块中分派的代码提取的串联。
import axios from 'axios';
function createAxios (options = {}) {
const axiosClient = axios.create(options);
axiosClient.defaults.withCredentials = false;
axiosClient.defaults.headers.common['Accept'] = 'text/html';
return {axiosClient};
}
function WithQuery ({axiosClient}) {
// This is a sample server that supports CORS.
var sampleUrl = 'http://html5rocks-cors.s3-website-us-east-1.amazonaws.com/index.html';
return {
query (url) {
return axiosClient.get(url || sampleUrl);
}
};
}
function WithLastModified (context) {
let lastModified;
context.axiosClient.interceptors.response.use(function (response) {
const {headers} = response;
console.log('header last-modified:', headers['last-modified']);
lastModified = headers['last-modified'];
return response;
});
return {
getLastModified () {
return lastModified;
},
get lastModified () {
return lastModified;
}
}
}
function build (options) {
const httpClient = createAxios(options);
return Object.assign({},
httpClient,
{search: WithQuery(httpClient)},
WithLastModified(httpClient));
}
const api = build();
api.search.query().then(() => {
console.log('get lastModified:', api.lastModified); // not working, always undefined
console.log('getLastModified:', api.getLastModified()); // work
});
这种类型的工厂方法用于注入依赖关系,并通过伪混合添加功能到最终对象。
答案 0 :(得分:0)
如果检查代码,您会注意到,即使获取描述符并将其添加到新对象中,您的访问器也将保留对factoryN
内部范围的p
对象的访问权(这些访问器形成闭包) )。
也就是说,即使您将新的描述符定义到新的对象实例中,也要对同一目标对象进行突变。
结论:如果您不重新解释您的实际目标是什么,我会说没有办法解决问题。
我不确定我是否理解您对2个不同的闭包定义的不同局部变量p的声明。我关心的是obj1.prop1和obj2.prop2在obj3a上的get / set变成简单值
使用您自己的代码:
function Factory1() {
// This is a function scoped reference
const p = {};
return {
get prop1 () { return p.prop; },
set prop1 (value) { p.prop = value; }
};
}
p
是一个函数范围的引用,返回的整个访问器都是捕获p
的闭包。
如果您使用这些访问器并将它们添加到另一个对象,则p
仍将指向捕获的引用。因此,当您在许多对象中设置prop1
时,它们都将设置相同的目标p
对象!