Appearance
Symbols
symbols诞生的背景是自ECMAScript 2015起,symbol成为了一种新的原生类型,就像number和string一样。
在 JavaScript(以及 TypeScript,因为 TypeScript 是 JavaScript 的超集)中,Symbol 是一种原始数据类型,它代表独一无二的值。Symbol 用于创建对象的属性名,这些属性名是唯一的,不会被其他代码无意中覆盖或修改。
Symbols有哪些特征
使用Symbols要牢记这些特点,正式因为这些特点,是的Symbol有了存在的意义, Symbol 的主要特点包括: 唯一性:每个 Symbol 值都是唯一的。
不可枚举:Symbol 属性不会出现在对象的常规 for...in 循环中,也不会被 Object.keys() 或 Object.getOwnPropertyNames() 方法枚举。 不可改变:Symbol 属性的值是不可改变的,不能被修改。 描述字符串:创建 Symbol 时可以提供一个描述字符串,用于在调试时识别 Symbol。
创建
symbol类型的值是通过Symbol构造函数创建的。
ts
let sym1 = Symbol();
let sym2 = Symbol("key"); // 可选的字符串key
Symbol一点创建就是不可变的,而且是唯一的
ts
let sym2 = Symbol("key");
let sym3 = Symbol("key");
sym2 === sym3; // false, symbols是唯一的
在 TypeScript 中,Symbol
的用途与 JavaScript 中相同,但由于 TypeScript 提供了类型系统和编译时检查,因此在使用 Symbol
时可以获得更多的类型安全保证。以下是 Symbol
在 TypeScript 中的一些常见用途:
- 作为对象属性的键:使用
Symbol
作为对象属性的键可以确保属性名不会与对象的其他属性发生冲突。
typescript
const firstName = Symbol('firstName');
const person = {
[firstName]: 'John'
};
console.log(person[firstName]); // John
- 定义元数据属性:
Symbol
可以用于定义一些不应该被直接访问的元数据属性,例如,用于调试或内部逻辑的属性。
typescript
const debugMode = Symbol('debugMode');
class MyClass {
[debugMode]: boolean;
constructor(debug: boolean) {
this[debugMode] = debug;
}
log(message: string) {
if (this[debugMode]) {
console.log(message);
}
}
}
const instance = new MyClass(true);
instance.log('Debugging is enabled');
- 扩展内置对象:使用
Symbol
可以安全地扩展内置对象,如Array
、Object
等,而不会覆盖已有的方法或属性。
typescript
const myMethod = Symbol('myMethod');
Array.prototype[myMethod] = function() {
// 扩展数组原型的方法
};
const array = [1, 2, 3];
array[myMethod](); // 调用扩展的方法
- 迭代器和生成器:在实现自定义迭代器或生成器时,可以使用
Symbol.iterator
和Symbol.asyncIterator
作为对象的键。
typescript
const iterable = {
[Symbol.iterator]: function* () {
yield 1;
yield 2;
yield 3;
}
};
for (const value of iterable) {
console.log(value);
}
- 元编程:在元编程中,
Symbol
可以用于定义一些特殊的元属性,例如Symbol.toStringTag
,它用于自定义对象的Object.prototype.toString.call()
方法的返回值。
typescript
const myObject = {
[Symbol.toStringTag]: 'MyObject'
};
console.log(Object.prototype.toString.call(myObject)); // [object MyObject]
- 类型安全的
Symbol
:在 TypeScript 中,可以使用unique symbol
类型来创建类型安全的Symbol
,确保每个unique symbol
都是独一无二的。
typescript
const mySymbol = Symbol() as unique symbol;
// 使用类型断言创建一个 unique symbol
const anotherSymbol = Symbol() as unique symbol;
// mySymbol 和 anotherSymbol 是不同类型的 unique symbol
使用 Symbol
在 TypeScript 中可以提供更安全、更可靠的代码,尤其是在处理大型项目和多人协作时。通过避免命名冲突和提高代码的可读性,Symbol
成为了一个非常有用的特性。
Symbol的成员和使用实例
TypeScript 中的 Symbol
是 JavaScript Symbol
的类型版本,它们在 TypeScript 中没有特殊的“默认成员”的概念。然而,JavaScript 有一系列内置的 Symbol
值,这些值在 TypeScript 中也被广泛使用。这些内置的 Symbol
值通常用于元编程,即编写影响程序本身行为的代码。以下是 JavaScript(和 TypeScript)中一些重要的内置 Symbol
值及其作用:
- Symbol.iterator
- 作用:定义对象的默认迭代器。当对象被用于
for...of
循环时,会调用这个方法。
- 作用:定义对象的默认迭代器。当对象被用于
typescript
const iterable = {
[Symbol.iterator]: function* () {
yield 1;
yield 2;
yield 3;
}
};
for (const value of iterable) {
console.log(value); // 1, 2, 3
}
- Symbol.asyncIterator
- 作用:定义对象的异步迭代器。用于
for await...of
循环,允许异步迭代对象。
- 作用:定义对象的异步迭代器。用于
typescript
const asyncIterable = {
[Symbol.asyncIterator]: async function* () {
yield 1;
yield 2;
yield 3;
}
};
for await (const value of asyncIterable) {
console.log(value); // 1, 2, 3
}
- Symbol.toStringTag
- 作用:用于自定义对象的
Object.prototype.toString.call()
方法的返回值。
- 作用:用于自定义对象的
typescript
const myObject = {
[Symbol.toStringTag]: 'MyObject'
};
console.log(Object.prototype.toString.call(myObject)); // [object MyObject]
- Symbol.hasInstance
- 作用:用于确定一个对象是否是某个构造函数的实例。这是
instanceof
操作符的钩子。
- 作用:用于确定一个对象是否是某个构造函数的实例。这是
typescript
class MyClass {
static [Symbol.hasInstance](instance) {
return false;
}
}
const obj = new MyClass();
console.log(obj instanceof MyClass); // false
- Symbol.isConcatSpreadable
- 作用:一个布尔值,指示对象是否应该被
Array.prototype.concat
方法展开其数组元素。
- 作用:一个布尔值,指示对象是否应该被
typescript
const arrayLike = {
length: 2,
0: 'a',
1: 'b',
[Symbol.isConcatSpreadable]: true
};
console.log(['x', 'y'].concat(arrayLike)); // ['x', 'y', 'a', 'b']
- Symbol.unscopables
- 作用:一个对象,其属性指示哪些属性不应该被
with
语句包含。
- 作用:一个对象,其属性指示哪些属性不应该被
typescript
Array.prototype[Symbol.unscopables] = {
copyWithin: true,
entries: true,
fill: true,
find: true,
findIndex: true,
// ... 更多属性
};
with (Array.prototype) {
copyWithin; // undefined
}
- Symbol.match
- 作用:用于定义一个正则表达式的匹配行为。
typescript
const regex = /hello/;
regex[Symbol.match] = function() {
return ['world'];
};
console.log('hello world'.match(regex)); // ['world']
- Symbol.replace
- 作用:用于定义一个正则表达式的替换行为。
typescript
const regex = /hello/;
regex[Symbol.replace] = function() {
return 'world';
};
console.log('hello world'.replace(regex)); // 'world world'
- Symbol.search
- 作用:用于定义一个正则表达式的搜索行为。
typescript
const regex = /hello/;
regex[Symbol.search] = function() {
return 6;
};
console.log('hello world'.search(regex)); // 6
- Symbol.split
- 作用:用于定义一个正则表达式的分割行为。
typescript
const regex = /hello/;
regex[Symbol.split] = function() {
return ['world'];
};
console.log('hello world'.split(regex)); // ['world']
这些内置的 Symbol
值在 TypeScript 中同样适用,并且 TypeScript 会提供对这些特殊方法的类型检查。这些 Symbol
值的使用使得开发者可以更精细地控制对象的行为,特别是在涉及到迭代、正则表达式和元编程的场景中。