Hướng dẫn và ví dụ ECMAScript Symbol
Xem thêm các chuyên mục:

Là một website được viết trên công nghệ web Flutter vì vậy hỗ trợ rất tốt cho người học, kể cả những người học khó tính nhất.
Hiện tại website đang tiếp tục được cập nhập nội dung cho phong phú và đầy đủ hơn. Mong các bạn nghé thăm và ủng hộ website mới của chúng tôi.


Symbol là một "kiểu dữ liệu nguyên thủy" (Primitive data type) mới, được giới thiệu trong ECMAScript 6. Trước ES6 chúng ta chỉ có 5 kiểu nguyên thủy là Number, String, Boolean, null, undefined.

Để tạo ra một Symbol bạn sử dụng cú pháp dưới đây:
// Create a Symbol
var mySymbol1 = Symbol();
// Create a Symbol
var mySymbol2 = Symbol("Something");
Chú ý rằng: Symbol không phải là một lớp, vì vậy bạn không thể tạo nó bằng toán tử new:
var mySymbol1 = new Simbol(); // ==> ERROR!!
var mySymbol2 = new Simbol("Something"); // ==> ERROR!!
Tất cả các kiểu nguyên thủy Number, String, Boolean, null, undefined đều rất rõ ràng và tường minh.
- Number: 1, 2, 3, ...
- String: "Hello", "Bye", ...
- Boolean: true, false
- null
- undefined
Symbol là một thứ trừu tượng, bạn không thể sờ vào được nó, và không thể biết giá trị thực tế của nó là gì. Symbol là hoàn toàn duy nhất (Hoàn toàn khác nhau), điều đó có nghĩa là nếu bạn tạo ra 2 Symbol, thì chúng là khác nhau, kể cả khi bạn tạo ra 2 Symbol theo cùng một cách.
symbol-example1.js
var symbolA1 = Symbol();
var symbolA2 = Symbol();
console.log(symbolA1); // Symbol()
console.log(symbolA2); // Symbol()
console.log(symbolA1 === symbolA2); // false
var symbolB1 = Symbol("Tom");
var symbolB2 = Symbol("Tom");
console.log(symbolB1); // Symbol(Tom)
console.log(symbolB2); // Symbol(Tom)
console.log(symbolB1 === symbolB2); // false

Symbol có thể sử dụng như một khóa (Key) cho các đối tượng Map.
symbol-map-key-example.js
var key1 = Symbol();
var key2 = Symbol();
var key3 = Symbol("Something");
var map = new Map();
map.set(key1, "Tom");
map.set("a_string_key", "Donald");
map.set(key2, "Jerry");
map.set(key3, "Mickey");
console.log( map.get(key1)); // Tom
console.log( map.get("a_string_key")); // Donald
console.log( map.get(key2)); // Jerry
console.log( map.get(key3)); // Mickey
[Symbol]?
Symbol có thể được sử dụng như một property của một đối tượng.
symbol-object-property-example.js
var prop1 = Symbol();
var prop2 = Symbol();
var prop3 = Symbol("Something");
var myObject = {
name : "Tom",
gender: "Male",
[prop1]: "Something 1",
[prop2]: "Something 2",
[prop3]: "Something 3",
};
console.log( myObject["name"] ); // Tom
console.log( myObject["gender"] ); // Male
console.log( myObject[prop1] ); // Something 1

Symbol thực sự có ích để bạn định nghĩa metadata (Siêu dữ liệu) trong một đối tượng. Nếu property (của một đối tượng) là một Symbol, nó sẽ không được nhận biết bởi các hàm trả về các property.
symbol-metadata-example.js
const sym = Symbol()
const foo = {
name: 'Tom',
age: 25,
[sym]: 'Some Hidden Metadata'
}
let keys = Object.keys(foo) // name, age
console.log("keys: " + keys);
let propNames = Object.getOwnPropertyNames(foo) // name, age
console.log("propNames: " + propNames);
for(let val of keys) {
console.log(foo[val]) // Tom // 25
}

