Javascript(笔记35) - ES6特性 - Symbol数据类型
Symbol
ES6引入了一种新的原始数据类型 Symbol ,表示独一无二的值。它是 Javascript 语言的第七种数据类型:
特点:
Symbol 的值是唯一的,用来解决命名冲突的问题;
Symbol 值不能与其他数据进行运算;
Symbol 定义的对象属性不能使用 for ... in 循环遍历;
可以使用 Reflect.ownKeys 来获取对象的所有键名;
创建Symbol
let s1 = Symbol();
let s2 = Symbol();
console.log(s1,s2,typeof(s1)); // Symbol() Symbol() 'symbol'
console.log(s1 === s2); // false
console.log(s1 == s2); // false
Symbol 的唯一性是内部实现的,表面上看都是 Symbol() ,长的一样,但不相等;
也可以带参数:仅做为说明;
let s1 = Symbol("Jack"); // 简单说明这个 Symbol 是干嘛的;
let s2 = Symbol("Jack");
console.log(s1 === s2); // false
即使有参数说明,也是不相等的,就像都是叫“小明”的人,是两个人;
通过 Symbol.for() 对象方式创建的,就可以相等了;
let s1 = Symbol.for("Jack");
let s2 = Symbol.for("Jack");
console.log(s1,s2,typeof(s1)); // Symbol(Jack) Symbol(Jack) 'symbol'
console.log(s1 === s2); // true
这么些数据类型怎么记呢: USONB: you are so niubility.
U:undefined
S:string、symbol
O:object
N:number、null
B:boolean
特性1:不能运算
let s = Symbol();
let res = s + 100; // 报错
let res = s > 100; // 报错:Cannot convert a Symbol value to a number
let res = s + "100"; // 报错:Cannot convert a Symbol value to a string
特性2:不能 new
这是个新规定,以前的包装类不受影响;
let sym = new Symbol(); // 报错
以前的还是可以用:new Boolean
、new String
以及 new Number
特性3:不能被 for...in 枚举
let obj = {};
obj[Symbol('a')] = 'one';
obj[Symbol.for('b')] = 'two';
obj['c'] = 'three';
obj.d = 'four';
for (let k in obj) {
console.log(k); // c d
}
console.log(obj[Object.getOwnPropertySymbols(obj)[0]]); // one
可以通过 Object.getOwnPropertySymbols(obj) 来获得 Symbol 属性;
特性4:JSON.stringify() 会被忽略
还以上面 obj 为例:
let obj = {};
obj[Symbol('one')] = 'one';
obj[Symbol.for('two')] = 'two';
obj['c'] = 'three';
obj.d = 'four';
console.log(JSON.stringify(obj)); // {"c":"three","d":"four"}
给对象添加方法和属性
1 在外部声明实例
同名的方法 ,两种方法,调用的时候用中括号 [] 。
// 原对象,有两个方法
let game = {
name:"wow",
up(){
console.log("穿上装备");
},
down(){
console.log("换下装备");
}
};
// 第一种办法:声明一个 Symbol()
let up = Symbol("up:grade");
// 为 game 对象创建方法
game[up] = function(){
console.log("打怪升级");
}
//调用方法
game[up](); // 打怪升级
// 第二种办法:声明一个对象,里面放俩属性
let methods = {
up:Symbol("up"),
down:Symbol("down")
}
// 再把对象的属性作为 game 的方法
game[methods.up] = function(){
console.log("穿上神秘装备");
}
game[methods.down] = function(){
console.log("换下神秘装备");
}
// 调用这些方法
game[methods.up](); // 穿上神秘装备
game[methods.down](); // 换下神秘装备
原对象 game 里已有了一个 up 方法;新建了一个 Symbol 实例,把这个实例作为 game 的方法名,再建一个 up 方法;声明一个对象,把 up (Symbol) 再作为 game 的方法名,再建一个 up 方法;
调用这些方法:
// obj[方法名]()
game[up](); // 打怪升级
game[methods.up](); // 穿上神秘装备
2 在内部隐去实例
也可以隐去实例化对象,直接使用 [Symbol()] 作为属性和方法名,效果一样;
let youxi = {
name : "狼人杀",
[Symbol('say')]:function(){
console.log('我可以发言');
},
[Symbol('zibao')](){
console.log('我可以自爆');
}
}
调用这些方法:
// Reflect.ownKeys(obj)
youxi[Reflect.ownKeys(youxi)[1]](); // 我可以发言
youxi[Reflect.ownKeys(youxi)[2]](); // 我可以自爆
// Object.getOwnPropertySymbols(obj);
youxi[Object.getOwnPropertySymbols(youxi)[0]](); // 我可以发言
youxi[Object.getOwnPropertySymbols(youxi)[1]](); // 我可以自爆
注意: 这两调用方法都是返回数组,但调用的下标却不一样;
Reflect.ownKeys(obj) 反射方法,返回所有自身属性数组,包括 Symbol 属性;
Object.getOwnPropertyNames(youxi) 返回所有属性,但不包括 Symbol 属性的数组;
Object.getOwnPropertySymbols(obj) 返回一个给定对象自身的所有 Symbol 属性的数组;
所以:Reflect.ownKeys(youxi) 相当于:
Object.getOwnPropertyNames(youxi).concat(Object.getOwnPropertySymbols(youxi))
时髦写法:
[...Object.getOwnPropertyNames(youxi),...Object.getOwnPropertySymbols(youxi)]
看下控制台:
Symbol内置值
除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法;
Symbol.hasInstance
用来判断某个对象是否为某构造器的实例。因此你可以用它自定义 instanceof 操作符在某个类上的行为。
class Person {
static [Symbol.hasInstance](param){
console.log(param);
console.log('我被用来检测类型了');
return true;
}
}
let o ={};
console.log(o instanceof Person); // true
自定义返回值了,想要返回 fasle ,也可以自己修改;
Symbol.isConcatSpreadable
配置某对象作为Array.prototype.concat()方法的参数时是否展开其数组元素。
const arr1 = [1,2,3];
const arr2 = [4,5,6];
const arr = arr1.concat(arr2);
console.log(arr); // [1, 2, 3, 4, 5, 6]
这是常规操作数组合并的方式;
改一下:
const arr1 = [1,2,3];
const arr2 = [4,5,6];
arr2[Symbol.isConcatSpreadable] = false;
const arr = arr1.concat(arr2);
console.log(arr); // [1, 2, 3, Array(3)]
其他属性也是控制当前对象在特定场景下的表现,如:
Symbol.split
Symbol.Primitive
Symbol.toStringTag
Symbol.species
这些Symbol的属性都和 Symbol 连在一起用,用来作为某对象的属性,在某些时候扩展功能;
Symbol.iterator
对象进行 for ... of 循环时,会调用 Symbol.iterator 方法,返回该对象的默认遍历器;
迭代器的剖分,放在下篇文章;