无法将对象与吸气剂/吸气剂合并

时间:2018-10-10 14:30:06

标签: javascript

我在合并两个对象时遇到一些问题,这些对象具有退化为值的属性获取器/设置器。如何预防呢?我必须手动克隆它吗?

下面是我的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'));


更新2018-10-11

一个简单的例子:

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
});

这种类型的工厂方法用于注入依赖关系,并通过伪混合添加功能到最终对象。

1 个答案:

答案 0 :(得分:0)

如果检查代码,您会注意到,即使获取描述符并将其添加到新对象中,您的访问器也将保留对factoryN内部范围的p对象的访问权(这些访问器形成闭包) )。

也就是说,即使您将新的描述符定义到新的对象实例中,也要对同一目标对象进行突变。

结论:如果您不重新解释您的实际目标是什么,我会说没有办法解决问题。

回答一些OP的评论

  

我不确定我是否理解您对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对象!