JavaScript建立物件

謙行發表於2013-08-28

JavaScript 有Date、Array、String等這樣的內建物件,功能強大使用簡單,人見人愛,但在處理一些複雜的邏輯的時候,內建物件就很無力了,往往需要開發者自定義物件。

物件是什麼

從JavaScript定義上講物件是無序屬性的集合,其屬性可以包含基本值、物件或函式。也就是說物件是一組沒有特定順序的屬性,每個屬性會對映到一個值上,是一組鍵值對,值可以是資料或物件。

最簡單的物件

JavaScript的一對花括號{}就可以定義一個物件,這樣的寫法實際上和呼叫Object的建構函式一樣

var obj={};
var obj2=new Object();

這樣構建出來的物件僅僅包含一個指向Object的prototype的指標,可以使用一些valueOf、hasQwnProperty等方法,沒有多大實際作用,自定義物件嘛總要有一些自定義的屬性、方法神馬的。

var obj={};
            obj.a=0;
            obj.fn=function(){
                alert(this);
            }
            
            var obj2={
                a:0,
                fn:function(){
                    alert(this);
                }
            }

可以在定義完物件後通過”.”為其新增屬性和方法,也可以使用字面量賦值方法在定義物件的時候為其新增屬性和方法,這樣建立的物件,其方法和屬性可以直接使用物件引用,類似於類的靜態變數和靜態函式,這樣建立物件有一個明顯缺陷——在定義大量物件的時候很費力,要一遍遍的寫幾乎是重複的程式碼。

抽象一下

既然是重複程式碼就可以抽象出來,用函式來做這些重複工作,在建立物件的時候呼叫一個專門建立物件的方法,對於不同的屬性值只需要傳入不同引數即可。

function createObj(a,fn){
                var obj={};
                obj.a=a;
                obj.fn=fn;
                return obj;
            }
            
            var obj=createObj(2,function(){
                alert(this.a);
            });

這樣在建立大量物件的時候,就可以通過呼叫此方法來做一些重複工作了,這種方式也不完美,因為在很多時候需要判斷物件的型別,上面程式碼建立出來的物件都是最原始的Object物件例項,只是擴充了一些屬性和方法。

有型一些

又是function登場的時候,JavaScript中function就是個物件,在建立物件的時候打可以拋開上面createObj方法,直接使用function作為物件,怎麼實現複用呢,這就在於function作為物件的特殊性了。

1. function可以接受引數,可以根據引數來建立相同型別不同值的物件

2. function作為建構函式(通過new操作符呼叫)的時候會返回一個物件,在貧下中農版jQuery中提到過一些建構函式的基本知識,簡單複製一下

建構函式的返回值分為兩種情況,當function沒有return語句或者return回一個基本型別(bool,int,string,undefined,null)的時候,返回new 建立的一個匿名物件,該物件即為函式例項;如果function體內return一個引用型別物件(Array,Function,Object等)時,該物件會覆蓋new建立的匿名物件作為返回值。

3. 那麼使用function怎麼解決型別識別問題呢,每個function例項物件都會有一個constructor屬性(也不是“有”,而是可以對應),這個屬性就可以指示其構造是誰,也可以使用instanceof 操作符來做判斷物件是否為XXX的例項。

不能光說不練,上程式碼

function Person(name){
                this.name=name;
                this.fn=function(){
                    alert(this.name);
                }
            }
            
            var person1=new Person('Byron');
            
            console.log(person1.constructor==Person);//true
            console.log(person1 instanceof Person); //true

這樣就完美了吧,也不是!雖然建構函式可以是物件有型,但物件的每個例項中的方法都要重複一遍!

function Person(name){
                this.name=name;
                this.fn=function(){
                    alert(this.name);
                }
            }
            
            var person1=new Person('Byron');
            var person2=new Person('Frank');
            
            console.log(person1.fn==person2.fn);//false

看看看,雖然兩個例項的fn一模一樣,但是卻不是一回事兒,這如果一個function物件有一千個方法,那麼它的每個例項都要包含這些方法的copy,很讓記憶體無語啊。

不玩兒虛的了

究竟有沒有一種近乎完美的構造物件的方式,及不用做重複工作,又有型,物件通用方法又不必重複?其實可以發現使用function已經距離要求和接近了,只差那麼一點兒——需要一個所有function物件的例項共享的容器,在這個容器記憶體發例項需要共享的屬性和方法,正好這個容器是現成的——prototype,不瞭解prototype的同學可以看看JavaScript prototype

function Person(name){
                this.name=name;
            }
            
            Person.prototype.share=[];
            
            Person.prototype.printName=function(){
                alert(this.name);
            }
            
            var person1=new Person('Byron');
            var person2=new Person('Frank');
            
            console.log(person1.printName==person2.printName);//true

這樣每個Person的例項都有自己的屬性name,又有所有例項共享的屬性share和方法printName,基本問題都解決了,對於一般的物件處理就可以始終這個有型又有愛的建立物件模式了。

相關文章