tl; dr 工作代码位于底部,可以更优雅。
我正在构建一个metalsmith(静态站点生成器)插件。 Metalsmith插件总是采用以下形式:
const myPlugin = options => (files, metalsmith, done) => {
// Mutate `files` or `metalsmith` in place.
done()
}
我已经使用函数(不可变)样式(Ramda.js)编写了我的插件,并希望用新值完全覆盖files
。以下是概念我想要的,但是不起作用,因为它重新分配files
到updated
而不操纵堆上的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]
}
})
}
有没有更好的方法来实现这些目标?
答案 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循环来添加字段。
Object.setPrototypeOf(old, Object.prototype)
)。