前言 :
通常很少直接確認物件的型態,因為 JavaScript 是動態語言,對於物件的操作,僅要求是否具備所需特性,而不在意所謂的類型,物件的特性偵測絕大多數情況下就足夠了. 例如 :
- if(obj.someProperty) {
- // 特性存在時作某些事
- }
檢驗物件 :
如果真得確認物件的型態,有許多方式,但基本上要不就所提供的資訊有限,要不就不可信任. 例如 typeof 運算子,傳回值是字串,對於基本資料型態,數值會傳回 'number'、字串會傳回 'string'、布林會傳回 'boolean'、對於 Function實例 會傳回'function'、對於 undefined 會傳回'undefined'、對於其它物件一律傳回 'object',包括 null 也是傳回'object',所以,只要是非函式實例的物件,基本上無從辨別真正型態.
你可以從物件的 constructor 特性來確認物件的建構式為何,因為如 函式 prototype 特性 中有談過,每個函式的實例, 其 prototype 會有個 constructor 特性,參考至函式本身,這是確認物件型態的方式之一,只不過,constructor 是個可修改的特性,雖然沒什麼人會去修改 constructor 特性,但是如果是在原型鏈的情況下 :
上面這個例子,是利用原型鏈查找機制,達到所謂繼承的效果. 由於 SportsCar.prototype 設定為 Car 的實例,所以在查找 wheels 特性 時,sportsCar 所參考物件本身沒有,就到原型物件上找,也就是 SportsCar.prototype 所參考的物件上找,這個物件是 Car 的實 例,本身也沒有 wheels 特性,所以就到 Car 實例的原型尋找,也就是 Car.prototype 所參考的物件,此時就找到了. 然而,在查找 constructor 時,依同樣的機制,所找到的其實是 Car.prototype.constructor 特性,上例中應該再加一行才會比較正確 :
- SportsCar.prototype.constructor = SportsCar;
關於 new 建立物件,函式 prototype 特性中談過,使用 new 關鍵字時,JavaScript 會先建立一個空物件,接著設定物件的原型為函式的 prototype 特性所參考的物件,然後呼叫建構式並將所建立的空物件設為 this. 注意,物件的原型是在建立物件之後就確立下來的,原型鏈查找特性時,是根據物件上的原型,而不是函式上的 prototype. 例如,你可以看看以下為何無法取得特性 :
這是初學者常犯的錯誤. 注意!物件的原型是在建立物件之後就確立下來的,所以在這行 :
- var sportsCar = new SportsCar();
再來用實際的程式示範會更清楚,這次用非標準的 __proto__ 來驗證 :
從上例中可以看到,建立物件時即設定原型,而物件上的原型最後跟 SportsCar.prototype 根本就不是同一個物件了。所以 new 建立物件時,例如 :
- var some = new Some();
- var some = {};
- some.__proto__ = Some.prototype;
- Some.call(some);
簡單地說,instanceof 是根據原型鏈來查找. 明白這個機制,以下用非標準 __proto__ 特性來欺騙 instanceof :
上例中建立的絕不是 Array 的實例,不過最後欺騙了 instanceof 使之傳回 true.
或許檢驗物件的原型也是個方式,但 __proto__ 是個非標準特性,如果你想要檢驗物件原型,可以使用 isPrototypeOf() 方法。例如 函式 prototype 特性 中就這麼作過 :
其實 isPrototypeOf() 的作用與 instanceof 類似,都是透過原型鏈來確認. 在取得一個物件的特性時,會尋找原型鏈,如果想確認特性是物件本身所擁有,或是其原型上的特性,則可透過物件都具有的 hasOwnProperty() 方法(當然,這是 Object.prototype 上的一個特性).例如 :
如果特性不是物件本身擁有,而是原型鏈上可取得,則會傳回 false,尋找不到特性也是傳回 false.
物件本身所新建的特性是可以用for in列舉的,有些內建特性無法列舉,想要知道特性是不是可用 for in 列舉,則可以使用 propertyIsEnumerable() 方法. 例如 :
當然,特性不存在時就無法列舉,所以會傳回 false.
另外,ECMAScript 規格要求 Object 預設的 toString() 要傳回以下的字串 :
JavaScript 的內建型態基本上都會遵守這樣的規定,例如 Object實例 會傳回 [object Object]、陣列會傳回[object Array]、函式會傳回[object Function]等,這也可作為判斷型態的依據,基於對標準的支持,現在一些程式庫多使用這個來作判斷.
注意 :
Supplement
* NodeJS Get Started
沒有留言:
張貼留言