JavaScript 語言核心(6)鍵值聚合體的物件
JavaScript 語言核心(5)操弄數值的運算子 << 前情 在 JavaScript 中,物件是 var obj = new Object(); 實際上,現在已經很少人這麼撰寫了,使用物件實字(Object literal)語法就可以建立一個物件: var obj = {}; 兩者的作用相同,物件實字寫法顯然較有效率。在 JavaScript 中,每個物件都可以是獨一無二,不一定是由其建構式來規範,這能力稱為物件個性化(Object individuation),你可以隨時為物件新增特性(Properties),也可以隨時用 > var obj = {}; undefined > obj.x = 10; 10 > obj.x; 10 > delete obj.x; true > obj.x; undefined > 若刪除成功, > var arr = []; undefined > arr.length; 0 > delete arr.length; false > 附帶一提的是, 如果事先知道物件的特性,可以使用物件實字一併建立。例如: > var obj = { ... x : 10, ... y: 20 ... }; undefined > obj.x; 10 > obj.y; 20 > 想要知道物件上有哪些自定義特性,可以使用 > for(var prop in obj) { ... console.log(prop); ... console.log(typeof prop); ... } x string y string undefined > 'x' in obj; true > 由以上也可以得知,每個特性名稱其實是字串型態,這也說明了,如果想用 事實上,點運算子( > var obj = {}; undefined > obj['x'] = 10; 10 > obj.x; 10 > obj['x']; 10 > JavaScript 的物件本質上,其實是個特性與值的群集(Collection),要比喻的話,有點像是 Java 中的 > var obj = { ... x : 10, ... y : 20 ... }; undefined > for(var prop in obj) { ... console.log(prop + ': ', obj[prop]); ... } x: 10 y: 20 undefined > 使用 > var obj = { ... 'openhome.cc': 'OpenHome', ... }; undefined > obj.openhome.cc; TypeError: Cannot read property 'cc' of undefined at repl:1:13 at REPLServer.self.eval (repl.js:110:21) at repl.js:249:20 at REPLServer.self.eval (repl.js:122:7) at Interface.<anonymous> (repl.js:239:12) at Interface.EventEmitter.emit (events.js:95:17) at Interface._onLine (readline.js:202:10) at Interface._line (readline.js:531:8) at Interface._ttyWrite (readline.js:760:14) at ReadStream.onkeypress (readline.js:99:10) > obj['openhome.cc']; 'OpenHome' > delete obj['openhome.cc']; true > 'openhome.cc' in obj; false > 除了使用 > var obj = {}; undefined > obj.x ? 'has x' : 'has no x'; 'has no x' > obj.x = 10; 10 > obj.x ? 'has x' : 'has no x'; 'has x' > 特性偵測也可以與 function doSome(option) { return { x : option.x || 1, y : option.y || 2, z : option.z || 3 }; } function log(obj) { for(var p in obj) { console.log(p + ': ' + obj[p]); } } var processed = doSome({ x : 10, y : 20 }); log(processed); 在上例中, x: 10 y: 20 z: 3 JavaScript 是個弱型別語言,在需要將物件轉為數值的場合,會呼叫 > var obj = { ... valueOf : function() { ..... return 100; ..... } ... }; undefined > 100 + obj; 200 > obj + 200; 300 > obj > 100; false > obj >= 100; true > 在需要將物件轉換為字串的場合,則會呼叫 > var caterpillar = { ... name : 'Justin Lin', ... url : 'openhome.cc', ... toString : function() { ..... return '[name: ' + this.name + ', url: ' + this.url + ']'; ..... } ... }; undefined > 'My info: ' + caterpillar; 'My info: [name: Justin Lin, url: openhome.cc]' > 在上例中,若透過 在JavaScript中, > var man1 = { ... name : 'Justin Lin', ... url : 'openhome.cc', ... equals : function(other) { ..... return (this.name === other.name) && (this.url === other.url); ..... } ... }; undefined > var man2 = { ... name : 'Justin Lin', ... url : 'openhome.cc', ... equals : function(other) { ..... return (this.name === other.name) && (this.url === other.url); ..... } ... }; undefined > man1 === man2; false > man1.equals(man2); true > 在上例中,兩個物件的 function equals(other) { return (this.name === other.name) && (this.url === other.url); } var man1 = { name : 'Justin Lin', url : 'openhome.cc', equals : equals }; var man2 = { name : 'Justin Lin', url : 'openhome.cc', equals : equals }; var man3 = { name : 'Justin Lin', url : 'openhome.cc', equals : equals }; console.log(man1.equals(man2)); // true console.log(man1.equals(man3)); // true 實際上,如果你知道如何使用函式定義建構式,並瞭解運用原型鏈(Prototype chain)實現繼承,上頭的需求可以改為以下的方式: function Man(name, url) { this.name = name; this.url = url; } Man.prototype.equals = function(other) { return (this.name === other.name) && (this.url === other.url); }; var man1 = new Man('Justin Lin', 'openhome.cc'); var man2 = new Man('Justin Lin', 'openhome.cc'); var man3 = new Man('Justin Lin', 'openhome.cc'); console.log(man1.equals(man2)); console.log(man1.equals(man3)); 至於為何可以這麼做,會留在之後說明函式時再來討論。 在 ECMAScript 5 的嚴格模式中,不能對一些內建特性做 在嚴格模式下,不允許在使用物件實字建立物件時做重複的特性定義。例如,以下會引發 'use strict'; var obj = { x : 10, x : 20, y : 30 }; EMCAScript 5 之後,在 |