本節書摘來自異步社區《JavaScript面向對象精要》一書中的第1章,第1.8節,作者:【美】Nicholas C. Zakas著,更多章節內容可以訪問云棲社區“異步社區”公眾號查看
1.8 原始封裝類型
JavaScript中一個最讓人困惑的部分可能就是原始封裝類型的概念。原始封裝類型共有3種(String、Number和Boolean)。這些特殊引用類型的存在使得原始類型用起來和對象一樣方便。(如果你不得不用獨特的語法或切換為基于過程的編程方式來獲取一個子字符串,那就太讓人困惑啦)。
當讀取字符串、數字或布爾值時,原始封裝類型將被自動創建。例如,下列代碼第一行,一個原始字符串的值被賦給name。第二行代碼把name當成一個對象,使用點號調用了charAt方法。
var name = "Nicholas";
var firstChar = name.charAt(0);
console.log(firstChar); // "N"
這是在背后發生的事情如下。
// what the JavaScript engine does
var name = "Nicholas";
var temp = new String(name);
var firstChar = temp.charAt(0);
temp = null;
console.log(firstChar); // "N"
由于第二行把字符串當成對象使用,JavaScript引擎創建了一個字符串的實體讓charAt(0)可以工作。字符串對象的存在僅用于該語句并在隨后被銷毀(一種稱為自動打包的過程)。為了測試這一點,試著給字符串添加一個屬性看看它是不是對象。
var name = "Nicholas";
name.last = "Zakas";console.log(name.last); // undefined
這段代碼試圖給字符串name添加last屬性。代碼運行時沒有錯誤,但是屬性卻消失了。到底發生了什么?你可以在任何時候給一個真的對象添加屬性,屬性會保留至你手動刪除它們。原始封裝類型的屬性會消失是因為被添加屬性的對象立刻就被銷毀了。
下面是在JavaScript引擎中實際發生的事情。
// what the JavaScript engine does
var name = "Nicholas";
var temp = new String(name);
temp.last = "Zakas";
temp = null; // temporary object destroyedvar temp = new String(name);
console.log(temp.last); // undefined
temp = null;
實際上是在一個立刻就被銷毀的臨時對象上而不是字符串上添加了新的屬性。之后當你試圖訪問該屬性時,另一個不同的臨時對象被創建,而新屬性并不存在。雖然原始封裝類型會被自動創建,在這些值上進行instanceof檢查對應類型的返回值卻都是false。
var name = "Nicholas";
var count = 10;
var found = false;console.log(name instanceof String); // false
console.log(count instanceof Number); // false
console.log(found instanceof Boolean); // false
這是因為臨時對象僅在值被讀取時創建。instanceof操作符并沒有真的讀取任何東西,也就沒有臨時對象的創建,于是它告訴我們這些值并不屬于原始封裝類型。
你也可以手動創建原始封裝類型,但有某些副作用。
var name = new String("Nicholas");
var count = new Number(10);
var found = new Boolean(false);console.log(typeof name); // "object"
console.log(typeof count); // "object"
console.log(typeof found); // "object"
如你所見,手動創建原始封裝類型實際會創建出一個object,這意味著typeof無法鑒別出你實際保存的數據的類型。
另外,使用String、Number和Boolean對象和使用原始值有一定區別。例如,下列代碼使用了Boolean對象,對象的值是false,但console.log(“Found”)依然會被執行。這是因為一個對象在條件判斷語句中總被認為是true,無論該對象的值是不是等于false。
var found = new Boolean(false);
if (found) {console.log("Found"); // this executes
}
手工創建的原始封裝類型在其他地方也很容易讓人誤解,在大多數情況下都只會導致錯誤。所以,除非有特殊情況,你應該避免這么做。