为什么Object.create没有为我创建新列表?

时间:2016-01-21 16:04:33

标签: javascript

我尝试在JavaScript中创建构建器模式。但是我想知道为什么如果我拨打Object.create两次,我会得到与以前相同的列表。

这是我的代码。

var filterBuilder = {
  filters: [],
  addFilter: function(options) {
    var filter = { 
      'type': 'selector',
      'dimension': options.dimension,
      'value': options.value
    }
    this.filters.push(filter);
    return this;
  },
  build: function() {
    return this.filters;
  }
};

如果我运行Object.create(filterBuilder).build(),我会[]这是好的。但是当我开始添加过滤器

Object.create(filterBuilder).addFilter({dimension: '1', value: 'v'}).build();

我得到一个很好的过滤器

但是如果我这样做

Object.create(filterBuilder).addFilter({dimension: '1', value: 'v'}).addFilter({dimension: '1', value: 'v'}).build();

我将获得三个过滤器,第一个来自上一个调用。是不是Object.create应该为我创建一个新对象?

3 个答案:

答案 0 :(得分:1)

原型属性是共享的,因此filters数组对于您创建的两个对象都是相同的。如果您希望每个对象都有自己的filters,则必须将其添加为拥有属性(该对象拥有的属性,而不是原型),即:

var filterBuilder = {
  addFilter: function(options) {
    var filter = {
      'type': 'selector',
      'dimension': options.dimension,
      'value': options.value
    }
    this.filters.push(filter);
    return this;
  },
  build: function() {
    return this.filters;
  }
};

var a = Object.create(filterBuilder)
a.filters = [];
a.addFilter({dimension: '1', value: 'v'}).build();

var b = Object.create(filterBuilder)
b.filters = []
b.addFilter({dimension: '1', value: 'v'}).addFilter({dimension: '1', value: 'v'}).build();

console.log(a.filters.length, b.filters.length); // 1 2

您也可以使用new执行此操作:

function FilterContainer() {
  this.filters = [];
}

FilterContainer.prototype.addFilter = function() {
  ...
};

FilterContainer.prototype.build = function() {
  ...
};

// Has its own `filters` array
new FilterContainer().addFilter(...).build();

答案 1 :(得分:1)

当您多次调用Object.create(filterBuilder)时,会得到两个对象,这些对象包含对同一filters数组的引用。

var b1 = Object.create(filterBuilder);
var b2 = Object.create(filterBuilder);

// now b1.filters is the _same_ object as b2.filters,
// so calling
b1.filters.push(...);

// will inevitably modify b2.filters as well.

这里你最好的选择是使用经典函数和原型

function FilterBuilder() {
    this.filters = [];
}

FilterBuilder.prototype.addFilter = function() { };

var builder = new FilterBuilder();
builder.addFilter();

答案 2 :(得分:1)

Object.create()接受一个可选的第二个参数,该参数可以定义不从原型继承的属性,因此您可以(重新)定义新创建的对象的filters属性,如下所示:

Object.create(filterBuilder, { 
  filters : { writable : true, enumerable: true, value : [] }
})

https://jsfiddle.net/1m7xx4ge/2/

// full code

var filterBuilder = {
  filters: [],
  addFilter: function(options) {
    var filter = { 
      'type': 'selector',
      'dimension': options.dimension,
      'value': options.value
    }
    this.filters.push(filter);
    return this;
  },
  build: function() {
    return this.filters;
  }
};

Object.create(filterBuilder, { 
  filters : { writable : true, enumerable : true, value : [] }
})
.addFilter({dimension: '1', value: 'v'}).build();

Object.create(filterBuilder, { 
   filters : { writable : true, enumerable : true, value : [] }
})
.addFilter({dimension: '1', value: 'v'})
.addFilter({dimension: '1', value: 'v'}).build();