遇到的問題
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const me = { name: 'Sina', talk() { console.log(`My name is ${this.name}`) }, }
const you = { name: 'Tim', talk() { console.log(`My name is ${this.name}`); }, }
me.talk() you.talk()
me.name = 'Tom' me.talk()
|
當我們有許多屬性一樣的物件時,若直接撰寫物件,會多出許多重複的code,並且物件的屬性是可以直接被修改,容易造成bug。
這時可以改用工廠函式來產生這些物件。
工廠函式
1 2 3 4 5 6 7 8 9 10 11
| function Person(name) { return { name, talk() { console.log(`My name is ${name}`) } } }
const me = Person('Tom'); me.talk()
|
工廠函式即是用函式直接回傳一個新的物件,物件的屬性的值可由函式的參數傳入。如此不僅避免重複的code,也防止物件的內容被任意修改。
範例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| function createElement(type, text, color) { const el = document.createElement(type); el.innerText = text; el.style.color = color; document.body.append(el);
return { el, setText(text) { el.innerText = text, }, setColor(color) { el.style.color = color, }, } }
const h1 = createElement('h1', 'Hey guys', 'red');
|
上面範例中使用工廠函式來快速製造 h1 元素並掛載到dom上。
工廠函式的問題
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function Person(name) { return { name, talk() { console.log(`My name is ${name}`) } } }
const me = Person('Tom'); const you = Person('Lisa');
me.talk = function() { return `Hello I am ${this.name}`; }
me.talk() you.talk()
|
使用工廠函式產生物件時,每個回傳的物件都是獨立的記憶體位置,如上我修改了 me.talk()的函式內容,
you.talk()並不會被修改,因為兩個是不同的獨立物件。
解決方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| const myProto = { talk() { return `I am ${this.name}` } }
function createPerson(name) { return Object.create(myProto, { name: { value: name, } }) }
const me = createPerson('Sina'); const you = createPerson('Lisa');
|
這次在工廠函式中,我們不直接回傳一個物件,而是用 Object.create() 方法,指定 myProto 為 prototype物件,
這樣 me.talk() 和 you.talk() 就會指向同一個函式了。