模板对象的对象构造函数

时间:2020-02-03 23:14:12

标签: javascript ecmascript-6

对于体育运动,我尝试构建一个构造器以基于模板构造一个对象。

template data 两个对象,其中 data 的键是 template 的键的子集:

const template = { a: 'foo', b: 'bar' };
const data = { a: 42 };

这些对象文字是示例。问题是如何对具有相同结构的任意对象执行此操作。也就是说,在对类构造函数进行编码时,属性()是未知的。

我想写一个构造函数,可以使用以下表达式基于此模板构造一个对象:

foo = new Foo (template, data)

其中console.log(foo)返回上面的示例// foo = {a:42}

这意味着,对象中存在的键将由模板对象文字定义。

到目前为止,我还没有找到在ES6(或更新版本)JS中实现此目的的好方法。

问:这样的构造函数是什么样子?对于基于类的方法来处理此类对象中的数据,有哪些好的模式?

一种怪异的方法是在构造函数中使用Object.assign(this, data)。例如:

class Foo {
  constructor(template, data) {
    localObject = niftyMergeFunction(template, data);
    Object.assign(this, localObject);
  }
}

但是,这是不好的,原因有几个。这是一个陈述,而不是一个表达。不是type-safe

我想避免继承,因为(i)我避免学习过时且有争议的做法,而更喜欢作文。此外,(ii) template 可以与 data 有一个共同的祖先,但由于概念上的原因,不能成为其父代。 (请考虑以下示例:人是动物,牛是动物;不要从人那里继承动物,也不要从动物那里继承牛,也许也从动物那里继承人的另一个实例。)

也没有基于原型的设计,因为它目前似乎不太受欢迎。

请注意,此时foo = Object.assign({}, data)可以轻松完成任务。但是,稍后我将使用部分分配cont Bar = in => Foo(template, in)并发送不同的数据结构而不是对象数据,例如bar = new Bar(someFunction(data));,但如何咖喱/部分分配给构造函数将是一个不同的问题,请仅将其视为现在。

3 个答案:

答案 0 :(得分:1)

JavaScript是一种基于对象的语言。 JavaScript中的类主要是语法糖。如果像我一样,您不喜欢面向类的面向对象,那么您就不必使用它。

如果您想编写一个函数来组合具有任意属性的对象,则使用Object.assign不会带来任何“麻烦”。

如果要防止进一步修改结果,可以使用Object.freeze

我认为您需要问自己的第一个问题是“我真的需要这样做吗?”您是否要使JavaScript外观和Haskell一样工作?这值得么?但是,您可能有充分的理由去做自己想做的事。

以下代码可能有用。

const curry = (fn, acc = [], cont) =>
      cont = (...args) => 
        (acc = [...acc, ...args], 
          args.length ? cont : fn(...acc))

const mapObject = (mapProperty, to, from) => 
    (Object.keys(to).forEach(k => 
        (isObject(to[k]) && isObject(from[k])) 
            ? mapObject(mapProperty, to[k], from[k])
            : mapProperty(to, from, k)), to)

const isObject = (o) => o !== null && typeof o === 'object'
const deepClone = (o) => JSON.parse(JSON.stringify(o))
const mapProperty = (to, from, key) => (from.hasOwnProperty(key) && (to[key] = from[key]))
const deepAssign = mapObject.bind(null, mapProperty)

const factory = curry((template, ...data) => 
                    data.reduce((acc, datum) => 
                        deepAssign(acc, datum), deepClone(template)))

const template = { a: '', b: '', c: { d: '' }, e: '', f: '' }
const myFactory = factory(template)
const o1 = { a: 'a'}
const o2 = { b: 'b' }
const o3 = { c: { d: 'd' } }
const o4 = { f: 'f' }
const o5 = { g: 'g' }

console.log(myFactory(o1)(o2)(o3)(o4)(o5)())

答案 1 :(得分:1)

class Foo {
  constructor (data, template) {
    this.data = data
    this.template = template
  }
  setTemplate (template) {
    this.template = template
  }
  get value () {
    let output = {}
    output[this.data] = this.template
    return output
  }
}

经过编辑以反映评论中的反馈

答案 2 :(得分:1)

基于传递给构造函数的参数,使用类语法构造函数中的属性毕竟是可能的。沿a => this[a]的行将函数映射到属性键的数组即可。在代码段中是一个示例,其中还对该属性进行了分配。

// example objects
const someObject = {
  a: 0,
  b: 0,
  c: 0,
};

const otherObject = {
  a: 1,
  c: 137,
  d: 42,
};

class Test {
  constructor(template, data) {
    Object.keys(template).map(a => {
      this[a] = data[a] ? data[a] : template[a];
      return null;
    });
    Object.seal(this);
  }
}

const test = new Test(someObject, otherObject);
console.log(test);
很好的补充是,它的新objecst在构造期间已经应用了Object.seal

更多评论

  • 如果还不能使用Object.seal,则在属性生成函数的末尾插入Object.freeze将有助于深度冻结。

  • 我无法实现此工作的实际目的:template对象的部分应用。这个想法是要有新的单变量类构造函数。 固定

相关问题