[TOC]
什么是Symbol属性
ES6中添加的一种新的原始数据类型Symbol(已有的原始数据类型有:String,Number,Boolean,null,undefined,Object)。
特点:
- Symbol属性对应的值是独一无二的,可以解决命名冲突问题;
- Symbol值不能与其他数据进行计算,包括字符串拼串;
- for in,for of遍历时不会遍历Symbol属性。
Symbol是基本数据类型,独一无二(永远不相等)。
let s1 = Symbol(); // 可以接收一个标识参数
let s2 = Symbol();
// symbol中可以增加标识
console.log(s1 === s2); // false
1
2
3
4
2
3
4
let s3 = Symbol('test'); // symbol中的标识一般为number或者string
let s4 = Symbol('test');
console.log(s3 === s4); // false
1
2
3
4
2
3
4
let obj = {
name: 'lisi',
[s2]: 1 // 对象的属性为Symbol类型的话,该属性不可枚举
}
console.log(obj); // { name: 'lisi', [Symbol()]: 1 }
console.log(obj[s2]); // 1
1
2
3
4
5
6
2
3
4
5
6
Symbol类型的属性不可枚举
let obj = {
name: 'lisi',
[s2]: 1 // 对象的属性为Symbol类型的话,该属性不可枚举
}
for (let key in obj) {
console.log(obj[key]); // 'name'
}
console.log(Object.keys(obj)); // [ 'name' ]
// getOwnPropertySymbols获取对象中symbol类型的key
console.log(Object.getOwnPropertySymbols(obj)); // [ Symbol() ]
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
Symbol.for
let s5 = Symbol.for('lisi'); // 没有这个变量,就声明一个
let s6 = Symbol.for('lisi'); // 如果已经存在了,可以直接获取对应的symbol
console.log(Symbol.keyFor(s5)); // lisi
// 所以s5和s6是相等的
console.log(s5 === s6); // true
1
2
3
4
5
6
2
3
4
5
6
Symbol.iterator
Symbol内置对象Symbol.iterator
实现对象的遍历。原因在于:对象的Symbol.iterator属性指向该对象的默认遍历器方法。
改写对象原生的instanceof方法
实现元编程可以对原生js的操作进行修改。
let obj = {
// 改写对象的instanceof方法
[Symbol.hasInstance](value) {
console.log(value); // { a: 1 }
// 只要value中存在a属性就返回true
return 'a' in value;
}
};
console.log({a: 1} instanceof obj); // true
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
Symbol.isConcatSpreadable
Symbol.isConcatSpreadable
:在使用展开运算符的时候是否把数组展开。
let arr = [1, 2, 3];
// 设置在使用concat方法进行数组拼接时,不展开arr
arr[Symbol.isConcatSpreadable] = false;
console.log([].concat(arr, [4, 5, 6]));
/*
[ [ 1, 2, 3, [Symbol(Symbol.isConcatSpreadable)]: false ],
4,
5,
6 ]
*/
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
Symbol.match
// match split search
let obj = {
[Symbol.match](value) {
// value的长度为2则返回true
return value.length === 2;
}
}
console.log('12'.match(obj)); // true
console.log('123'.match(obj)); // false
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
Symbol.species(衍生对象)
// species 衍生对象
class MyArray extends Array {
constructor(...args) { // 先将类数组转为数组[1, 2, 3]
// 调用父类的构造函数
super(...args); // 再展开
}
// 强制修改一下
// 使得arr2 instanceof MyArray为false
// arr2 instanceof Array为true
// 静态属性
// 静态即属于类自己的
static get [Symbol.species]() {
return Array;
}
}
let arr = new MyArray(1, 2, 3);
console.log(arr); // MyArray [ 1, 2, 3 ]
let arr2 = arr.map(item => item *= 2); // arr2是arr的衍生对象
console.log(arr2 instanceof MyArray); // false
console.log(arr2 instanceof Array); // true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Symbol.toPrimitive
let obj = {
[Symbol.toPrimitive](type) {
console.log(type); // number
return 11;
}
}
console.log(obj++); // 11
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
let obj = {
[Symbol.toPrimitive](type) {
console.log(type); // default
return 11;
}
}
console.log(obj + '22'); // 1122
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Symbol.toStringTag
let obj = {
[Symbol.toStringTag]: 'test'
}
console.log(Object.prototype.toString.call(obj)); // [object test]
1
2
3
4
2
3
4
Symbol.unscopables
with({name: 1}){
// with内部会以{name: 1}对象为this指向来取值
console.log(name); // 1
}
1
2
3
4
2
3
4
let arr = [];
console.log(arr[Symbol.unscopables]);
/*
{ copyWithin: true,
entries: true,
fill: true,
find: true,
findIndex: true,
includes: true,
keys: true }
这些方法默认取不到,这些方法不在数组的作用域内
*/
let arr = [];
with(arr){
// with内部会以arr为this指向来取值
console.log(forEach); // [Function: forEach]
console.log(findIndex); // ReferenceError: findIndex is not defined
}
// 模板引擎(ejs这些)就是用with语法实现的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19