代码之家  ›  专栏  ›  技术社区  ›  Henry Marshall

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

  •  1
  • Henry Marshall  · 技术社区  · 6 年前

    tl;博士 工作代码位于底部,可以使其更加优雅。

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

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

    我已经以功能性(不可变)风格编写了我的插件(带有 Ramda.js )并希望完全覆盖 files 使用新值。以下是 概念上 我想要的,但因为它是重新分配的,所以不起作用 文件 updated 不操纵 文件 对象。

    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 回复  |  直到 6 年前
        1
  •  1
  •   Pedro A Sindre Sorhus    6 年前

    在JavaScript中没有超优雅的方法来实现这一点,但这并不是一件坏事。事实是,编写良好的JavaScript不需要这样的行为。JavaScript中没有“通过引用传递”这样的东西,所以像您这样的尝试自然会不雅观。

    如果一个库需要这样的行为,而不是试图通过引用传递“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循环来添加字段。

    不过,我应该补充一点,根据具体情况,您可能还希望将对象的原型设置为预期值(例如,如果旧对象是日期的实例,并且您希望将其设置为普通对象,那么您当然需要调用 Object.setPrototypeOf(old, Object.prototype) )。