標籤:obj rop person property 細節 調用 tor rabl 字母
1. 原廠模式
用函數來封裝以特定介面建立對象的細節。但是這種方法無法解決確定物件類型的問題。
function createPerson(name,age,job){ var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function() { alert(this.name);} return o;}var person1 = createPerson("Nicholas",29,"SoftWare Engineer");console.log(person1.name); //Nicholasvar person2 = createPerson("Sofia",27,"Docter");person2.sayName(); //Sofia
2.建構函式模式
可通過建立自訂的建構函式,從而定義自訂物件類型的屬性和方法。建構函式始終都要應該以一個大寫字母開頭;要建立一個建構函式的新執行個體,必須使用new操作符。
function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ alert(this.name); };}var person1 = new Person("Nicholas",25,"Chemical Engineer");var person2 = new Person("Sofia",28,"Executive Manager");console.log(person1 instanceof Object); //trueconsole.log(person1 instanceof Person); //trueconsole.log(person1.sayName==person2.sayName); //false
使用建構函式模式可以確定對象的類型,但是上面像這樣將對象方法寫入建構函式內部會使得每個方法都要在每個執行個體上重新建立一遍。以這種方式建立的函數,會導致不同的範圍鏈和標識符來解析,因此不同執行個體上的同名函數是不相等的。
然而這樣是完全沒有必要的,建立任務相同的不同的Function執行個體。可將函數定義在建構函式外部,來解決這個問題。
function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.sayName = sayname; }function sayname(){ alert(this.name)}var person1 = new Person("Nicholas",25,"Chemical Engineer");var person2 = new Person("Sofia",28,"Executive Manager");console.log(person1.sayName()); //Nicholasconsole.log(person2.sayName()); //Sofiaconsole.log(person1 instanceof Object); //trueconsole.log(person1 instanceof Person); //true
但是如果對象需要定義很多方法,就需要定義很多全域函數,那麼這個自訂的參考型別就毫無封裝性可言了。
3. 原型模式
每個函數都有一個prototype屬性,這個屬性是一個指標,指向一個對象,也就是原型對象,這個對象的用途是包含可以由特定類型的所有執行個體共用的屬性和方法。這樣可以通過將屬性和方法直接添加到原型對象中來讓所有的對象執行個體來共用。
function Person(){}Person.prototype.name = "Nicholas";Person.prototype.age = 29;Person.prototype.job = "Chemical Engieer";Person.prototype.sayName = function(){ alert(this.name); };var person1 = new Person();person1.sayName(); //Nicholasvar person2 = new Person();console.log(person2.age); //29console.log(Person.prototype.isPrototypeOf(person1)); // trueconsole.log(Object.getPrototypeOf(person1)==Person.prototype); //trueperson1.name = "Lisa"; console.log(person1.name); Lisaconsole.log(person1.hasOwnProperty("name")); //true
在預設情況下,所有原型對象都會自動擷取一個constructor(建構函式)屬性,這個屬性是一個指向prototype屬性 所在函數的指標。建立了自訂的建構函式之後,其原型對象預設只會取得constructor屬性。當調用建構函式建立一個新執行個體後,該執行個體的內部包含一個指標(內部屬性),指向建構函式的原型對象,在ES5中叫[[Prototype]]。雖然在指令碼中沒有標準的方式訪問[[Prototype]],但FireFox、Safari和Chrome在每個對象上都支援一個屬性_proto_。
但是當重寫整個原型對象時,即將Person.prototype設定為一個新對象時(如下),constructor屬性也變成了新對象的constructor屬性(指向Object建構函式),不再指向Person函數。
Person.prototype={ name:"Nicholas", age: 29, job: "Software Engineer", sayName: function(){ alert(this.name);}}
如果constructor屬性很重要,可以在新原型對象上加上constructor:Person, 但是這樣constructor屬性的[[Enumerable]]特性被設定為true。預設情況下是不可枚舉的,false。
可以通過isPrototypeOf()方法確定某對象執行個體是否屬於某對象原型。如果執行個體的[[Prototype]]指向調用isPrototypeOf()方法的對象,那麼這個方法返回true。
ES5中,增添了一個新方法,Object.getPrototypeOf(),這個方法返回[[Prototype]]的值。
使用hasOwnProperty()方法可以檢測一個屬性是存在於執行個體中還是存在於原型中。這個方法只有在給定屬性存在於對象執行個體中時,才會返回true。
4.建構函式模式和原型模式組合使用
這種建構函式和原型混合的模式,目前子啊ECMAScript中使用最廣泛的一種建立自訂類型的方法。每個執行個體都會有自己的一份執行個體屬性的副本,同時也共用著方法的引用,極大程度低節省了記憶體。
function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.friends = ["Shelby","Court"]; }
Person.prototype={
construtor: Person,
sayName: function{
alert(this.name);
}
}
var person1=new Person("Nicholas",29,"Software Engineer");
var person2=new Person("Greg",27,"Chemical Engineer");
person1.friends.push("Sofia");
console.log(person1.friends); //["Shelby","Court","Sofia"]
console.log(person2.friends); //["Shelby","Court"]
5.動態原型模式
同時使用建構函式與原型,僅在必要的情況下初始化原型。
function Person(name,age,job){ //屬性 this.name = name; this.age = age; this.job = job; //方法 if(typeof this.sayName != "function"){ Person.prototype.sayName=function(){ alert(this.name);}}
6.穩妥建構函式模式
穩妥對象,指的是沒有公用屬性,而且方法也不引用this的對象。穩妥對象最適合在一些安全的環境(環境中會禁止使用this和new)中,或者在防止資料被其他應用程式改動時使用。
function createPerson(name,age,job){ var o = new Object(); //定義私人變數和函數 //添加方法 o.sayName = function() { alert(name);}; //返回對象 return o;}var friend=Person("Sofia",25,"Chemical Engineer");friend.sayName(); //"Sofia"
在上述的例子中,除了調用sayName()方法,沒有別的方式可以訪問到傳入到建構函式中的未經處理資料成員。
JavaScript中建立對象的方法