在面試過程中,會遇到有關Symbol的問題,所以學習了下:
<script>
//=======Symbol:
//Symbol是由ES6規範引入的一項新特性,是一種新的基礎數據類型,它的功能類似於一種標識唯一性的ID。
//通常情況下,我們可以通過調用Symbol()函數來創建一個Symbol實例,用來表示獨一無二的值,是一種原始數據類型。
let x = Symbol();
console.log(typeof x); //symbol
// Symbol函數可以接受字符串爲參數,表示對Symbol實例的描述。爲在控制檯輸出,或者轉換爲字符串時,比較容易區分.
let s2 = Symbol('another symbol')
// ES2019提供了一個屬性description,直接返回Symbol的描述
// Symbol值都是不相等的,意味着Symbol值可以作爲標識符,用於對象的屬性名,就可以保證不會出現同名的屬性
let s3 = Symbol('another symbol')
console.log(s3 === s2); //false
// Symbol作爲對象的屬性名時,不能用點運算符,要使用[]
let a = Symbol();
let obj1 = {
[a]: function (arg) {
console.log(arg)
}
}
obj1[a](123); //123
// Symbol作爲屬性名時,該屬性是公有屬性,不是私有屬性,
// 使用場景:
// 1、定義一組常量,保證常量的值都不相等.示例1:
const log = {};
log.levels = {
DEBUG: Symbol('debug'),
INFO: Symbol('info'),
WARN: Symbol('warn')
}
console.log(log.levels.DEBUG, 'debug messagee'); //Symbol(debug) "debug messagee"
console.log(log.levels.INFO, 'info messagee'); //Symbol(info) "info messagee"
// 示例2:
const COLOR_RED = Symbol();
const COLOR_GREEN = Symbol();
function getComplement(color) {
switch (color) {
case COLOR_RED:
return COLOR_RED;
case COLOR_GREEN:
return COLOR_GREEN;
default:
throw new ERROR('undefined color')
}
}
// 常量使用symbol值最大好處,就是其他任何值都不可能有相同的值,因此可以保證上面的switch語句會按設計的方式工作。
//2、作爲對象的key屬性,防止對象屬性被重寫,示例:
let name = Symbol();
{
plugin = {};
plugin[name] = 'plugin';
console.log(plugin[name]); //plugin
}
{
let name = Symbol();
plugin[name] = 'user';
console.log(plugin[name]);//user
}
console.log(plugin); //{Symbol(): "plugin", Symbol(): "user"}
console.log(plugin[name]); //plugin
// 當使用了Symbol作爲對象的屬性key後,在對該對象進行key的枚舉時,會有什麼不同?在實際應用中,我們經常會需要使用Object.keys()或者for...in來枚舉對象的屬性名,那在這方面,Symbol類型的key表現的會有什麼不同之處呢?來看以下示例代碼:
let object1 = {
[Symbol('name')]: '一斤代碼',
age: 18,
title: 'enginner'
}
Object.keys(object1);//["age", "title"]
for (let p in object1) {
console.log(p); //age title
}
Object.getOwnPropertyNames(object1);//["age", "title"]
// 從以上代碼的輸出,不難看出,Symbol類型的key是不能通過Object.keys()或者for...in來枚舉,它未被包含在對象自身的屬性名集合(property names)之中。所以,利用該屬性,我們可以把一些不需要對外操作和訪問的屬性使用Symbol來定義。
// 當使用JSON.stringify(),將對象轉換爲JSON字符串時,Symbol也被排除在外,即不含Symbol的值。
console.log(JSON.stringify(object1)); //{"age":18,"title":"enginner"}
// 那麼,怎麼獲取以Symbol方式定義的對象屬性呢?可以使用下列針對Symbol的API:
// => 使用Object的API:
Object.getOwnPropertySymbols(object1); //[Symbol(name)]
// => 使用新增的反射API
Reflect.ownKeys(object1); //(3) ["age", "title", Symbol(name)]
// 3、使用Symbol定義類的私有屬性/方法
// 模塊化中的使用,在a.js文件中:
const PASSWORD = Symbol();
class Login {
constructor(username, password) {
this.username = username;
this[PASSWORD] = password;
}
checkPassword(pwd) {
return this[PASSWORD] === pwd
}
}
export default Login;
// b.js文件:
import Login from './a.js';
const login = new Login('admin', '123455');
login.checkPassword('123456');
login.PASSWORD // oh!no!
login[PASSWORD];// oh!no!
login['PASSWORD']// oh!no!
// 由於Symbol常量被定義在a.js模塊中,在b。js中拿不到,也不能創建一個一模一樣的(是唯一的),所以這個PASSWORD是限制在a.js中。所以使用它來定義的類屬性是沒有辦法被模塊外訪問到的,達到了一個私有化的效果。
// 註冊和獲取全局Symbol
//通常情況下,在瀏覽器窗口(window)中,使用Symbol()函數來定義和Symbol實例就夠了,但,如果應用設計到多個window(如使用iframe),並需要這些window中創建的Symbol是同一個,就不能使用Symbol()函數了。要使用另一個API:就是Symbol.for()
//可以註冊或獲取一個window間全局的Symbol實例
let gs1 = Symbol.for('global_symbol_1'); //註冊一個全局Symbol
let gs2 = Symbol.for('global_symbol_1');
//獲取全局Symbol
console.log(gs1 === gs2); //true
</script>
參考:https://www.jianshu.com/p/f40a77bbd74e