物件



在JavaScript中,物件是Object的實例。你可以如下建立一個新的物件:
var obj = new Object();

實際上,現在已經很少人這麼撰寫了,使用物件實字(Object literal)語法就可以建立一個物件:
var obj = {};

兩者的作用相同,物件實字寫法顯然較有效率。在JavaScript中,你可以隨時為物件新增特性(Properties),也可以隨時用delete運算子來刪除特性。例如:
js> var obj = {};
js> obj.x = 10;
10
js> delete obj.x;
true
js>


若刪除成功,delete會傳回true,並非所有特性都可被delete刪除,有些內建特性可能無法被刪除(例如在瀏覽器中的一些特性)。附帶一提的是,delete作用在非物件特性或變數時,會傳回true。例如delete 1;就會傳回true。

如果事先知道物件的特性,可以使用物件實字一併建立。例如:
js> var obj = {
  >     x : 10,
  >     y : 20
  > };
js> obj.x;
10
js> obj.y;
20
js>


想要知道物件上有哪些自定義特性,可以使用for in語法,逐一取出物件的特性名稱。例如:
js> for(var prop in obj) {
  >     print(prop);
  >     print(typeof prop);
  > }
x
string
y
string
js> 'x' in obj;
true
js>


由以上也可以得知,每個特性名稱其實是字串型態,這也說明了,如果想用in測試某特性時,特性名稱必須以字串指定。

事實上,點運算子(.)只是存取物件特性的一種方式。你也可以使用[]運算子來存取特性。例如:
js> var obj = {};
js> obj['x'] = 10;
10
js> obj.x;
10
js> obj['x'];
10
js>


JavaScript的物件本質上,其實是個特性與值的群集(Collection),要比喻的話,就像是Java中的Map物件。如果你要使用for in取得物件上的特性與值,則可以如下:
js> var obj = {
  >     x : 10,
  >     y : 20
  > };
js> for(var prop in obj) {
  >     print(prop + ': ' + obj[prop])
  > }
x: 10
y: 20
js>


使用[]運算子的場合之一,就是當你的特性會包括空白、. 字元等時。例如:
js> var obj = {
  >     'caterpillar.onlyfun' : 'Openhome'
  > };
js> obj.caterpillar.onlyfun;
js: "<stdin>", line 136: uncaught JavaScript runtime exception: TypeError: Cannot read property "onlyfun" from undefined
        at <stdin>:136

js> obj['caterpillar.onlyfun'];
Openhome
js> delete obj['caterpillar.onlyfun'];
true
js> 'caterpillar.onlyfun' in obj;
false
js>


除了使用in測試物件上是否存在特性之外,由於物件上不存在某個特性時,你試圖存取時會傳回undefined,而undefined若在判斷是否成立時會被當作false,所以就有了特性偵測的作法:
js> var obj = {};
js> if(obj.x) {
  >     print('x exists.' );
  > }
js> obj.x = 10;
10
js> if(obj.x) {
  >     print('x exists.' );
  > }
x exists.
js>


特性偵測也可以與||一同結合,用在合併物件特性。例如:
js> var obj = {
  >     x : 10,
  >     y : 20
  > };
js> var option = {
  >     x : obj.x || 1,
  >     y : obj.y || 2,
  >     z : obj.z || 3
  > };
js> option.x;
10
js> option.y;
20
js> option.z;
3
js>


在上例中,選項物件的x、y、z特性預設值分別是1、2、3,如果obj上有提供對應的特性,則以obj提供的為主,否則就以選項物件的為主,這也經常用在函式上有太多參數及預設值要提供的場合,之後說明函式時還會看到(不清楚||運算為何會有這種結果的話,請看 運算子 中的說明)。

JavaScript是個弱型別語言,在需要將物件轉為數值的場合,會呼叫valueOf()方法。例如:
js> var obj = {
  >     valueOf : function() {
  >         return 100;
  >     }
  > };
js> 100 + obj;
200
js> obj + 200;
300
js> obj > 100;
false
js> obj >= 100;
true
js>


在需要將物件轉換為字串的場合,則會呼叫toString()方法。例如:
js> var caterpillar = {
  >     name : 'Justin Lin',
  >     url  : 'openhome.cc',
  >     toString : function() {
  >         return '[name: ' + this.name + ', url: ' + this.url + ']';
  >     }
  > };
js> caterpillar;
[name: Justin Lin, url: openhome.cc]
js> 'My info: ' + caterpillar;
My info: [name: Justin Lin, url: openhome.cc]
js>


在上例中,this代表caterpillar所參考的物件,之後還會詳細說明this是什麼。

在JavaScript中,==或===用在物件比較時,是比較參考的對象是否為同一物件,而不是物件實際內含值,如果你要比較兩個物件實際上是否為同一物件,必須自行定義專屬方法,這個方法名稱並沒有規範。例如,也許定義個equals()方法:
js> var man1 = {
  >     name : 'Justin Lin',
  >     url  : 'openhome.cc',
  >     equals : function(other) {
  >         return (this.name == other.name) &&  (this.url == other.url);
  >     }
  > };
js> var man2 = {
  >     name : 'Justin Lin',
  >     url  : 'openhome.cc',
  >     equals : function(other) {
  >         return (this.name == other.name) &&  (this.url == other.url);
  >     }
  > };
js> man1 == man2;
false
js> man1 === man2;
false
js> man1.equals(man2);
true
js>


在上例中,equals所參考的函式其實內容重複了。如果你懂在JavaScript中函式是物件的觀念,則可以修改如下:
js> function equals(other) {
  >     return (this.name == other.name) &&  (this.url == other.url);
  > }
js> var man1 = {
  >     name : 'Justin Lin',
  >     url  : 'openhome.cc',
  >     equals : equals
  > };
js> var man2 = {
  >     name : 'Justin Lin',
  >     url  : 'openhome.cc',
  >     equals : equals
  > };
js> var man3 = {
  >     name : 'caterpillar',
  >     url  : 'caterpillar.onlyfun.net',
  >     equals : equals
  > };
js> man1.equals(man2);
true
js> man1.equals(man3);
false
js>


關於函式之後還會詳加說明。