我尝试在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
应该为我创建一个新对象?
答案 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();