ES2015 introduces some language features that developers have long expected, but also some little-known features that have not been obvious, such as Symbol.
Symbol is a new primitive data type, a unique tag that is guaranteed to not conflict with other Symbols. In this sense, you can think of Symbol as a kind of UUID (a universal unique identifier). Let's see how Symbol works and what we can do with it.
Key points
Create a new Symbol
Creating a new Symbol is very simple, just call the Symbol function. Note that this is just a standard function, not an object constructor. Trying to call it with the new operator results in a TypeError. Each time you call the Symbol function, you get a new and completely unique value.
const foo = Symbol(); const bar = Symbol(); foo === bar // false
You can also create a tagged Symbol by passing a string as the first parameter. A tag does not affect the value of Symbol, but is useful for debugging, and the tag will be displayed if the toString() method of Symbol is called. Multiple Symbols can be created with the same tags, but this has no advantage, which can lead to confusion.
let foo = Symbol('baz'); let bar = Symbol('baz'); foo === bar // false // console.log(foo); // Symbol(baz)
Purpose of Symbol
Symbol is a good replacement for strings or integers as class/module constants:
class Application { constructor(mode) { switch (mode) { case Application.DEV: // 设置开发环境的应用程序 break; case Application.PROD: // 设置生产环境的应用程序 break; default: throw new Error('无效的应用程序模式:' + mode); } } } Application.DEV = Symbol('dev'); Application.PROD = Symbol('prod'); // 使用示例 const app = new Application(Application.DEV);
Strings and integers are not unique values; for example, the number 2 or the string "development" may also be used for different purposes elsewhere in the program. Using Symbol allows us to be more confident in the provided values.
Another interesting use of Symbol is as an object attribute key. If you have ever used JavaScript objects as a hash map (association arrays in PHP terms and dictionaries in Python terms), you will be familiar with using square bracket notation to get/set properties:
const foo = Symbol(); const bar = Symbol(); foo === bar // false
Use square bracket notation, we can also use Symbol as the attribute key. There are several advantages to doing this. First, you can be sure that Symbol-based keys never conflict, unlike string keys that may conflict with existing properties or methods of the object. Secondly, they are not enumerated in the for...in loop and are ignored by functions such as Object.keys(), Object.getOwnPropertyNames(), and JSON.stringify(). This makes them ideal for properties you don't want to include when serializing objects.
let foo = Symbol('baz'); let bar = Symbol('baz'); foo === bar // false // console.log(foo); // Symbol(baz)
However, it is worth noting that using Symbol as a key does not guarantee privacy. There are new tools available to allow you to access Symbol-based property keys. Object.getOwnPropertySymbols() returns an array of any Symbol-based keys, while Reflect.ownKeys() returns an array of all keys, including Symbol.
class Application { constructor(mode) { switch (mode) { case Application.DEV: // 设置开发环境的应用程序 break; case Application.PROD: // 设置生产环境的应用程序 break; default: throw new Error('无效的应用程序模式:' + mode); } } } Application.DEV = Symbol('dev'); Application.PROD = Symbol('prod'); // 使用示例 const app = new Application(Application.DEV);
Public Symbol
Symbol key properties are actually invisible to code before ES6, they are ideal for adding new features to existing types of JavaScript without breaking backward compatibility. The so-called "public" Symbol is a predefined property of the Symbol function that is used to customize the behavior of certain language features and to implement new functions such as iterators.
Symbol.iterator is a public Symbol used to assign a special method to an object that allows iteration:
const data = []; data['name'] = 'Ted Mosby'; data['nickname'] = 'Teddy Westside'; data['city'] = 'New York';
Built-in types String, Array, TypedArray, Map, and Set have a default Symbol.iterator method that is called when using instances of these types in a for...of loop or when using extension operators. . Browsers have also started using the Symbol.iterator key to allow iterating over DOM structures (such as NodeList and HTMLCollection) in the same way.
Global Registration
Thespecification also defines a runtime-wide Symbol registry, meaning you can store and retrieve Symbols in different execution contexts, such as between a document and an embedded iframe or Service Worker.
Symbol.for(key) Retrieves the Symbol for the given key from the registry. If the key does not exist Symbol, a new Symbol is returned. As you might expect, subsequent calls to the same key will return the same Symbol.
Symbol.keyFor(symbol) allows you to retrieve the keys for a given Symbol. Calling the method with Symbol that does not exist in the registry will return undefined:
const user = {}; const email = Symbol(); user.name = 'Fred'; user.age = 30; user[email] = 'fred@example.com'; Object.keys(user); // ['name', 'age'] Object.getOwnPropertyNames(user); // ['name', 'age'] JSON.stringify(user); // {"name":"Fred","age":30}
User case
In some use cases, using Symbol can provide advantages. One use case that has been mentioned in the previous article is when you want to add a "hidden" property to an object that will not be included when the object is serialized.
Library authors can also use Symbol to safely add properties or methods to client objects without worrying about overwriting existing keys (or their keys are overwritten by other code). For example, widget components (such as date selectors) are often initialized using various options and need to be stored in a state somewhere. It is not ideal to assign a widget instance to a DOM element object because the property may conflict with another key. Using Symbol-based keys can cleverly circumvent this problem and ensure that your Widget instance is not overwritten. For a more detailed look at the Mozilla Hacks blog post ES6 in Depth: Symbols.
Browser support
If you want to experiment with Symbol, the support for mainstream browsers is quite good. As you can see, current versions of Chrome, Firefox, Microsoft Edge, and Opera all support the Symbol type natively, as well as Android 5.1 and iOS 9 on mobile devices. If you need to support older browsers, you can also use polyfill.
Conclusion
While the main reason for introducing Symbol seems to be to facilitate adding new features to the language without breaking existing code, they do have some interesting uses. All developers should at least have a basic understanding of them and be familiar with the most commonly used public Symbols and their uses.
FAQs about ES6 Symbol
ES6 Symbol is a new primitive data type introduced in ES6 (ECMAScript 6). They are unique and immutable data types that can be used as identifiers for object properties. They can be used to create private properties for objects, implement meta-level programming concepts, and avoid naming conflicts. They can also be used to define custom iterative behavior for objects.
You can use the Symbol() function to create a new Symbol. This function returns a unique Symbol every time it is called, even if you pass the same argument to it. For example, let symbol1 = Symbol('symbol'); let symbol2 = Symbol('symbol');
Here, symbol1 and symbol2 are different Symbols, even if the same parameter "symbol" is passed to the Symbol() function.
You can use Symbol in square brackets as the object key. For example, let symbol = Symbol('key'); let obj = {}; obj[symbol] = 'value';
Here, Symbol "symbol" is used as a key in object "obj".
The global Symbol registry is a shared environment where you can create, access, and share Symbols across different realms such as iframes or Service Workers. You can create a Symbol in the global registry using Symbol.for(key) and access it using Symbol.keyFor(symbol).
You can use Symbol with objects to create unique keys. This is useful for avoiding naming conflicts, because Symbol is always unique. For example, let symbol = Symbol('key'); let obj = { [symbol]: 'value' };
Here, Symbol "symbol" is used as a key in object "obj".
Yes, you can convert Symbol to a string by calling the toString() method on it. This returns a string in the format "Symbol(description)", where "description" is an optional description you pass to the Symbol() function.
Yes, you can use Symbol with arrays. For example, you can use Symbol as the unique attribute key to store metadata about an array. However, Symbol is not included in the length property of the array, and most array methods do not return them.
Yes, you can use Symbol with functions. For example, you can use Symbol as the unique attribute key to store metadata about a function. However, Symbol is not included in the function's length property, and most function methods do not return them.
Yes, you can use Symbol with classes. For example, you can use Symbol as the unique attribute key to store metadata about a class. However, Symbol is not included in the class's length property, and most class methods do not return them.
Yes, you can use Symbol with strings. For example, you can use Symbol as the unique attribute key to store metadata about a string. However, Symbol is not included in the string's length property, and most string methods do not return them.
The above is the detailed content of ES6 in Action: Symbols and Their Uses. For more information, please follow other related articles on the PHP Chinese website!