2016-01-21 74 views
0

我正在尝试在JavaScript中创建一个生成器模式。但我想知道为什么如果我打电话Object.create两次,我得到了和以前一样的清单。为什么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

因为'filter'是原型的属性而不是新创建的对象。所有从该原型继承的对象都共享该属性。类似的情况[here](http://stackoverflow.com/questions/34363094/understanding-prototypal-inheritance-methodologies-in-js/34363433) – MinusFour

+0

Object.create'创建了一个新的空对象,它继承了filterBuilder的属性'。它不会创建新的数组或“过滤器”属性。 – Bergi

回答

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(); 
+0

感谢您的明确答复。我读了某处,我应该避免使用'新'我想这只适用于继承? – toy

+1

这是好的建议,这取决于。你可以用'Object.create'来创建你自己的东西,我的目标是像'MyObject.new()',这比'new MyObject()'更好。但是使用ES6'class'和扩展运算符可以避免一些混淆和不熟悉的语法。 – elclanrs

+0

@toy:是的,当为从其他对象继承的子类创建原型对象时,应该避免使用'new'。没有理由在其他地方担心新事物。 – Bergi

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(); 
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(); 
相关问题