通过引用替换JS对象[重构工作代码]

时间:2018-03-24 12:58:09

标签: javascript pass-by-reference heap-memory

tl; dr 工作代码位于底部,可以更优雅。

我正在构建一个metalsmith(静态站点生成器)插件。 Metalsmith插件总是采用以下形式:

const myPlugin = options => (files, metalsmith, done) => {
  // Mutate `files` or `metalsmith` in place.
  done()
}

我已经使用函数(不可变)样式(Ramda.js)编写了我的插件,并希望用新值完全覆盖files。以下是概念我想要的,但是不起作用,因为它重新分配filesupdated而不操纵堆上的files对象。

const myPlugin = options => (files, metalsmith, done) => {
  const updated = { foo: "foo" }
  files = updated

  done()
}

我已经实现了所需的功能,但是看起来不太优雅。

const myPlugin = options => (files, metalsmith, done) => {
  const updated = { foo: "foo" }
  deleteMissingKeys(old, updated)
  Object.assign(old, updated)

  done()
}

const deleteMissingKeys = (old, updated) => {
  Object.keys(old).forEach(key => {
    if (!updated.hasOwnProperty(key)) {
      delete old[key]
    }
  })
}

有没有更好的方法来实现这些目标?

1 个答案:

答案 0 :(得分:1)

在JavaScript中没有超级优雅的方法来做到这一点,但这不是一件坏事。事实是,编写良好的JavaScript不应该像这样的行为。在JavaScript中没有“pass-by-reference”这样的东西,所以像你这样的尝试是不自然的。

一个库需要这样的行为,而不是试图找出一个“hack”来传递引用,有一个更“javascriptonic”的方法来做它,它传递一个包装器对象期望的对象:

// instead of trying to use a "hack" to pass-by-reference
var myObj = { /* ... */ };
function myFunc(obj) {
    // your hack here to modify obj, since
    // obj = { /* ... */ }
    // won't work, of course
}
myFunc(myObj);

// you should use a wrapper object
var myWrapper = {
    myObj: { /* ... */ }
}
function myFunc(wrapper) {
    wrapper.myObj = { /* ... */ };
}
myFunc(myWrapper);

我强烈建议您首先重新考虑为什么要真正做到这一点。

但如果你坚持,你的解决方案并不是那么糟糕,我喜欢你使用Object.assign()而不是笨重的for循环来添加字段。

但是,我应该补充一点,根据情况,您可能还希望将对象的原型设置为预期值(例如,如果旧对象是Date的实例,并且您希望将其设为普通对象,你当然需要致电Object.setPrototypeOf(old, Object.prototype))。

相关问题