2016-01-21 2 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' является свойством прототипа, а не только созданным объектом. Все объекты, которые наследуются от этого прототипа, разделяют это свойство. Аналогичный случай [здесь] (http://stackoverflow.com/questions/34363094/understanding-prototypal-inheritance-methodologies-in-js/34363433) – MinusFour

+0

'Object.create' создает новый пустой объект, который наследует свойства от' filterBuilder '. Он не создает новый массив или свойство 'filters'. – 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

Спасибо за четкий ответ. Я где-то читал, и я должен избегать использования 'new', я думаю, что применяется только для наследования? – toy

+1

Это нормально, это зависит. Вы можете сделать свою собственную вещь с помощью Object.create, я бы нацелился на что-то вроде MyObject.new() ', это лучше, чем' new MyObject() '. Но с ES6 'class' и оператором распространения вы избегаете некоторой путаницы и незнакомого синтаксиса. – elclanrs

+0

@toy: Да, вы должны избегать «новых» при создании объектов-прототипов для подклассов, которые должны наследоваться от другого объекта. Нет причин бояться «нового» в другом месте. – 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(); 
Смежные вопросы