Javascript组成如何扩展对象

时间:2018-04-08 14:45:04

标签: javascript inheritance composition

我正在尝试采用新的ES6功能来更好地组合没有类继承的对象。但是,我不明白如何扩展和对象或覆盖函数。下面的代码使用了Object.assign()的组合模式。

问题:如何在不复制整个TextCell对象的情况下创建第二个对象工厂UnderlinedCell。它的行为类似于TextCell,但getHeight返回getHeight + 1的差别很小,而draw方法添加了带有短划线“ - ”的行。

为什么我要这样做?:我正试图了解本视频中所述的构图概念Composition over Inheritance from Johansson

以下是对象工厂TextCell的代码。

const getHeight = (state) => ({
  getHeight: () => state.text.length
})

const draw = (state) => ({
  draw: () => state.text.join(" | ")
})

const TextCell = (text) => {
  let state = {
    text: text.split("\n")
  }

  return Object.assign(getHeight(state), draw(state))
}

console.log("The height of the cell is %s", TextCell("foo\nbar").getHeight())
console.log(TextCell("foo\nbar").draw())

2 个答案:

答案 0 :(得分:1)

首先,state是私有的。这意味着我们只能使用TextCell的公开方法,即getHeightdraw

现在,UnderlineCell是一个功能,可以TextCell组成,扩展 TextCell的实现。 e.g。



const getHeight = (state) => ({
  getHeight: () => state.text.length
})

const draw = (state) => ({
  draw: () => state.text.join(" | ")
})

const TextCell = (text) => {
  const state = {
    text: text.split("\n")
  }

  return Object.assign(getHeight(state), draw(state))
}


const UnderlineCell = (text) => {
  const textCell = TextCell(text);
  const getHeight = () => textCell.getHeight() + 1;
  const line = '\n------\n';
  const draw = () => textCell.draw().replace(' | ', line) + line;

  return {...textCell, getHeight, draw}; 
}

const uCell = UnderlineCell('hello\nthis');
console.log(uCell.draw());




答案 1 :(得分:1)

我仍然不明白为什么在给定的代码中使用闭包的复杂性而不是使用常规的this,因为这也很好,而且给定的代码看起来不可维护,并且最糟糕的是它隐藏了原来的state对象,以防止以后扩展对象。您可以像这样重写它并实现您的要求:

const getHeight = () => ({
  getHeight() {
    return this.text.length
  }
})

const draw = () => ({
  draw() {
    return this.text.join(" | ")
  }
})

const TextCell = (text) => {
  let state = {
    text: text.split("\n")
  }

  return Object.assign(state, getHeight(), draw())
}

const TextCell2 = (text) => {
  let state = TextCell(text)

  var originalGetHeight = state.getHeight;

  return Object.assign(state, {
    getHeight() {
      // use the original original getHeight and append + 1
      return originalGetHeight.call(this) + '1'
    },
    draw() {
      return this.text.join(" - ")
    }
  });
}

console.log("The height of the cell is %s", TextCell("foo\nbar").getHeight())
console.log(TextCell("foo\nbar").draw())

console.log("The height of the cell is %s", TextCell2("foo\nbar").getHeight())
console.log(TextCell2("foo\nbar").draw())

但是如果你想继续隐藏state对象的方法,那么你需要复制TextCell中的代码,因为在工厂方法中创建的state对象只是可在getHeight(state)draw(state)创建的闭包中访问。