創建對象
一.工廠模式
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("Nicho",29,"farmer");
var person2 = createPerson("Mike",19,"farmer");
person1.sayName();
person2.sayName();
二.構造函數模式
function Person(name,age,work){
this.name = name;
this.age = age;
this.work = work;
this.sayName = function(){
alert(this.name);
};
}
var person1 = new Person("Nicho",29,"farmer");
var person2 = new Person("Mike",19,"farmer");
person1.sayName();
person2.sayName();
new Person("Nicho",29,"farmer")的執行步驟
1>創建一個新的對象
2>將構造函數的作用域賦給新對象
3>執行構造函數中的代碼
4>返回新對象
1.將構造函數當作函數
任何函數只要通過new操作符來調用,那它就可以作爲構造函數,而任何函數,如果不通過new操作符來調用,那它跟普通函數也不會有什麼兩樣。
//當構造函數使用
var person =new Person("Nich",26,"worker");
person.sayName();
//作爲普通函數調用
Person("Nich",26,"worker");
windown.sayName();
//在另一個對象的作用域調用
var o = new Object();
Person.call(o,"Nich",26,"worker");
o.sayName();
2.構造函數的問題
使用構造函數的主要問題是:每個方法都要在每個實例上重新創建一次,person1,person2都有sayName方法,但是不是同一個Function實例,
alert(person1.sayName == person2.sayName);//false
可以通過下面的方法來解決這個問題
fuction Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = sayName;
}
funciton sayName(){
alert(this.name);
}
這樣person1和person2對象就共享了在全局作用域中定義的同一個sayName()方法,但是這就導致了兩個新的問題,第一,在全局作用域定義的函數實際上只被某個特定的對象使用,這樣全局作用域名不副實,第二,如果對象需要很多方法,那麼就需要定義很多全局作用域的方法,於是我們的自定義引用類型就沒有了封裝性。
三,原型模式
每個函數都有一個prototype屬性,該屬性是一個對象,它的用途是包含可以由特定類型的所有實例共享的屬性和方法,使用原型的好處是可以讓所有對象實例共享它所包含的屬性和方法,不必在構造函數裏定義對象信息,可以將這些信息直接添加到原型對象中。
function Person(){
}
Person.prototype.name = "Nicho";
Person.prototype.age = 26;
Person.prototype.job = "farmer";
Person.prototype.sayName = function(){
alert(this.name);
}
var perons1 = new Person();
alert(person1.name);//"Nicho"
var perons2 = new Person();
alert(person2.name);//"Nicho"
alert(person1.sayName == person2.sayName);//true
1.原型
每當代碼讀取某個對象的屬性時,都會執行一次搜索,目標是具有給定名字的屬性,搜索首次從對象實例開始,如果在實例中找到了具有給定名字的屬性,則返回該屬性的值,如果沒有找到,則繼續搜索指針指向原型對象,在原型對象中查找具有給定名字的屬性,如果在原型對象中找到這個屬性就返回這個屬性的值。
原型最初只包含constructor屬性,而這個屬性也是共享的,因此可以通過對象實例訪問。
雖然可以通過對象實例訪問保存在原型中的值,但是不能通過實例去設置原型中的值。
2.原型與in操作
alert("name" in person1);//true;
in操作符會在通過對象能夠訪問到給定屬性時返回true,無論屬性存在於實例中還是在原型中。hasOwnProperty()方法僅僅在實例中存在屬性時返回true。
同時使用這兩個方法可以確定屬性是存在於實例中還是存在於原型中。
在使用for-in循環時,返回的是所有能夠通過對象訪問的可枚舉的屬性,其中既包括存在於實例中的屬性也包括存在於原型中的屬性
3.更簡單的原型語法
function Person(){
}
Person.prototyep ={
name:"Nicho",
age :29,
job:"worker",
sayName: function(){
alert(this.name);
}
};
注意:這種形式會導致constructor屬性不再指向Person了,沒創建一個函數,就會同時創建它的prototype對象,這個對象也會自動獲得constructor屬性,而這種語法,完全重寫了prototype對象,因此constructor屬性也變成了新的對象的constructor屬性,指向Object,
注:可以設置回來
function Person(){
}
Person.prototyep ={
constructor:Person,
name:"Nicho",
age :29,
job:"worker",
sayName: function(){
alert(this.name);
}
};
4.原型的動態性
由於在原型中查找值是一個搜索,因此對原型的任何修改都能夠立即從實例上反映出來,即使先創建了實例後修改原型也是如此。之所以這樣是因爲實例與原型之間的鬆散耦合關係,實例與原型之間連接的僅僅是一個指針,而非一個副本。
但是如果重寫整個原型對象那情況就不一樣了。調用構造函數時會爲實例添加一個指向最初原型的_proto_指針,而把原型修改爲另一個對象就等於切斷了構造函數與最初原型之間的聯繫。(實例中的指針僅僅指向原型,而不指向構造函數)
5.原生對象的原型
所有原生的引用類型都是採用原型模式來創建的,通過原生對象的原型,不僅可以取得所有默認方法的引用,而且可以定義新的方法,可以像修改自定義原型一樣修改原生對象的原型,因此可以隨時添加方法。
Strig.prototype.startsWith = function (test){
return this.indexOf(text) == 0;
}
var msg ="Hello world";
alert(msg.startsWith("Hello"));//true;
這裏就爲String添加了一個startsWith方法
6.原型模式的問題
首先,省略了構造函數初始化的環節
其次,最大的問題是由其共享的本性所導致的。這種共享對函數和基本類型可以,但是對於引用類型,問題就比較明顯。
function Person(){
}
Person.prototype ={
constructor : Person,
name:"Nicho",
age:29,
job:"worker",
friends:["Mike","Jam"],
sayName : function(){
alert(this.name);
}
};
var person1 = new Person();
var person2 = new Person();
person1.friends.push("Van");
alert(person1.friends);//Mike Jam Van
alert(person2.friends);//Mike Jam Van
四.組合使用構造函數模式和原型模式
構造函數:定義實例屬性
原型模式:定義方法和共享的屬性
function Person(name,age ,job){
this.name = name;
this.age = age;
this.job = job;
this.friends =["Shelby","Court"];
}
Person.prototype ={
constructor:Person,
sayName: function(){
alert(this.name);
}
}
五.動態原型模式
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);
};
}
}
六.穩妥構造函數模式
穩妥對象指的是沒有公共屬性,而且其方法也不引用this的對象,穩妥對象最適合在一些安全環境(禁止使用new和this)或者在防止數據被其他應用程序改動時使用
function Person(name,age,job){
var o = new Object();
o.sayName = function(){
alert(name);
};
return o;
}