我們可以利用JavaScript的語法特征,以類的思想來創建對象。
方法一:原始方法
代碼如下:
<script>
var obj = new Object();
obj.name = "Kitty";//為對象增加屬性
obj.age = 21;
obj.showName = function () {//為對象添加方法
console.log(this.name);
};
obj.showAge = function(){
console.log(this.age);
};
obj.showName();
obj.showAge();
</script>
這種方法通過new關鍵字生成一個對象,然后根據JavaScript是動態語言的特性來添加屬性和方法,構造一個對象。其中的this表示調用該方法的對象。
這種方法的問題在於:如果我們需要多次創建對象,那么就需要重復代碼多次,不利於代碼的復用。
方法二:工廠方法
代碼如下:
<script>
function createObj(){
var obj = new Object();//創建對象
obj.name = "Kitty";
obj.age = "21";
obj.showName = function () {
console.log(this.name);
};
obj.showAge = function () {
console.log(this.age);
};
return obj;
}
var obj1 = createObj();
var obj2 = createObj();
obj1.showName();
obj1.showAge();
obj2.showName();
obj2.showAge();
</script>
這種方法雖然也實現了創建對象,但是同樣地,如果需要多次創建對象,而且屬性內容不一樣的話,也是需要重復代碼多遍。需要重新考慮代碼重用率,接下來修改代碼,使其可以提高代碼重復率,而且可以改變工廠方法,傳入參數賦值。
改進代碼如下:
<script>
function createObj(name,age){
var obj = new Object();
obj.name = name;
obj.age = age;
obj.showName = function () {
console.log(this.name);
};
obj.showAge = function(){
console.log(this.age);
};
return obj;
}
var obj1 = new createObj("Kitty","21");
var obj2 = new createObj("Luo","22");
obj1.showName();//Kitty
obj1.showAge();//21
obj2.showName();//luo
obj2.showAge();//22
</script>
這種方法雖然可以提高代碼的重用率,但和面向對象中類的概念相比,有一個很大的缺陷。面向對象強調對象的屬性私有,但對象的方法是共享。而上面的工廠方法在創建對象時,要為每個對象創建各自私有的方法。同時,由於為每個對象都創建邏輯相同的方法,所以很浪費內存。
改進代碼如下:
<script>
function createObj(name,age){
var obj = new Object();
obj.name = name;
obj.age = age;
obj.showName = showName;
obj.showAge = showAge;
return obj;
}
function showName(){
console.log(this.name);
}
function showAge(){
console.log(this.age);
}
var obj1 = new createObj("Kitty","21");
var obj2 = new createObj("Luo","22");
obj1.showName();//Kitty
obj1.showAge();//21
obj2.showName();//luo
obj2.showAge();//22
</script>
上面通過定義幾個函數對象,解決了不同對象持有函數對象的私有問題。現在所有對象的方法都持有上面兩個函數的引用。但是這么一來,對象的函數和對象又相互獨立,這和面向對象中特定方法屬於特定類的思想不符合。
方法三:構造函數方法
代碼如下:
<script>
function Person(name,age){
this.name = name;
this.age = age;
this.showName = function () {
console.log(this.name);
};
this.showAge = function () {
console.log(this.age);
};
}
var obj1 = new Person("Kitty","21");
var obj2 = new Person("Luo","22");
obj1.showName();//Kitty
obj1.showAge();//21
obj2.showName();//luo
obj2.showAge();//22
</script>
構造函數的方法和工廠方法一樣,會為每個對象創建獨享的函數對象。當然也可以將這些函數對象定義在構造函數外面,這樣有了對象和方法相互獨立的問題。
使用構造函數存在的最大問題就是每個實例都會將所有的屬性創建一次。這個對於數值屬性來說可以接受,但是如果函數方法每個實例都要創建一遍,則不合理。
要創建Person()的新實例,必須使用new操作符。以這種方式調用構造函數實際上會經歷以下四個步驟:
創建一個新對象;
將構造函數的作用域賦給新對象(因此this就指向了這個新對象);
執行構造函數中的代碼(為這個新對象添加屬性);
返回新對象。
方法四:原型方法
代碼如下:
<script>
function Person(){} //定義一個空構造函數,且不能傳遞參數
//將所有的屬性的方法都賦予prototype
Person.prototype.name = "Kitty";
Person.prototype.age = 21;
Person.prototype.showName = function (){
console.log(this.name);
};
Person.prototype.showAge = function (){
console.log(this.age);
};
var obj1 = new Person("Kitty","21");
var obj2 = new Person("Luo","22");
obj1.showName();//Kitty
obj1.showAge();//21
obj2.showName();//luo
obj2.showAge();//22
</script>
當生成Person對象時,prototype的屬性都賦給了新的對象。那么屬性和方法是共享的。首先,該方法的問題是構造函數不能傳遞參數,每個新生成的對象都有默認值。其次,方法共享沒有任何問題,但是,當屬性是可改變狀態的對象時,屬性共享就有問題。
修改代碼如下:
<script>
function Person(){} //定義一個空構造函數,且不能傳遞參數
//將所有的屬性的方法都賦予prototype
Person.prototype.age = 21;
Person.prototype.array = new Array("Kitty","luo");
Person.prototype.showAge = function (){
console.log(this.age);
};
Person.prototype.showArray = function (){
console.log(this.array);
};
var obj1 = new Person();
var obj2 = new Person();
obj1.array.push("Wendy");//向obj1的array屬性添加一個元素
obj1.showArray();//Kitty,luo,Wendy
obj2.showArray();//Kitty,luo,Wendy
</script>
上面的代碼通過obj1的屬性array添加元素時,obj2的array屬性的元素也跟着受到影響,原因就在於obj1和obj2對象的array屬性引用的是同一個Array對象,那么改變這個Array對象,另一引用該Array對象的屬性自然也會受到影響,混合的構造函數/原型方式使用構造函數定義對象的屬性,使用原型方法定義對象的方法,這樣就可以做到屬性私有,而方法共享。
方法五:混合的構造函數/原型方式
代碼如下:
<script>
function Person(name,age){
this.name = name;
this.age = age;
this.array = new Array("Kitty","luo");
}
Person.prototype.showName = function (){
console.log(this.name);
};
Person.prototype.showArray = function (){
console.log(this.array);
};
var obj1 = new Person("Kitty",21);
var obj2 = new Person("luo",22);
obj1.array.push("Wendy");//向obj1的array屬性添加一個元素
obj1.showArray();//Kitty,luo,Wendy
obj1.showName();//Kitty
obj2.showArray();//Kitty,luo
obj2.showName();//luo
</script>
屬性私有后,改變各自的屬性不會影響別的對象。同時,方法也是由各個對象共享的。在語義上,這符合了面向對象編程的要求。
方法六:動態原型方法
代碼如下:
<script>
function Person(name,age){
this.name = name;
this.age = age;
this.array = new Array("Kitty","luo");
//如果Person對象中_initialized 為undefined,表明還沒有為Person的原型添加方法
if(typeof Person._initialized == "undefined"){
Person.prototype.showName = function () {
console.log(this.name);
};
Person.prototype.showArray = function () {
console.log(this.array);
};
Person._initialized = true;
}
}
var obj1 = new Person("Kitty",21);
var obj2 = new Person("luo",22);
obj1.array.push("Wendy");//向obj1的array屬性添加一個元素
obj1.showArray();//Kitty,luo,Wendy
obj1.showName();//Kitty
obj2.showArray();//Kitty,luo
obj2.showName();//luo
</script>
這種方法和構造函數/原型方式大同小異。只是將方法的添加放到了構造函數之中,同時在構造函數Person上添加了一個屬性用來保證if語句只能成功執行一次,在實際應用中,采用最廣泛的構造函數/原型方法。動態原型方法也很流行,它在功能上和構造函數/原型方法是等價的。不要單獨使用構造函數和原型方法。
原文鏈接:https://blog.csdn.net/u010297791/article/details/55670841