js中的Symbol类型详解

314 阅读4分钟

语法

Symbol([description])

  • description 可选的,字符串类型。对 symbol 的描述,可用于调试但不是访问 symbol 本身。

Symbol类型详解

  1. symbol 是一种基本数据类型。Symbol() 函数会返回 symbol 类型的值。
  2. 作为构造函数来说它并不完整,因为它不支持语法:"new Symbol()"。
  3. 每个从 Symbol() 返回的 symbol 值都是唯一的。一个 symbol 值能作为对象属性的标识符;这是该数据类型仅有的目的。
  4. Symbole可以显示的转为字符串,布尔值,但是不能转为数字,symbol通过Boolean()转为布尔值时为true,取反为false;symbol通过toString调用后会返回Symbol([description])
  5. 属性名遍历:
  • Symbol 作为属性名,该属性不会出现在for...infor...of循环中,也不会被Object.keys()Object.getOwnPropertyNames()JSON.stringify()返回。
  • 它不是私有属性,有一个Object.getOwnPropertySymbols方法,可以获取指定对象的所有 Symbol 属性名。
  • Object.getOwnPropertySymbols():返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。
  • Reflect.ownKeys():返回所有类型的键名。Symbol.for(key)使用给定的 key 搜索现有的 symbol,如果找到则返回该 symbol。否则将使用给定的 key 在全局 symbol 注册表中创建一个新的 symbol。
let obj = {
  [Symbol('my_key')]: 1,
  enum: 2,
  nonEnum: 3
    };
Reflect.ownKeys(obj)
//  ["enum", "nonEnum", Symbol(my_key)]
  1. symbol的静态方法
  • Symbol.for(key) 使用给定的 key 搜索现有的 symbol,如果找到则返回该 symbol。否则将使用给定的 key 在全局 symbol 注册表中创建一个新的 symbol。
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2 // true
  • Symbol.keyFor(sym) 传入一个symbol值可以返回该值在全局注册的键名。
let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"
let s2 = Symbol("foo");//不能返回该值注册的键名
Symbol.keyFor(s2) // undefined
  1. ES6的内置Symbol值
  • Symbol.hasInstance用于判断某对象是否为某构造器的实例。因此你可以用它自定义 instanceof操作符在某个类上的行为。
class Array1 {
  static [Symbol.hasInstance](instance) {
    return Array.isArray(instance);
  }
}
console.log([] instanceof Array1);
  • Symbol.isConcatSpreadable 符号用于配置某对象作为Array.prototype.concat()方法的参数时是否展开其数组元素。该属性是一个可读写的布尔值,默认值为undefined当值为false时,数组不能被展开,为true或undefined则可以展开其数组元素。
let arr1 = [1,2];
console.log([].concat(arr1,[3,4]));//[1,2,3,4]
console.log(arr1[Symbol.isConcatSpreadable]);//默认的undefined

arr1[Symbol.isConcatSpreadable] = true;
console.log([].concat(arr1,[3,4]));//[1,2,3,4]
console.log(arr1[Symbol.isConcatSpreadable]);//属性值为true

arr1[Symbol.isConcatSpreadable] = false;
console.log([].concat(arr1,[3,4]));
//此时的结果变成了[Array(2), 3, 4]
//展开后是[[1, 2, Symbol(Symbol.isConcatSpreadable): false],3,4]
//这里的Symbol(Symbol.isConcatSpreadable): false]不是一个元素,而是一个属性
console.log(arr1[Symbol.isConcatSpreadable]);//false
  • Symbol.asyncIterator 符号指定了一个对象的默认异步迭代器。如果一个对象设置了这个属性,它就是异步可迭代对象,可用于for await...of循环。
const myAsyncIterable = new Object();
myAsyncIterable[Symbol.asyncIterator] = async function*() {
    yield "hello";
    yield "async";
    yield "iteration!";
};

(async () => {
    for await (const x of myAsyncIterable) {
        console.log(x);
        // expected output:
        //    "hello"
        //    "async"
        //    "iteration!"
    }
})();
  • Symbol.iterator 为每一个对象定义了默认的迭代器。该迭代器可以被 for...of循环使用。
const iterable1 = {};
iterable1[Symbol.iterator] = function* () {
  yield 1;
  yield 2;
  yield 3;
};
console.log([...iterable1]);
// expected output: Array [1, 2, 3]
  • Symbol.match 指定了匹配的是正则表达式而不是字符串。String.prototype.match()方法会调用此函数。
const regexp1 = /foo/;
// console.log('/foo/'.startsWith(regexp1)); //不能是正则表达式
// expected output (Chrome): Error: First argument to String.prototype.startsWith must not be a regular expression
// expected output (Firefox): Error: Invalid type: first can't be a Regular Expression
// expected output (Safari): Error: Argument to String.prototype.startsWith cannot be a RegExp

regexp1[Symbol.match] = false;//匹配的不是正则表达式而是字符串

console.log('/foo/'.startsWith(regexp1));
// expected output: true

console.log('/baz/'.endsWith(regexp1));
// expected output: false
  • Symbol.species 是个函数值属性,其被构造函数用以创建派生对象。
class Arr extends Array { };
const d1 = new Arr()
console.log(d1.concat([]) instanceof Arr); // true
console.log(d1 instanceof Array); // true

class Arr1 extends Array {
  static get [Symbol.species]() {
    return Array;
  }
};
const d2 = new Arr1()
console.log(d2.concat([]) instanceof Arr1); // false
console.log(d2 instanceof Array); // true
  • Symbol.toPrimitive 是内置的 symbol 属性,其指定了一种接受首选类型并返回对象原始值的表示的方法。它被所有的强类型转换制算法优先调用。
const object1 = {
  [Symbol.toPrimitive](hint) {
    if (hint === 'number') {
      return 42;
    }
    return null;
  }
};
console.log(+object1);
// expected output: 42
  • Symbol.toStringTag属性可以是一个字符串也可以是一个存取器get方法,当对象调用toString方法时,会返回[object 返回值]
let obj = {
    //属性值为存取器get方法
  get [Symbol.toStringTag](){
    return 'aaa';
  }
};
console.log(obj.toString());
//打印[object aaa]

let obj2 = {
    //字符串属性值
  [Symbol.toStringTag]:'bbb'
}
console.log(obj2.toString());
//打印[object bbb]
  • Symbol.unscopables对象的该属性指向一个对象,可以控制这个对象的属性是否被with环境过滤。
const obj={
  a:111,
  b:222,
  c:333,
}
obj[Symbol.unscopables]={
  a:true,
  b:false
}
with(obj){
  // console.log(a);
    //因为对a设置为了true,所以a属性会被with环境过滤掉,不能通过with访问,会报错
  console.log(b);//222
  console.log(c);//333
}
console.log(obj[Symbol.unscopables]);
//{a: true, b: false}