Javascript 构建器模式看不到声明的变量

Javascript Builder Pattern Not Seeing Declared Varialble

我正在尝试实施构建器模式以生成 JSON 选项字符串,这些选项被传递到库中以生成小部件。我不明白为什么 console.log 下面的 this.options 是未定义的。

let Options = function(options) {
  this.options = options;
}

let OptionsObjectBuilder = function () {

  let options;

  return {
      addConstantLineToValueAxis: function (lineValue) {
          console.log(this.options); // EQUALS UNDEFINED SO CAN'T ADD TO THIS OBJECT
          this.options.valueAxis.constantLine.value = lineValue;
          return this;
      },
      build: function () {
          return new Options(this.options);
      }
  };
};

let option = new OptionsObjectBuilder().addConstantLineToValueAxis(1000000000).build();

我相信我应该只在构建器模式中的添加函数末尾返回时使用 this。我仍然不确定为什么在示例 (zetcode.com/javascript/builderpattern) 中我的代码基于.. 他们使用 this.name 设置值,但在他们的构建函数中传递了 name

// @Steven de Salas: expando function: 
function buildObjectDepth(obj, base) {
    return Object.keys(obj)
      .reduce((clone, key) => {
        key.split('.').reduce((innerObj, innerKey, i, arr) => 
          innerObj[innerKey] = (i+1 === arr.length) ? obj[key] : innerObj[innerKey] || {}, clone)
        return clone;
    }, Object.assign({}, base));
}

let Options = function(options) {
  this.options = options;
}

let OptionsObjectBuilder = function () {

  let options = {};

  return {
      addConstantLineToValueAxis: function (lineValue) {
         options = buildObjectDepth({"valueAxis.constantLine.value": lineValue}, options);
         return this;
      },
      build: function () {
          return new Options(options);
      }
  };
};

let obj = new OptionsObjectBuilder().addConstantLineToValueAxis(1000000000).build();

str = JSON.stringify(obj);
str = JSON.stringify(obj, null, 4); // indented output.
alert(str);

构建器有两种不同的方式来存储临时状态:

  • 在构建器对象本身中(通过设置 this.options =
  • 在闭包中(通过设置options =

闭包示例的好处是外部无法访问临时构建器状态。

您可以使用任何一种方式,只要建造者从正确的地方使用它们。我将修复您提到的 post 中的损坏示例。我认为他们开始使用闭包,但它没有用,因为参数名称隐藏了闭包变量,他们最终在切换到使用 this 时感到困惑。他们忘记更新 build() 函数以从正确的位置读取。

使用构建器对象状态 - 公开内部状态

let Task = function(name, description, finished, dueDate) {

    this.name = name;
    this.description = description;
    this.finished = finished;
    this.dueDate = dueDate;
}

let TaskBuilder = function () {
    return {
        setName: function (name) {
            this.name = name;
            return this;
        },
        setDescription: function (description) {
            this.description = description;
            return this;
        },
        setFinished: function (finished) {
            this.finished = finished;
            return this;
        },
        setDueDate: function (dueDate) {
            this.dueDate = dueDate;
            return this;
        },
        build: function () {
            return new Task(this.name, this.description, this.isFinished, this.dueDate);
        }
    };
};

let builder = new TaskBuilder().setName('Task A').setDescription('finish book')
    .setDueDate(new Date(2019, 5, 12));
let task = builder.build();
// Notice the builder does expose the name/description... properties
console.log({builder, task});

使用闭包变量 - 隐藏内部状态

let Task = function(name, description, finished, dueDate) {

    this.name = name;
    this.description = description;
    this.finished = finished;
    this.dueDate = dueDate;
}

let TaskBuilder = function () {

    let name;
    let description;
    let isFinished = false;
    let dueDate;

    return {
        setName: function (pName) {
            name = pName;
            return this;
        },
        setDescription: function (pDescription) {
            description = pDescription;
            return this;
        },
        setFinished: function (pFinished) {
            finished = pFinished;
            return this;
        },
        setDueDate: function (pDueDate) {
            dueDate = pDueDate;
            return this;
        },
        build: function () {
            return new Task(name, description, isFinished, dueDate);
        }
    };
};

let builder = new TaskBuilder().setName('Task A').setDescription('finish book')
    .setDueDate(new Date(2019, 5, 12));
let task = builder.build();
// Can't see the name/description... properties on the builder, just the methods
console.log({builder, task});