ES6 新增了一种原始数据类型 Symbol,可以创建一个全局唯一的值。Symbol 作为对象属性的 key,可以保证不会和其他属性名冲突。它的使用方法和意义都值得深入学习和探讨。
1. Symbol 的创建和使用
要创建一个 Symbol,只需要调用全局的 Symbol 函数即可:
const mySymbol = Symbol(); console.log(mySymbol); // Symbol()
由于每个 Symbol 都是全局唯一的,因此每次创建的 Symbol 都不同:
const mySymbol1 = Symbol(); const mySymbol2 = Symbol(); console.log(mySymbol1 === mySymbol2); // false
Symbol 也可以接受一个参数,作为 Symbol 的描述,方便调试和识别:
const mySymbol = Symbol("my description"); console.log(mySymbol.toString()); // "Symbol(my description)"
Symbol 作为对象属性的 key,可以保证不会和其他属性名冲突。下面是一个示例:
const obj = { [Symbol("mySymbol")]: "value1", prop2: "value2" }; console.log(obj); // {Symbol(mySymbol): "value1", prop2: "value2"} console.log(obj.prop2); // "value2" console.log(obj[Symbol("mySymbol")]); // undefined
可以看到,Symbol(mySymbol) 这个属性名不会被其他属性名覆盖,可以用来存储一些特殊的值,避免命名冲突。
2. Symbol 的内置属性
Symbol 还提供了一些内置的属性,用来控制对象的行为。
2.1 Symbol.iterator
Symbol.iterator 用于指定一个对象的遍历器方法。遍历器方法是一个返回遍历器的函数,被 for...of 循环等语句调用。下面是一个示例:
-- -------------------- ---- ------- ----- --- - --- -- --- ----- -------- - ----------------------- ----------------------------- -- ------- -- ----- ------ ----------------------------- -- ------- -- ----- ------ ----------------------------- -- ------- -- ----- ------ ----------------------------- -- ------- ---------- ----- ----- --- ------ ---- -- ---- - ------------------ - -- - -- - -- -
上面的代码中,arrSymbol.iterator 返回一个遍历器对象 iterator,它具有 next 方法,每次调用返回一个遍历元素的对象。通过 for...of 语句也可以遍历数组,相当于调用 arrSymbol.iterator。
2.2 Symbol.species
Symbol.species 用于指定对象的构造函数。在创建 object 对象的子类时,可以指定 Symbol.species 为构造函数,这样在创建子类实例时,会使用指定的构造函数。下面是一个示例:
-- -------------------- ---- ------- ----- ------- ------- ----- - ------ --- ------------------ - ------ ------ - - ----- --- - --- ---------- -- --- ------------------------- -- --- -- -- ----------------------------- -- -----
上面的代码中,MyArray 类继承了 Array 类,并且重写了 slice 方法,返回一个 MyArray 实例。但是,指定了 Symbol.species 为 Array 类,因此使用 slice 方法返回的实例也是 Array 类型。
3. Symbol 的应用场景
Symbol 的应用场景非常广泛,下面列举几个常用的应用场景。
3.1 避免命名冲突
Symbol 可以作为对象属性的 key,避免了命名冲突的问题。下面是一个示例:
-- -------------------- ---- ------- ----- ----- - - ---- -------------- ------ ---------------- ----- -------------- -- -------- ------------- ------ - ---------- - ----- - ----- --- - --- ------------- ----------- ----------------- -- ------------- ----- ------------- ------- ----------------- -- ------------- ----- ---- -----
上面的代码中,color 对象使用 Symbol 定义了三种颜色,setColor 函数可以将任何对象的颜色设置为这三种颜色之一。由于颜色是用 Symbol 定义的,因此不会和其他属性名冲突。
3.2 定义常量
Symbol 还可以作为常量的定义。由于每个 Symbol 是全局唯一的,因此可以用 Symbol 定义一个常量:
-- -------------------- ---- ------- ----- -------- - ---------- ----- -------- -------- ------- - -- ---- --- --------- - ---------------- -- -- ----- -------- - ---- - ---------------- -- --- -- ----- -------- - - ------------ -------------
上面的代码中,MY_CONST 作为一个常量的定义,传给 fn 函数时,可以比较 arg 是否等于 MY_CONST 来实现一些特殊的逻辑。
3.3 扩展内置对象
Symbol 还可以用来扩展内置对象的方法。下面是一个示例:
-- -------------------- ---- ------- --------------------------------- - ---------- - --- - - -- ------ - ----- -- -- -- ------ ----------------- ----- - - ----------- -- -- -- --- ------ ---- -- -------- - ------------------ - -- --- -- --- -- --- -- --- -- ---
上面的代码中,使用 Symbol 扩展 String 类型的遍历方法,并使用 for...of 循环遍历字符串的每一个字符。
4. 总结
Symbol 是 ES6 中新增的原始数据类型,创建的每个 Symbol 都是全局唯一的。Symbol 可以作为对象的属性名,避免了命名冲突的问题;还可以作为常量的定义、内置对象的扩展等。Symbol 的内置属性还可以用来控制对象的行为,如遍历方法、构造函数等。掌握 Symbol 的使用方法,可以提高代码的可读性和扩展性。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/648d000248841e9894b4b361