JavaScript 允許我們像使用對象壹樣使用原始類型(字符串,數字等)。JavaScript 還提供了這樣的調用方法。我們很快就會學習它們,但是首先我們將了解它的工作原理,畢竟原始類型不是對象(在這裏我們會分析地更加清楚)。
我們來看看原始類型和對象之間的關鍵區別。
壹個原始值:
是原始類型中的壹種值。
在 JavaScript 中有 7 種原始類型:string
,number
,bigint
,boolean
,symbol
,null
和 undefined
。
壹個對象:
能夠存儲多個值作爲屬性。
可以使用大括號 {}
創建對象,例如:{name: "John", age: 30}
。JavaScript 中還有其他種類的對象,例如函數就是對象。
關于對象的最好的事兒之壹是,我們可以把壹個函數作爲對象的屬性存儲到對象中。
let john = { name: "John", sayHi: function() { alert("Hi buddy!"); } }; john.sayHi(); // Hi buddy!
所以我們在這裏創建了壹個包含 sayHi
方法的對象 john
。
許多內建對象已經存在,例如那些處理日期、錯誤、HTML 元素等的內建對象。它們具有不同的屬性和方法。
但是,這些特性(feature)都是有成本的!
對象比原始類型“更重”。它們需要額外的資源來支持運作。
以下是 JavaScript 創建者面臨的悖論:
人們可能想對諸如字符串或數字之類的原始類型執行很多操作。最好使用方法來訪問它們。
原始類型必須盡可能的簡單輕量。
而解決方案看起來多少有點尴尬,如下:
原始類型仍然是原始的。與預期相同,提供單個值
JavaScript 允許訪問字符串,數字,布爾值和 symbol 的方法和屬性。
爲了使它們起作用,創建了提供額外功能的特殊“對象包裝器”,使用後即被銷毀。
“對象包裝器”對于每種原始類型都是不同的,它們被稱爲 String
、Number
、Boolean
、Symbol
和 BigInt
。因此,它們提供了不同的方法。
例如,字符串方法 str.toUpperCase() 返回壹個大寫化處理的字符串。
用法演示如下:
let str = "Hello"; alert( str.toUpperCase() ); // HELLO
很簡單,對吧?以下是 str.toUpperCase()
中實際發生的情況:
字符串 str
是壹個原始值。因此,在訪問其屬性時,會創建壹個包含字符串字面值的特殊對象,並且具有可用的方法,例如 toUpperCase()
。
該方法運行並返回壹個新的字符串(由 alert
顯示)。
特殊對象被銷毀,只留下原始值 str
。
所以原始類型可以提供方法,但它們依然是輕量級的。
JavaScript 引擎高度優化了這個過程。它甚至可能跳過創建額外的對象。但是它仍然必須遵守規範,並且表現得好像它創建了壹樣。
數字有其自己的方法,例如,toFixed(n) 將數字舍入到給定的精度:
let n = 1.23456; alert( n.toFixed(2) ); // 1.23
我們將在後面 數字類型 和 字符串 章節中看到更多具體的方法。
構造器 String/Number/Boolean
僅供內部使用
像 Java 這樣的壹些語言允許我們使用 new Number(1)
或 new Boolean(false)
等語法,明確地爲原始類型創建“對象包裝器”。
在 JavaScript 中,由于曆史原因,這也是可以的,但極其 不推薦。因爲這樣會出問題。
例如:
alert( typeof 0 ); // "number" alert( typeof new Number(0) ); // "object"!
對象在 if
中始終爲真,所以此處的 alert 將顯示:
let zero = new Number(0); if (zero) { // zero 爲 true,因爲它是壹個對象 alert( "zero is truthy?!?" ); }
另壹方面,調用不帶 new
(關鍵字)的 String/Number/Boolean
函數是可以的且有效的。它們將壹個值轉換爲相應的類型:轉成字符串、數字或布爾值(原始類型)。
例如,下面完全是有效的:
let num = Number("123"); // 將字符串轉成數字
null/undefined 沒有任何方法
特殊的原始類型 null
和 undefined
是例外。它們沒有對應的“對象包裝器”,也沒有提供任何方法。從某種意義上說,它們是“最原始的”。
嘗試訪問這種值的屬性會導致錯誤:
alert(null.test); // error
除 null
和 undefined
以外的原始類型都提供了許多有用的方法。我們後面的章節中學習這些內容。
從形式上講,這些方法通過臨時對象工作,但 JavaScript 引擎可以很好地調整,以在內部對其進行優化,因此調用它們並不需要太高的成本。
重要程度: 5
思考下面的代碼:
let str = "Hello"; str.test = 5; alert(str.test);
妳怎麽想的呢,它會工作嗎?會得到什麽樣的結果?
試試運行壹下:
let str = "Hello"; str.test = 5; // (*) alert(str.test);
根據妳是否開啓了嚴格模式 use strict
,會得到如下結果:
undefined
(非嚴格模式)
報錯(嚴格模式)。
爲什麽?讓我們看看在 (*)
那壹行到底發生了什麽:
當訪問 str
的屬性時,壹個“對象包裝器”被創建了。
在嚴格模式下,向其寫入內容會報錯。
否則,將繼續執行帶有屬性的操作,該對象將獲得 test
屬性,但是此後,“對象包裝器”將消失,因此在最後壹行,str
並沒有該屬性的蹤迹。
這個例子清楚地表明,原始類型不是對象。
它們不能存儲額外的數據。