工廠模式與建構函式模式
簡單工廠模式
以Object建構函式或字面量的方式建立物件有著重複性,會產生大量重複程式碼的缺陷,由此,便出現了工廠模式。
function createObj (name,age) {
var obj = new Object();
obj.name = name;
obj.age = age;
return obj;
}
var obj1 = createObj("小明",66);
var obj2 = createObj("小白",13);
console.log(obj1.name) //小明
console.log(obj2.name) //小白
工廠模式的缺陷
由於新建的所有物件都是Object的例項。所以出現了物件的識別問題
console.log(obj1 instanceof Object) //true
console.log(obj2 instanceof Object) //true
為了解決上述問題,又出現了建構函式模式
function CreateObj (name,age) { this.name = name; this.age = age; this.sayName = function () { } } var obj1 = new CreateObj('小白',19); var obj2 = new CreateObj('小明',10); console.log(obj1.name)//小白 console.log(obj2.name)//小明
可以看到工廠模式與建構函式的區別
沒有在函式內部新建Object例項 — var obj = new Object();
把屬性和方法都新增到了this上。
最後也沒有返回值。
注意,函式名的第一個字母是大寫,當然沒有也可以,但這樣做是為了區分建構函式與普通函式的區別,按照慣例是要加上的。事實上,建構函式和普通函式一樣,沒有什麼區別。而當呼叫函式的時候如果使用了new操作符,那麼這個普通的函式就成了一個建構函式。
當使用了new操作符對函式進行呼叫的時候,後臺會新建一個物件,將建構函式作用域賦給新的物件,所以this指標就指向了這個物件。最後是執行建構函式裡的程式碼,這裡是給新建的物件中添加了兩個屬性與方法。
此外,我們可以對這些例項化物件進行識別了。
function CreateObj1 (name,age) {
this.name = name;
this.age = age;
this.sayName = function () {
}
}
function CreateObj2 (name,age) {
this.name = name;
this.age = age;
this.sayName = function () {
}
}
var obj1 = new CreateObj1("小明",11);
var obj2 = new CreateObj2("小紅",11);
console.log(obj1.constructor) //CreateObj1 obj1例項的建構函式是CreateObj1
console.log(obj2.constructor) //CreateObj2 obj2例項的建構函式是CreateObj2
console.log(obj1 instanceof CreateObj1) //true obj1從屬於CreateObj1
console.log(obj2 instanceof CreateObj2) //true obj2從屬於CreateObj2
console.log(obj1 instanceof CreateObj2) //false obj1不從屬於CreateObj2
由此解決了物件識別的問題,我們可以知道這些例項物件都從屬於誰,而不像工廠模式一樣,所以的的例項物件都只是從屬於Object。但其實所以的物件都是從屬於Object的。
console.log(obj1 instanceof Object) //true
console.log(obj2 instanceof Object) //true
console.log(obj1.__proto__.__proto__ === Object.prototype) //true
但建構函式模式仍存在一些問題,即每個方法都會被重新建立一遍。
function CreateObj1 (name,age) {
this.sayName = function () {
}
}
以上函內在sayName屬性上定義了一個方法。而定義一個方法,就會生成一個新的物件。(函式也是物件)
如同 : var sayName = new Function(…)
這樣,隨著建構函式的每一次呼叫,就會新建出越來越多的相同的方法,而這些方法的功能都是相同的,浪費了空間。
function CreateObj1 () {
this.sayName = function () {
}
}
var obj1 = new CreateObj1();
var obj2 = new CreateObj1();
console.log(obj1.sayName == obj2.sayName) //false
通過地址的比較可以發現,不同例項之間的方法的引用地址是不同的。
如果說要避免重複建立方法的問題,可以這樣做:
function CreateObj1 () {
this.sayName = sayName;
}
function sayName () {
console.log(1)
}
var obj1 = new CreateObj1();
var obj2 = new CreateObj1();
console.log(obj1.sayName == obj2.sayName)//true
我們把函式的定義放到建構函式的外邊,然後在建構函式裡儲存函式的引用地址。從而避免了重複定義函式的問題。
但這種方案存在很多缺陷,並沒有被人們所用,缺少封裝性,汙染全域性。解決的方式是通過原型模式來解決。