資料型別
在JavaScript中,資料型別可以分為兩類:基礎資料型別、引用/複雜資料型別
1.基礎型別:
-
String -> 表示文字型別,如
"Hello World!"
-
Number -> 表示數字,可以是整數或者浮點數,例如
3
或者3.141592
,在JavaScript中,所有數字都是浮點數型別,即使沒有小數部分 -
Boolean -> 表示邏輯實體,只有兩個值:
true
和false
-
Undefined -> 表示表裡已被宣告但未賦值,或者直接沒有被宣告
-
Null -> 表示一個為空的值
-
BigInt(ES2020引入) -> 表示大於
2^53 - 1
的整數,這是Number型別能安全表示的最大整數。BigInt型別的值透過在整數後面加n來建立,例如9007199254740991n
。 -
Symbol(ES6引入) --> 符號型別,表示唯一、不可變的資料值,常用於物件屬性的鍵
2.物件/複雜型別
Object,表示一個例項物件,是鍵值隊的集合。在JavaScript中,幾乎所有事物都是物件,包括陣列、函式等。
-
Function,特殊型別的物件,可呼叫,有時被視為一種資料結構,因為它們可以像物件一樣具有屬性和方法
-
Array,特殊型別的物件,用於儲存資料集合跟列表
此外,Date、RegExp(正規表示式)、Map、Set、WeakMap、WeakSet等都是特殊的物件型別,都可以用來儲存和管理資料。
下面重點說一下Symbol
型別,面試愛問o(╥﹏╥)o
1. 作為物件屬性的鍵:
使用Symbol建立的變數始終是唯一的,把它作為屬性的鍵,可以有效避免衝突或者意外覆蓋問題
let price = {
"影流之主": 6800,
"影流之主": 4800,
}
console.log(price);//{ '影流之主': 4800 }
//可以看到列印出來的物件只有一個屬性,下面改寫一下:
const KEY_ONE = Symbol();
const KEY_TWO = Symbol();
let price2 = {
[KEY_ONE]: 6800,
[KEY_TWO]: 4800,
};
const MY_KEY = Symbol();
price2[MY_KEY] = 3600;
console.log(price2[KEY_ONE]);//6800
console.log(price2);//{ [Symbol()]: 6800, [Symbol()]: 4800, [Symbol()]: 3600 }
2. Symbol值的描述
它可以接受一個字串作為引數,並且透過description屬性可以獲取到對應的描述,進而區分不同的Symbol
const MY_NAME = Symbol('MY_NAME');
const YOUR_NAME = Symbol('YOUR_NAME');
let person = {
[MY_NAME]: '你比從前快樂KX',
[YOUR_NAME]: '甜酒果子',
}
console.log(person[MY_NAME]);//你比從前快樂KX
console.log(person[YOUR_NAME]);//甜酒果子
console.log(MY_NAME.description);//MY_NAME
console.log(YOUR_NAME.description);//YOUR_NAME
//需要說明的是,帶有相同引數的兩個Symbol值不相等,這個引數只是表示Symbol值的描述而已
const id1 = Symbol('id');
const id2 = Symbol('id');
console.log(id1 === id2);//false
3. 隱藏屬性
使用Symbol建立的變數作為物件的屬性,不能被常規方法訪問到,所以可以使用這一點將屬性隱藏,造成一個假的私有屬性現象
const MY_NAME = Symbol('MY_NAME');
const YOUR_NAME = Symbol('YOUR_NAME');
let person = {
[MY_NAME]: '你比從前快樂KX',
[YOUR_NAME]: '甜酒果子',
'name': '張三',
}
console.log(Object.values(person));//[ '張三' ]
console.log(Object.keys(person));//[ 'name' ]
console.log(Object.getOwnPropertyNames(person));//[ 'name' ]
for (const key in person) {
console.log(key);//name
}
可以遍歷到Symbol的方法:
Object.getOwnPropertySymbols() :返回物件中只包含symbol型別key的陣列
Reflect.ownKeys() :返回物件中所有型別key的陣列(包含symbol)
console.log(Object.getOwnPropertySymbols(person));//[ Symbol(MY_NAME), Symbol(YOUR_NAME)
console.log(Reflect.ownKeys(person));//[ 'name', Symbol(MY_NAME), Symbol(YOUR_NAME) ]
4. Symbol自帶的方法
Symbol.for(),在全域性 Symbol 登錄檔中搜尋鍵為 key 的 Symbol。如果找到,則返回它;否則,將建立一個與給定鍵相關聯的新 Symbol。這使得多個獨立的程式碼片段可以透過給定的鍵共享 Symbol。
Symbol.keyFor(),接受一個透過 Symbol.for 方法建立的 Symbol,並返回該 Symbol 登錄檔中的鍵。如果 Symbol 不是全域性註冊的,則返回 undefined。
由於Symbol建立的值獨一無二,但有時候我們可能希望使用同一個Symbol值,這時候就可以透過Symbol.for()
建立
const KEY1 = Symbol.for('KEY');
const KEY2 = Symbol.for('KEY');
console.log(KEY1 === KEY2);//true
console.log(Symbol.keyFor(KEY1));//KEY
console.log(Symbol.keyFor(KEY3));//undefined
3. 包裝型別
在JavaScript中,包裝型別(Wrapper Objects)不被視為獨立的資料型別,而是存在於語言的執行時行為中,用於提供一種方式將原始資料型別(如 string、number、boolean、symbol、bigint)轉換為物件。這樣,原始值就可
以像物件一樣使用,訪問方法和屬性。如下:
let heroName = 'LeBlanc';
console.log(heroName.toLowerCase());//leblanc
console.log(heroName.toString());//LeBlanc
在上面的例子中,字串 heroName 是一個原始型別的值。當呼叫 .toLowerCase() 方法時,JavaScript臨時將 heroName 包裝為一個 String 物件,以便可以訪問 .toLowerCase() 方法。方法呼叫完成後,返回的是一個新的原始型別的字串,而臨時建立的包裝物件被丟棄。
儘管包裝物件在技術上不是JavaScript的基本資料型別,但它們是理解和使用語言中的原始值與物件之間互動的重要概念。然而,直接使用這些包裝物件的建構函式來建立物件(例如,使用 new String("LeBlanc"))是不推薦的,因為它可能導致混淆和錯誤。在大多數情況下,最好讓JavaScript自動處理原始值和物件之間的轉換。
另外,如果你嘗試在原始值上設定一個屬性,JavaScript 會建立一個臨時物件,就像訪問屬性或方法時一樣,但是設定的屬性不會保留,因為這個臨時物件會被立即丟棄。
這個行為可能初看起來有些反直覺。以下是一個例子來說明這個過程:
let assassin = 'LeBlanc';
assassin.chineseName = '樂芙蘭';
console.log(assassin);//LeBlanc
console.log(assassin.chineseName);//undefined
在這個例子中,assassin 是一個字串,因此是一個原始值。當我們嘗試給它設定 chineseName 屬性時,JavaScript 會臨時將 assassin 轉換成一個 String 包裝物件,並在這個物件上設定 chineseName 屬性。但是,一旦這個操作完成,這個臨時的包裝物件就會被丟棄,所以 chineseName 並沒有被真正新增到 assassin 上。當我們接下來嘗試訪問 assassin.chineseName 時,你會得到 undefined,因為 assassin 是一個原始值,它沒有任何附加的屬性。
這也是為什麼通常不建議在原始值上設定屬性:這些屬性不會被永久儲存,因此這個操作沒有任何實際效果。這個行為是 JavaScript 自動裝箱機制的一部分,設計是為了讓原始值表現得像物件一樣,同時保持原始值的輕量和高效。