1. 工廠模式
function createPerson(name, age){
var obj = new Object();
obj.name = name;
obj.age = age;
obj.sayName = function(){
console.log(this.name); // | console.log(obj.name)
};
return obj;
}
var p1 = createPerson("ys", 12);
var p2 = createPerson("ys", 12);
console.log(p1); // { name: 'ys', age: 12, sayName: [Function] }
console.log(p2); // { name: 'ys', age: 12, sayName: [Function] }
console.log(p1 == p2); //false
特點:
- 內部創建對象,外部返回,相當於調用函數,
- 對象無類型(比如其他oo語言,new一個對象,那個這個對象的構造函數就是對象類型)
2.構造函數模式
function Person(name, age){
this.name = name;
this.age = age;
this.sayName = function(){
console.log(this.name);
};
}
var p1 = new Person("ys", 12);
var p2 = new Person("ys", 12);
console.log(p1); // { name: 'ys', age: 12, sayName: [Function] }
console.log(p2); // { name: 'ys', age: 12, sayName: [Function] }
console.log(p1 == p2); //false
console.log(p1 instanceof Person); //true
console.log(p2 instanceof Person); //true
console.log(p1 instanceof Object); //true
console.log(p2 instanceof Object); //true
console.log(p1.constructor == Person); //true /*constructor屬性爲構造函數屬性,指向構造函數Person*/
console.log(p2.constructor == Person); //true
特點:
- 通過該模式創建的對象有自定義類型Person, 每個對象都是構造函數的實例
- 構造函數已經不再是意義上的調用函數,而是使用了new,構造過程包括四個步驟:
- ①創建一個新對象
- ②將構造函數的作用域賦給新對象(因此this指向了這個新對象)
- ③執行構造函數中的代碼(爲這個新對象添加屬性)
- ④返回新對象
對於這樣的構造函數模式,會發現有一點瑕疵,那就是sayName函數的功能是一樣的,但是每個對象的實例都有該函數,這樣卻顯得有點冗餘,在此基礎上,進行了一些改良:
function Person(name, age){
this.name = name;
this.age = age;
this.sayName = sayName;
}
function sayName(){
console.log(this.name);
}
將公共的函數部分,提取出來,作爲全局函數,使得每個構造函數去調用他,達到了所有實例對象複用的效果。
2015-12-12 補充…
通過不斷的的學習,對構造函數模式有了新的理解,補充:
上面我寫的構造函數是用函數聲明的方式定義的,另一種方法,我們也可以用對象直接量方法聲明
var Person = function(name, age){
this.name = name;
this.age = age;
this.sayName = function(){
console.log(this.name);
};
}
var p1 = new Person("ys", 12);
var p2 = new Person("ys", 12);
console.log(p1); // { name: 'ys', age: 12, sayName: [Function] }
console.log(p2); // { name: 'ys', age: 12, sayName: [Function] }
這樣同樣我得到了效果….但是最近看書學習,發現了一個問題,上面我這種方法(包括兩種方法 )安全嗎?
就連我之前都沒有質疑過安全性,看看下面的代碼
構造函數我就不寫了.函數,對象直接量都是一個意思…
var p1 = Person("ys", 12);
var p2 = Person("ys", 12);
console.log(p1); // undefined
console.log(p2); // undefined
我們會發現竟然是undefined,怎麼會,快找找原因….原因是他少了new這個關鍵字…
爲什麼會出現這樣的原因呢,我們正確的結果,或許一看你就會了解。
var p1 = Person("ys", 12);
var p2 = Person("ys", 12);
console.log(p1); // undefined
console.log(p2); // undefined
console.log(window.name); //ys
console.log(window.age); //12
原因就是沒了new這個關鍵字,對於js的new關鍵字,大家可以這樣理解:
new就是將函數內部的this的值,賦值給當前對象的this,如:this.name(實例對象) = this.name(構造函數)
當沒有new的時候,this就變爲了window,也就解釋了。
那麼問題又來了,有時候我們就是會忘記new,那這樣的構造函數就顯得不安全,這裏有一個安全的構造函數模式,可以幫到你
/*安全的構造函數模式*/
var Person = function(name, age){
if(this instanceof Person){
this.name = name;
this.age = age;
this.sayName = function(){
console.log(this.name);
};
}else{
return new Person(name, age);
}
}
var p1 = Person("ys", 12);
var p2 = Person("ys", 12);
console.log(p1); // { name: 'ys', age: 12, sayName: [Function] }
console.log(p2); // { name: 'ys', age: 12, sayName: [Function] }
console.log(window.name); // undefined
console.log(window.age); // undefined
3.原型對象模式
然後我們也覺得一個問題出現了,對於上面改良後的構造函數模式,所創建的全局函數sayName似乎成了Person構造函數的私人司機,只對於他一個人用,這樣也就失去了全局函數的價值,而且當存在諸多構造函數時候,諸多的“sayName”也是一個問題,這個時候,原型模式完美的解決了這個問題
//需要變動部分
function Person(name){
this.name = name;
}
//永久不變部分
Person.prototype.age = 12;
Person.prototype.sayName = function(){
console.log(this.name);
}
var p1 = new Person("ys");
var p2 = new Person("ab");
console.log(p1.sayName()); //ys
console.log(p1.age); //12
console.log(p2.sayName()); //ab
console.log(p2.age); //12
console.log(p1.sayName == p2.sayName); //true
當創建一個函數時候,該函數存在一個prototype屬性,該屬性是一個指針,指向一個對象,這個對象是一個方法和屬性的集合,存儲公共的屬性和方法,達到所有實例共享的目的。
有全局對象的特性,區別於全局,Person構造函數的私人全局,只對它(Person)一個人生效。
當存在於對象實例時候,他們共享prototype裏面的東西。