型別與純值

JavaScript 型別基礎介紹

型別

JavaScript 是一個動態型別的語言,也就是在賦值時才會知道型別

1
2
3
4
5
6
7
// c#
bool isNew = 'hello'; // error

// js
var isNew = true; // boolean and no errors
isNew = 'yup'; // string and no errors
isNew = 1; // number and no errors

純值 (基本型別)

純值是一種資料的型別,表示一個值,換句話說不是物件,因為物件是名稱/值的配對,JS 有以下六種值

undefined

JS 給所有變數的初始值,直到你主動賦值,這表示還未設定值,所以不應該使用它來設定值

null

這也表示沒有值,但與 undefined 的差異在於可使用它來定義變數沒有值

boolean

true 或 false 表示

number

表示一個浮點數 float,所以永遠有小數點跟在後面,和其他程式語言分成整數和浮點數不同,JS 只有一種型別來表示數字

string

可使用單引號 ‘’ 或雙引號 “” 來括住任何字符

symbol

symbol 代表一個唯一值,可透過 symbol() 函數來生成

1
2
3
4
5
6
7
let s1 = Symbol();

typeof s1; // symbol

let s2 = Symbol();

s1 === s2; // false

因為 symbol 為一個函數不是 constructor,所以使用關鍵字 new 會出錯

1
2
// TypeError: Symbol is not a constructor
let s1 = new Symbol();

symbol 函數可以給定一個字串參數來命名,藉此區別不同的 symbol 參數,但因為唯一特性,即使給定同一參數也是不同的值

1
2
3
4
5
6
7
8
9
let s1 = Symbol('foo');
let s2 = Symbol('bar');

s1.toString(); // 'Symbol(foo)'
s2.toString(); // 'Symbol(bar)'

let s3 = Symbol('foo');

s1 === s3; // false

由於 symbol 的唯一特性,所以 symbol 被拿來當物件屬性名稱時可以確保不會出現相同的名稱,也確保不會被覆蓋,物件的賦值有以下 3 種方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let mySymbol = Symbol('a');

// 1
let obj = {};
obj[mySymbol] = 'Hello';

// 2
let obj = {
[mySymbol]: 'Hello'
};

// 3
let obj = {};
Object.defineProperty(obj, mySymbol, {value: 'Hello'});

這裡要注意的是,使用 symbol 作為物件的屬性時,只能透過 computed property [] 語法,不能使用 . 運算子

1
2
3
4
5
let a = {};

a.mySymbol = 'Hello';

a[mySymbol]; // undefined
Global symbol

如果希望共享同一個 symbol 可以透過 Symbol.for()Symbol.keyFor() 來存取值

  • Symbol.for(key)
    取得名稱為 key 的值,如果該值不存在,則會建立一個新的值到 global symbol registry 再返回,另外 key 名稱也會被當成 symbol 名稱

    1
    2
    3
    4
    5
    6
    7
    8
    9
    Symbol.for('foo');

    Symbol.for('foo') === Symbol.for('foo'); // true

    Symbol('foo') === Symbol('foo'); // false

    let a = Symbol.for('foo');

    a.toString(); // 'Symbol(foo)'
  • Symbol.keyFor()
    用來取得 global symbol key 的名稱,如果沒有該名稱則返回 undefined

    1
    2
    3
    4
    5
    6
    7
    let a = Symbol.for('foo');

    Symbol.keyFor(a); // foo

    let b = Symbol();

    Symbol.keyFor(b); // undefined
Object.getOwnPropertySymbols() : Symbol 遍歷

物件的 symbol 屬性名稱無法被遍歷,如 for....infor...ofObject.keys()Object.getOwnPropertyNames()JSON.stringify() 都不會返回 Symbol 屬性名稱

因此如果要取得 Symbol 屬性名稱可以使用 Object.getOwnPropertySymbols() 方法,此方法會返回一個陣列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let obj = {};

obj[Symbol('a')] = 'a';
obj[Symbol.for('b')] = 'b';
obj['c'] = 'c';
obj.d = 'd';

for (var i in obj) {
console.log(i);
}
// c
// d

let objectSymbols = Object.getOwnPropertySymbols(obj);

objectSymbols; // [Symbol(a), Symbol(b)]