JavaScript Primitives Objects

接續上一篇文章,JavaScript 的資料型別可以分為兩類:基本型別(primitive value)和物件(object)。基本型別包含字串、數值、布林值等,物件除了物件外,還有像是函數、Regular Expression 等。JavaScript 還有一組很特別的 constructor,對應到每種基本型別,所以你可以new String('blah');來產生基本型別的物件:

new String('blah');
new Number(42);
ner Boolean(true);

如果看最近的書本和教學都會說不要使用這種方法來建立這些基本型別,缺點有效能問題、API 設計不好,會有混淆等等。不過如果是物件的話,不就可以很方便的做一些操作了嗎?

這兩年很受歡迎的 Ruby 有一個特性就是所有的基本型別都是物件,所以就可以很簡單的用一些串接的方式直接對這些基本型別進行操作:

str = 'hello'
str.capitalize        #  Hello
str.capitalize!
str                   #  Hello
str.count('l')        #  2

在 JavaScript 中的基本型別其實不需要以物件的形式,也可以做類似的操作:

var str = 'hello';
str.length;           // 2
str.contains('l');    // true
str.indexOf('l');     // 2

但是如果想要更進一步的在上面加上屬性或是 method 就會發現行不通:

var str = 'hello';
str.target = 'world';
str.target;            // undefined

這中間到底是有什麼差異呢?這個問題我想了很久,直到看了 The Secret Life of JavaScript Primitives 這篇文章才瞭解,最後面這個例子,其實等同於:

var str = 'hello';
(new String(str)).target = 'world';
(new String(str)).target;

當使用物件形式的.運算子對基本型別資料操作的時候,會產生一個新的物件,然後用完就丟掉,所以在指派 target 屬性那行操作到的物件,和要取回 target 屬性那行的物件,是完全不一樣的兩個物件,這也就是為什麼這些資料可以用類似物件的方法操作,但是卻不能真的像物件一樣使用。