1. Introduction
Typesymbol
is a basic data type newly introduced by ES6, which has static properties and static methods. Among them, static properties expose several built-in member objects, and static methods expose global symbol
registration.
Typessymbol
have the following characteristics: ① Uniqueness: each symbol
value is unique; ② Immutability: symbol
the value cannot be modified; ③ Attribute identifier: the symbol
value of the type can be used as the identifier of the object attribute key
; ④Symbol can be used with other data Types can be operated on but cannot be cast to other data types. Using the first two features, you can avoid property name conflicts and ensure that properties are not accidentally overwritten.
Typessymbol
are widely used in many libraries and frameworks. Common application scenarios include creating private properties, defining constants, defining event names, and implementing various identifier-related functions.
2. Create
1、Symbol([description])
Symbol([description])
The value of the type is created through the function symbol
, but it will not be added to the global symbol table. The optional parameter description
is string type data, which represents the current symbol
description. This parameter is only used as an identifier and will not affect symbol
it . Uniqueness.
But this function is not a constructor, because this function does not support new Symbol()
the syntax, and an error will be thrown if this syntax is used TypeError
. Each value of the type Symbol()
obtained through the function symbol
is unique and unique. Even if two symbol
have the same value description
, they belong to two different values.
// 创建symbol数据
let s = Symbol();
console.log(s); // Symbol()
console.log(typeof s); // symbol
// 创建symbol数据并添加描述
let s1 = Symbol('one');
console.log(s1); // Symbol(one)
console.log(typeof s1); // symbol
// 创建symbol数据并添加相同的描述
let s2 = Symbol('one');
console.log(s2); // Symbol(one)
console.log(typeof s2); // symbol
// 判断symbol数据是否相等
console.log(s1 === s2); // false
console.log(s1 == s2); // false
// 使用new关键字创建symbol数据
let s3 = new Symbol(); // Uncaught TypeError: Symbol is not a constructor
2、Symbol.for(key)
The fourth part is explained in the common method chapter.
3. Common attributes
1. description (read-only)
This property is a read-only property used to get symbol
the description string of the current value.
Case code:
// 创建symbol数据 不添加描述
let s = Symbol();
// 创建symbol数据并添加描述
let s1 = Symbol('one');
// 使用description输出symbol数据的描述
console.log(s.description); // undefined
console.log(s1.description); // one
2、hasInstance
This attribute is Symbol
a built-in static attribute of the type. The attribute value is a Symbol value, which is immutable and is used to define the @@hasInstance
key of the object's method. @@hasInstance
The method is used to determine whether an object is an instance of a certain constructor. We can Use this attribute to customize instanceof
the behavior of an operator on a class.
When an object's prototype chain is checked using instanceof
the operator, the object's @@hasInstance
method is called. In other words, obj instanceof Constructor
it is actually called Constructor[Symbol.hasInstance](obj)
. Therefore, we can use a custom @@hasInstance
method to customize whether the object is an instance of a certain constructor.
Case code:
class MyArray {
static [Symbol.hasInstance](instance) {
return Array.isArray(instance);
}
}
console.log([] instanceof MyArray); // true
console.log({
} instanceof MyArray); // fales
3、isConcatSpreadable
This property is Symbol
a built-in static property of the type. The property value is a Symbol value, which is immutable and is used to define @@isConcatSpreadable
the key of the object. @@isConcatSpreadable
method is an internal Symbol that determines concat()
whether the object expands its elements when the array's method is called.
If @@isConcatSpreadable
returns true
(default value), the object elements are expanded and merged; if the method returns false
, the object is added to the array as a single element to form a multi-dimensional array. We can @@isConcatSpreadable
customize the object 's concat()
expansion behavior in the method by setting the object's
Case code:
let arr1 = [1, 2, 3]
let arr2 = ['a', 'b', 'c']
// 默认为true 进行展开合并
console.log(arr1.concat(arr2)); // [1, 2, 3, 'a', 'b', 'c']
// 设置arr2 的值为false
arr2[Symbol.isConcatSpreadable] = false
// 再次合并 此时不会展开
console.log(arr1.concat(arr2)); // [1, 2, 3, ['a', 'b', 'c']]
4、iterator
IsSymbol.iterator
a built-in static property of the Symbol type. The property value is a Symbol value used to define the default iterator of the object @@iterator
. @@iterator
method is a special internal method that returns an iterator object.
When an object is traversed using for...of
a loop or the spread operator ( ), the object's method is called to obtain an iterator object. An iterator object allows you to access each element of the object in turn by calling its method. We can implement custom iterator behavior through custom methods. Custom methods should return an iterator object with methods. Each time the method is called, the iterator object should return an object containing the and properties, indicating the value of the current iteration and indicating whether the iteration has ended....
@@iterator
next()
@@iterator
@@iterator
next()
next()
value
done
value
done
Case code:
let arr3 = [1, 2, 3]
// for..of..形式遍历
console.log('for..of..形式遍历');
for (const item of arr3) {
console.log(item);
}
// ... 扩展运算符形式遍历
console.log('扩展运算符形式遍历');
console.log([...arr3]);
// 自定义默认迭代器
arr3[Symbol.iterator] = function () {
let index = 0;
return {
next: function () {
if (index < arr3.length) {
return {
value: arr3[index++] * 3, done: false };
} else {
return {
value: undefined, done: true };
}
}
};
};
// 输出数组本身
console.log('输出数组本身');
console.log(arr3);
// for..of..形式遍历
console.log('for..of..形式遍历');
for (const item of arr3) {
console.log(item);
}
// ... 扩展运算符形式遍历
console.log('扩展运算符形式遍历');
console.log([...arr3]);
// forEach 形式遍历
console.log(' forEach 形式遍历');
arr3.forEach(item => {
console.log(item);
});
// for 形式遍历
console.log('for 形式遍历');
for (let i = 0; i < arr3.length; i++) {
console.log(arr3[i]);
}
Results of the:
5、toPrimitive
IsSymbol.toPrimitive
a built-in static property of the Symbol type, used to define @@toPrimitive
the key of the object's conversion method. @@toPrimitive
The conversion method is an internal method used to convert an object to a primitive value. It accepts a parameter hint
indicating the expected conversion type. hint
The parameter can be one of three values:
"default"
: Indicates that the object can be converted to a primitive value of any type, for example:"" + x
(forced to a primitive value , not a string)."number"
: Indicates that the object is expected to be converted to a primitive value of numeric type, for example: arithmetic operation (+-*/
)."string"
: Indicates that the object is expected to be converted to a primitive value of string type, such as template string (${}
),String()
etc.
The value of the parameter hint
is determined by many complex factors such as context and operation needs, such as: calling the operator of the object, implicit type conversion, valueOf
and toString
methods, etc.
When an object is used in a context that requires primitive values, such as arithmetic operations or string concatenation, the JavaScript engine first looks for the object's Symbol.toPrimitive
properties. If the attribute exists and is a function, the engine will call the function and pass in the corresponding hint
parameters to convert and obtain the original value of the object, that is, a string, number, or Boolean value. We can customize the conversion behavior of the object through custom @@toPrimitive
methods, fully control the original conversion process, and return the original value of the object.
Case code:
// 一个没有提供 Symbol.toPrimitive 属性的对象
const obj1 = {
};
console.log(+obj1); // NaN
console.log(`${
obj1}`); // "[object Object]"
console.log(obj1 + ""); // "[object Object]"
// 接下面声明一个对象,手动赋予了 Symbol.toPrimitive 属性
const obj2 = {
};
obj2[Symbol.toPrimitive] = function (hint) {
// hint 参数值是 "number"
if (hint === "number") {
// 返回对象有多少条属性
return Object.keys(obj2).length;
}
// hint 参数值是 "string"
if (hint === "string") {
// 返回对象转换成的JSON字符串
return JSON.stringify(obj2);
}
// hint 参数值是 "default"
return true;
};
console.log(+obj2); // 0
console.log(`${
obj2}`); // "{}"
console.log(obj2 + ""); // "true"
6, match, replace, search, toStringTag and other attributes
Please understand yourself. . .
4. Commonly used methods
1、for()
The methodSymbol.for(key)
will key
search for the corresponding value from all declared global symbol data according to the parameters (excluding Symbol()
data created through creation). If this value exists, it will return it; if it does not exist, it will create a new global symbol data key
based on this. description
, and return the created data.
If you create data based Symbol()
on this first , and then use this method to search, it will not be found, because this method only searches in global data, and creates non-global data.key
description
symbol
Symbol()
// 第一次使用for()方法 由于之前不存在以foo为key的symbol 所以创建一个 symbol 并放入 symbol 注册表中,键为 "foo"
const a = Symbol.for("aaa");
// 第二次使用for()方法 由于之前注册过 所以直接从 symbol 注册表中读取键为"foo"的 symbol
const b = Symbol.for("aaa");
// 验证两者是否为同一个symbol
console.log(a === b); // true
// 如果是通过Symbol()方法创建 则会创建两个key相同的symbol 但并不是同一个symbol
const c = Symbol("bbb");
const d = Symbol("bbb");
// 验证两者是否为同一个symbol
console.log(c === d); // false
2、keyFor()
The methodSymbol.keyFor(symbol)
will search for the data symbol
from all declared global symbol
data based on the parameters and return the data key
. If symbol
the value is found from the global data symbol
, the value symbol
of the is returned key
, and the return value is a string type; if the value does not exist symbol
or the symbol
corresponding value key
is empty, then it is returned undefined
.
If the parameter symbol
is Symbol()
the data created by the method, it will not be found, because symbol
the data created by this method is not global, and the return value is undefined
.
// 创建一个全局 Symbol 且有key
const a = Symbol.for("aaa");
console.log(Symbol.keyFor(a)); // "aaa"
// 创建一个全局 Symbol 但没有key
const b = Symbol.for();
console.log(Symbol.keyFor(b)); // undefined
// 创建一个非全局 Symbol 且有key
const c = Symbol("ccc");
// 创建一个全局的 Symbol 且有相同的key
const c2 = Symbol.for("ccc");
console.log(Symbol.keyFor(c)); // undefined
console.log(Symbol.keyFor(c2)); // "ccc"
// 验证两者是否为同一个symbol
console.log(c === c2); // false
// 下面的 原生Symbol 没有保存在全局 Symbol 注册表中
console.log(Symbol.keyFor(Symbol.iterator)); // undefined
3、toString()
The objectSymbol
has its own toString()
methods, which override Object.prototype.toString()
the methods on the prototype chain.
Symbol data cannot be implicitly converted to a string, so toString()
a method is required to convert the data into a string.
// 创建一个symbol
const a = Symbol("aaa");
console.log(a.toString()); // Symbol(aaa)
// 创建一个全局symbol
const b = Symbol.for("bbb");
console.log(b.toString()); // Symbol(bbb)
4. Other methods such as valueOf()
Please understand yourself. . .
5. Related applications
1. As the only property key of the object
CanSymbol
be used as a key for object properties to ensure key
the uniqueness of the properties and avoid accidental overwriting or conflict of properties.
// 声明一个 symbol 数据
const a = Symbol('aaa');
// 声明一个全局 symbol 数据
const b = Symbol.for('bbb')
// 声明对象 利用 symbol 数据作为 key
const obj = {
[a]: '11111111',
a: '22222222',
[b]: '33333333'
};
// 再次声明一个 symbol 数据 与 a 有相同的description
// 以该symbol作为key 修改数据 虽然声明时的 description 相同
// 但是是两个不同的 symbol 数据 所以obj[Symbol('aaa')] 与 obj[a] 是两个不同的属性
// 修改其中一个不会影响另一个
obj[Symbol('aaa')] = '44444444';
// 输出属性数据
console.log(obj[a]); // 11111111
// 此处相当于又声明了一个symbol
console.log(obj[Symbol('aaa')]); // undefined
// 再次输出对象的数据
console.log(obj);
// 可通过 symbol 数据作为 key 修改数据
// obj[a] = '44444444';
Results of the:
2. Declare a unique constant
With Symbol
the uniqueness of data, we can declare constants and ensure that the constant values are unique and cannot be accidentally modified or overwritten.
// 声明一个常量 且常量值为 symbol 数据
const a = Symbol("aaa");
// 在函数中匹配常量值
function myFunction(value) {
// 判断传入的值是否与常量值相等
if (value === a) {
console.log("常量值被匹配");
} else {
console.log("常量值未匹配");
}
}
// 传入定义的变量
myFunction(a); // 输出 "常量值被匹配"
// 传入一个新的 symbol 数据 且 description 与常量值相同
myFunction(Symbol("aaa")); // 输出 "常量值未匹配"
3. Rewrite the built-in method of the object
By utilizing Symbols and built-in properties, we can rewrite the object's built-in methods to adapt to specific business scenarios and customize the object's behavior. However, when rewriting built-in methods, you must not break the original language specifications and the expected behavior of other codes.
// 声明一个对象 并改写其内置toString方法的返回值
const myObj = {
// 该Symbol的内置属性 决定了toString方法的返回值
[Symbol.toStringTag]: "MyObject",
};
// 输出对象的toString方法的返回值
console.log(Object.prototype.toString.call(myObj)); // 输出 "[object MyObject]"
4. Define the private members of the class
Symbol
An identifier that can be used
// 定义一个symbol数据
const _privateMember = Symbol("private");
// 定义一个类
class MyClass {
constructor() {
// 定义类的私有成员 以symbol数据作为标识符
this[_privateMember] = "私有成员";
}
// 私有成员的get方法
getPrivateMember() {
return this[_privateMember];
}
}
// new 一个实体对象
const instance = new MyClass();
// 通过get方法正常访问
console.log(instance.getPrivateMember()); // 输出 "私有成员"
// 直接访问 无法访问
console.log(instance[_privateMember]); // 输出 undefined