es6的symbol

230 阅读2分钟

symbol是es6新增的一个类型。使用下面语法声明cosnt s = Symbol()。注意首字母大写,不需要new关键字。Symbol方法会返回独一无二的值,这个值和任何数都不相同。

一、参数

Symbol参数支持string | number | undefined

即使传递进去的参数一样,2者也不相同。

const s1 = Symbol('a');
const s2 = Symbol('a');

console.log(typeof s1, typeof s2); // 都是Symbol(a)
console.log(s1 === s2); // false 二者不相同

可以调用toString将其转为字符串。可以转为Boolean型

const s1 = Symbol('a');
console.log(s1.toString()); // 'Symbol(a)'
console.log(Boolean(s1)); // 恒为true, 即使 Boolean(Symbol())也是为true 

二、作为属性名

在es6中,可以用变量作为方法名,例如下面

let kname = 'name';

let person = {
    [kname]: '小明'
};

console.log(person.name); // 可以访问
console.log(person[kname]); // 可以访问

如果用了symbol后,要访问属性,不能再通过对象.属性来访问,只能对象[变量]用方式。例如下面代码

let kname = Symbol('name');
let person = {
    [kname]: '小明'
}

console.log(person.name); // 不可以访问,因为kname是个symbol,不等于'name'
console.log(person[kname]); // 可以访问

在es6的class中,可以利用symbol这个特性实现私有方法和私有属性。

使用symbol作为属性名,这个属性不会被for..inObject.keysObject.getOwnPropertyNamesJSON.stringify获取到。要获取可以通过Object.getOwnPropertySymbols来获取。

let kname = Symbol('name');
let p = {
    [kname]: '小明',
    age: 18
};

for (const key in p) {
    console.log(`${key}==${p[key]}`); // 只能打印出age
}

console.log(Object.keys(p)); // ["age"]
console.log(Object.getOwnPropertyNames(p)); // ["age"]
console.log(JSON.stringify(p)); // '{"age":18}'
console.log(Object.getOwnPropertySymbols(p)); // [Symbol(name)]
console.log(p[Object.getOwnPropertySymbols(p)]); // 小明

除了Object.getOwnPropertySymbols外,还可以用es6的Reflect对象的静态方法Reflect.ownKeys,他可以返回所有类型的属性名。

let kname = Symbol('name');
let p = {
    [kname]: '小明',
    age: 18
};

console.log(Reflect.ownKeys(p)); // ["age", Symbol(name)]
console.log(Reflect.ownKeys(p)[1]); // Symbol(name)类型
console.log(p[Reflect.ownKeys(p)[1]]); // 小明

三、Symbol.for() 和 Symbol.keyFor()

Symbol包含2个静态方法。forkeyFor

3.1 Symbol.for

直接只用Symbol创建的遍历是独一无二的,就像上面的例子。

而使用Symbol.for创建的不一样,会根据传入的参数,优先判断下有没有创建过了,有则返回创建过的变量。无则创建1个。使用该方法创建symbol值后会在全局范围进行注册。

const s1 = Symbol('s');
const s2 = Symbol('s');
console.log(s1 === s2); // false

const s3 = Symbol.for('s');
const s4 = Symbol.for('s');
console.log(s4 === s3); // true

console.log(s1 === s3); // false

注意:这个全局注册包括当前页面和页面中的iframe,以及servie worker

比如下面有2个html,inner.html以iframe的形式嵌入

<!-- inner.html -->
<script type="text/javascript">
    var sym = Symbol.for('a');
</script>

<!-- outer.html -->
<iframe id="iframe" src="./inner.html"></iframe>
<script type="text/javascript">
    var s = Symbol.for('a');
    console.log(document.getElementById('iframe').contentWindow.sym === s); // true
</script>

跨iframe后判断,2个symbol相同

3.1 Symbol.for

该方法传入一个Symbol值,返回该值在全局注册的键名。只能查Symbol.for,如果是Symbol创建的就无法查回。

const s1 = Symbol.for('a');
console.log(Symbol.keyFor(s1)); // 'a'

const s2 = Symbol('a');
console.log(Symbol.keyFor(s2)); // undefined