Các Symbol Property không hoàn toàn ẩn, bạn vẫn có thể lấy ra danh sách các Symbol Property của một đối tượng thông qua các phương thức sau:
Object.getOwnPropertySymbols(someObject);
Reflect.ownKeys(someObject);
Ví dụ:
symbol-get-props-example.js
const sym1 = Symbol();
const sym2 = Symbol("Test");
const someObject = {
name: 'Tom',
age: 25,
[sym1]: 'Some Hidden Metadata 1',
[sym2]: 'Some Hidden Metadata 2'
}
var symbolProps = Object.getOwnPropertySymbols(someObject);
console.log(symbolProps); // [ Symbol(), Symbol(Test) ]
var objKeys = Reflect.ownKeys(someObject);
console.log(objKeys); // [ 'name', 'age', Symbol(), Symbol(Test) ]
Trong ES5 rất thường xuyên bạn phải tạo ra các hằng số (constants) để đại diện cho khái niệm nào đó. Và kiểu dữ liệu thường được sử dụng để định nghĩa hằng số là Number hoặc String.
OK, Chẳng hạn bạn cần tạo ra 4 hằng số đại diện cho 4 mùa của năm, và hàm getWeather(season) trả về thời tiết tương ứng với mùa được truyền vào.
var SEASON_SPRING = "SPRING";
var SEASON_SUMMER = "SUMMER";
var SEASON_AUTUMN = "AUTUMN";
var SEASON_WINTER = "WINTER";
function getWeather(season) {
switch(season) {
case SEASON_SPRING:
return "warm";
case SEASON_SUMMER:
return "hot";
case SEASON_AUTUMN:
return "cool";
case SEASON_WINTER:
return "cold";
default:
throw 'Invalid season';
}
}
console.log( getWeather(SEASON_SPRING) ); // warm
Đôi khi bạn sử dụng sai hằng số trong code nhưng vẫn được chương trình chấp nhận. Điều này thật nguy hiểm.
var SEASON_SPRING = "SPRING";
var SEASON_SUMMER = "SUMMER";
var SEASON_AUTUMN = "AUTUMN";
var SEASON_WINTER = "WINTER";
var FRAMEWORK_SPRING = "SPRING";
var FRAMEWORK_STRUTS = "STRUTS";
var weather1 = getWeather( SEASON_SPRING ); // warm
// (***)
var weather2 = getWeather( FRAMEWORK_SPRING ); // warm
Sử dụng Symbol để định nghĩa các hằng số là một giải pháp tốt cho bạn trong trường hợp này. Các hằng số kiểu Symbol đại diện cho một khái niệm cụ thể nào đó được gọi là các Enums (Giống với khái niệm Enums trong Java).
symbol-enums-example.js
// Season Enums:
const SEASON_SPRING = Symbol();
const SEASON_SUMMER = Symbol();
const SEASON_AUTUMN = Symbol();
const SEASON_WINTER = Symbol();
// Framework Enums:
const FRAMEWORK_SPRING = Symbol();
const FRAMEWORK_STRUTS = Symbol();
function getWeather(season) { // Season Enums
switch(season) {
case SEASON_SPRING:
return "warm";
case SEASON_SUMMER:
return "hot";
case SEASON_AUTUMN:
return "cool";
case SEASON_WINTER:
return "cold";
default:
throw 'Invalid season';
}
}
console.log( getWeather(SEASON_SPRING) ); // warm
console.log( getWeather(FRAMEWORK_SPRING) ); // Throw Error: Invalid season
Phương thức Symbol.for(keyName) trả về một giá trị là một Symbol tương ứng với khóa keyName trong một đối tượng Map toàn cục (Global). Nếu khóa keyName không tồn tại trong đối tượng Map toàn cục, một cặp keyName/Symbol(keyName) sẽ được thêm vào đối tượng Map, và trả về Symbol(keyName) nói trên.

symbol-for-example.js
const tom = Symbol.for('Tom') // If the Symbol does not exist, it's created
const tom2 = Symbol.for('Tom') // The Symbol exists, so it is returned
console.log( tom === tom2); // true
Symbol.for() & Symbol.for(undefined) là giống nhau.
symbol-for-example2.js
const foo = Symbol.for();
const bar = Symbol.for(undefined);
console.log( foo === bar); // true
Nếu một Symbol đang được quản lý trên đối tượng Map toàn cục, bạn có thể tìm được khóa của nó bằng cách sử dụng phương thức Symbol.keyFor(symbol).
symbol-keyFor-example.js
const foo = Symbol.for('someKey');// This Symbol in Global Map.
const key1 = Symbol.keyFor(foo); // someKey
console.log(key1); // someKey
const bar = Symbol("Test");// This Symbol not in Global Map.
const key2 = Symbol.keyFor(bar);
console.log(key2); // undefined