javascript中創建對象的幾種方式

javascript中提供瞭通過Object構造函數或對象字面量方式來創建單個的對象,當我們想要創建很多對象的時候,簡單的通過這兩種方法就會產生大量的重復。在此,我總結瞭幾種創建對象的模式。本文是在我閱讀《javascript高級程序設計》後總結而來。

 

1.工廠模式

這種模式通過用函數來減少代碼重復,利用函數的參數作為接口,與對象的屬性與方法對接。

 

復制代碼

function createfactory(name,age){

    var obj = new Object();

    obj.name = name;

    obj.age = age;

    return obj;

}

var test1 = createfactory('aaa',18);

var test2 = createfactory('bbb',50);

復制代碼

這樣就完成瞭簡單的代碼復用,實現瞭代碼重復,但是無法確定所創建對象的類型。

 

構造函數模式

我們都知道Object,Array等原生的構造函數可以用來創建對象。構造函數模式和此類似,通過自定義創建構造函數,來創建新類型的對象。

 

復制代碼

function Createfunction(name,age,){

    this.name = name;

    this. age = gae;

    this.sayname = function(){

        alert(this.name);

    }

}

var test1 = new Createfunction('aaa',20);

var test2 = new Createfunction('bbb',50);

復制代碼

按照慣例,構造函數應以一個大寫字母開頭。這種模式可以將新對象的類型確定下來。然後這種模式依舊存在問題,test1和test2兩個實例中都有 sayname方法,在javascript中函數就是對象,因此在創建test1和test2的同時也實例化瞭兩次函數對象,相當於這樣:

 

復制代碼

###原型模式

每個函數都有一個prototype屬性,指向它的原型對象。原型對象可以讓所有對象實例共享其中的屬性和方法。看下面的例子。

“`javascript

function Cf(){}

Cf.prototype.name = "aaa";

Cf.prototype.age = 29;

Cf.prototype.sayname = function(){

    alert(this.name);

    }

var test1 = new Createfunction();

var test2 = new Createfunction();

復制代碼

上面這種方法通過將屬性和方法添加到瞭構造函數的原型對象中,這樣新對象的所有實例會共享這些屬性和方法。

為瞭進一步減少代碼量,有人提出瞭重寫原型對象的方法。看下面的例子。

 

復制代碼

function Cf(){}

Cf.prototype = {

    name = "aaa";

    age = 29;

    sayname = function(){

        alert(this.name);

    }

}

var test1 = new Createfunction();

var test2 = new Createfunction();

復制代碼

這種方法通過重寫原型對象進一步減少代碼重復,然而這樣的寫法帶來瞭新的問題。

在簡單的通過原型模式創建對象時,原型對象的動態變化會實時的反應 在實例中,因為實例中的[[Prototype]]屬性是指向原型對象的,這樣對於調用屬性和方法的向上搜索過程,會搜尋到原型對象中的屬性和方法。而當 先實例化一個對象後,再重寫原型對象,實例中的[[Prototype]]不再指向新的原型對象,因而導致在調用的過程中無法向上搜索到新的原型對象,所 以在使用重寫原型對象方法的時候,一定要先重寫對象,再創建實例。

原型對象模式依舊存在缺點,雖然它省略瞭為函數傳參這一環節,但是實例默認情況下都取得相同的屬性值。此外對於包含引用類型的屬性來說,當對實例屬性修改會導致原型對象中屬性的同步變化。這樣,這種變化也就實時的反應在瞭所有的實例中。顯然這不是我們想要的結果。

聯系前面說的構造函數模式,我們可以通過組合使用構造函數模式和原型模式來解決這一問題。

 

復制代碼

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);

            }

        };

        

        var person1 = new Person("Nicholas", 29, "Software Engineer");

        var person2 = new Person("Greg", 27, "Doctor");

復制代碼

在構造函數中定義實例屬性,在原型模式中定義方法和共享的屬性。這樣,每個實例都有自己的實例屬性的副本,同時也有共享的屬性和方法,節省瞭內存,也可以通過傳參來定義實例屬性。

 

動態原型模式

動態原型模式其實相當於原型模式的一個變種,將所有的信息都封裝在構造函數中,僅在必要的情況下初始化原型對象。

 

復制代碼

function Person(name, age, job){

        

            //properties

            this.name = name;

            this.age = age;

            this.job = job;

            

            //methods

            if (typeof this.sayName != "function"){

            

                Person.prototype.sayName = function(){

                    alert(this.name);

                };

                

            }

        }

 

        var friend = new Person("Nicholas", 29, "Software Engineer");

        friend.sayName();

復制代碼

在這個構造函數中通過判斷屬性是否存在來決定是否對原型對象初始化。這樣隻有在第一次實例化對象時才會對原型對象初始化,可以說是十分的完美瞭。

 

寄生構造函數模式

當我們想為一個已經存在的構造函數創建一個具有額外方法的構造函數,由於不能重寫存在的構造函數,這時就可以使用這種模式瞭。看例子。

 

復制代碼

       function SpecialArray(){       

 

            //create the array

            var values = new Array();

            

            //add the values

            values.push.apply(values, arguments);

            

            //assign the method

            values.toPipedString = function(){

                return this.join("|");

            };

            

            //return it

            return values;        

        }

        

        var colors = new SpecialArray("red", "blue", "green");

復制代碼

這個例子中,創建瞭一個具有額外方法的數組,具有額外的特殊方法,在不修改數組構造函數的前提下,創建瞭一個新的構造函數。不過寄生構造函數模式返回的對象與構造函數的原型對象沒有關系。

發佈留言