2017年12月4日 星期一

[ JavaScript Gossip ] JavaScript 核心 : 這些東西不簡單 (物件)

轉載自 這裡 
前言 : 
在 JavaScript 中,物件是 Object 的實例. 你可以如下建立一個新的物件 : 
  1. var obj = new Object();  
實際上,現在已經很少人這麼撰寫了,使用物件實字(Object literal)語法就可以建立一個物件 : 
兩者的作用相同,物件實字寫法顯然較有效率。在 JavaScript 中,你可以隨時為物件新增特性(Properties),也可以隨時用 delete 運算子來刪除特性. 例如 : 
> var obj = {}
undefined
> obj.x = 10
10
> obj.x
10
> delete obj.x
true
> obj.x
undefined

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

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

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

> 'x' in obj
true
> 'z' in obj
false

由以上也可以得知,每個特性名稱其實是字串型態,這也說明了,如果想用 in 測試某特性時,特性名稱必須以字串指定. 事實上,點運算子(.)只是存取物件特性的一種方式。你也可以使用 [] 運算子來存取特性. 例如 : 
> var obj = {}
undefined
> obj['x'] = 10
10
> obj.x
10
> obj['x']
10
> obj['y']
undefined

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

使用 [] 運算子的場合之一,就是當你的特性會包括空白、. 字元等時. 例如 : 
> var obj = { 'catepillar.onlyfun':'Openhome' }
undefined
> obj.catepillar.onlyfun
TypeError: Cannot read property 'onlyfun' of undefined
at repl:1:15
at sigintHandlersWrap (vm.js:22:35)
at sigintHandlersWrap (vm.js:73:12)
at ContextifyScript.Script.runInThisContext (vm.js:21:12)
at REPLServer.defaultEval (repl.js:340:29)
at bound (domain.js:280:14)
at REPLServer.runBound [as eval] (domain.js:293:12)
at REPLServer. (repl.js:538:10)
at emitOne (events.js:101:20)
at REPLServer.emit (events.js:188:7)

> obj['catepillar.onlyfun']
'Openhome'
> delete obj['catepillar.onlyfun']
true
> 'catepillar.onlyfun' in obj
false

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

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

在上例中,選項物件的 x、y、z 特性預設值分別是 1、2、3,如果 obj 上有提供對應的特性,則以 obj 提供的為主,否則就以選項物件的為主,這也經常用在函式上有太多參數及預設值要提供的場合,之後說明函式時還會看到(不清楚 || 運算為何會有這種結果的話,請看 運算子 中的說明). JavaScript 是個弱型別語言,在需要將物件轉為數值的場合,會呼叫 valueOf() 方法. 例如 : 
> var obj = { valueOf:function(){return 100;} }
undefined
> 100 + obj
200
> obj + 200
300
> obj > 100
false

在需要將物件轉換為字串的場合,則會呼叫 toString() 方法. 例如 : 
> var john = { name:'John K Lee', url:'puremonkey', toString:function(){ return '[name:' + this.name + ', url:' + this.url + ']'} }
undefined
> john
{ name: 'John K Lee',
url: 'puremonkey',
toString: [Function: toString] }

> 'My info: ' + john
'My info: [name:John K Lee, url:puremonkey]'

在 JavaScript 中,== 或 === 用在物件比較時,是比較參考的對象是否為同一物件,而不是物件實際內含值 (前者會嘗試將 == 兩邊轉換為同一型態,再比較是否相等,但後者只要 === 兩邊型態不一,就會判斷為false. 更詳細說明請參考 "Equality comparisons and sameness"),如果你要比較兩個物件實際上是否為同一物件,必須自行定義專屬方法,這個方法名稱並沒有規範. 例如,也許定義個 equals() 方法 : 
> var man1 = { name:'John', url:'puremonkey', equals:function(other){return (this.name == other.name) && (this.url == other.url);} }
undefined
> var man2 = { name:'John', url:'puremonkey', equals:function(other){return (this.name == other.name) && (this.url == other.url);} }
undefined
> man1 == man2 # man1 與 man2 是否為同一物件?
false
> man1 === man2
false
> man1.equals(man2)
true

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

Supplement 
MDN - Working with objects 
W3CSchools - JavaScript Objects

沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...