2016-01-21 117 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(); 
相關問題