javascript 符号_JavaScript“符号”简介及其在元编程中的使用

javascript 符号

JavaScript中的元编程 (Metaprogramming in JavaScript)

What are the primitive data types in JavaScript? Well, they are null, undefined, string, number and boolean. Do we need more? Yes. The symbol is a new primitive data type introduced in ES2015 (ES6) along with bigint which was also introduced in this revision.

JavaScript中的原始数据类型是什么? 好吧,它们是nullundefinedstringnumberboolean 。 我们需要更多吗? 是的 。 该symbol是在ES2015( ES6 )中引入的新原始数据类型 ,在本修订版中也引入了bigint

typeof null;      // 'object' (it's a bug)
typeof undefined; // 'undefined'
typeof 100; // 'number'
typeof "hello"; // 'string'
typeof true; // 'boolean'
typeof Symbol(); // 'symbol'
typeof 100n; // 'bigint'

In this lesson, we are just going to talk about symbols and leave others for another day. Symbols are fascinating and not like any other data type you have seen before. For the starters, the symbol is a primitive data type, however, you can’t write it in literal form because it doesn’t have one.

在本课中,我们将讨论符号并将其他符号留给别人。 符号令人着迷,并且与您之前见过的任何其他数据类型都不一样。 对于初学者来说,该符号是一种原始数据类型,但是您不能以文字形式编写它,因为它没有一个。

var sym = Symbol(description);

To create a symbol, you need to call the Symbol function as shown above. This function always returns a unique symbol value. The internal implementation of a symbol is up to the implementer (JavaScript engine) but it is neither a string, number, or a boolean value. Let’s see how it looks like.

要创建符号,您需要如上所示调用Symbol函数。 此函数始终返回唯一的符号值。 符号的内部实现取决于实现者( JavaScript引擎 ),但是它既不是stringnumber也不是boolean值。 让我们看看它的样子。

Image for post
symbols/constructor.jssymbols / constructor.js

The Symbol constructor always returns a new symbol. It accepts description argument which is used as a debugging aid while logging a symbol to the console and it shouldn’t be confused with the actual value of the symbol.

Symbol构造函数始终返回一个新符号。 它接受description参数,该参数在将符号记录到控制台时用作调试辅助 ,请勿将其与符号的实际值混淆。

Two symbols can’t have the same value if created from the Symbol() call since every Symbol() call, with or without a description, always returns a new symbol with its own unique value. Therefore a symbol can only be equal to itself.

如果从Symbol()调用中创建两个符号,则它们不能具有相同的值,因为每个Symbol()调用(带有或不带有描述)总是返回一个具有其唯一值的新符号。 因此,符号只能等于其自身。

Since symbol values are unique and not visible to the runtime, they cannot be represented in a literal form as you would normally do with strings or numbers. Hence there isn’t a magic syntax like var sym = #$@%#*#; that would make a symbol. You need to use Symbol() function call.

由于符号值是唯一的,并且对于运行时不可见,因此它们不能像通常使用字符串或数字那样以文字形式表示。 因此,没有像var sym = #$@%#*#;这样的魔术语法var sym = #$@%#*#; 那将成为一个象征。 您需要使用Symbol()函数调用。

💡 The Symbol function, unlike any other function, isn’t constructible which means the expression new Symbol() will throw with TypeError: Symbol is not a constructor error however it does provide static methods as we will see later.

💡的 Symbol功能,不同于其他任何功能,是不是constructible,这意味着表达new Symbol()将抛出TypeError: Symbol is not a constructor错误但它确实提供静态方法,我们将在后面看到。

A symbol is allowed to be used as an object’s key. Since a symbol is not a string and it doesn’t have a literal form, we need to use the square-bracket notation ([]) as you would use with a variable that contains a string.

允许将符号用作对象的键。 由于符号不是string ,也不具有文字形式,因此我们需要使用方括号符号( [] ),就像使用包含string的变量一样。

Image for post
symbols/object-keys.jssymbols / object-keys.js

In the above example, we have created sym symbol to represent the salary of the person object. The only way can get and set (or even delete) the value represented by a property name of the type symbol is by using the original symbol value (stored in a variable) and the [] notation.

在上面的示例中,我们创建了sym符号来表示person对象的薪水。 获取设置 ( 或什至 删除 )类型symbol的属性名称所表示的值的唯一方法是使用原始符号值( 存储在变量中 )和[]表示法。

If you ever lost the symbol value which represents a property in the object, it would be really tough to access its value in the object again. As you can see, using [Symbol()] syntax isn’t a wise solution because now you do not have access to the symbol that represents the property.

如果您丢失了表示对象中某个属性的符号值,那么再次访问该对象中的值将非常困难。 如您所见,使用[ Symbol() ]语法不是一个明智的解决方案,因为现在您无权访问代表该属性的符号。

Object properties of the type symbol are not enumerable which means they do not show up in the result of Object.keys() method (own/enumerable properties) of an object and in the for-in loop (own+inherited/enumerable properties) as well as in the result of the Object.getOwnPropertyNames() method (own/enumerable+non-enumerable properties)

类型symbol对象属性不可枚举 ,这意味着它们不会显示在对象的Object.keys()方法的结果( 拥有/可枚举的属性 )和for-in循环中( 拥有+继承/可枚举的属性 )以及Object.getOwnPropertyNames()方法的结果( 拥有/枚举+不可枚举的属性 )

Image for post
symbols/non-enumerable.jssymbols / non-enumerable.js

I wouldn’t look at it as a drawback but a powerful abstraction feature. Since symbols are treated as non-enumerable properties, they can hold special meaning in the program. One must need to have the reference to the original symbol to override the value of a symbol property. This works perfectly well for a module that exposes an object with symbol property but not the symbol.

我不会将其视为缺点,而是强大的抽象功能。 由于符号被视为不可枚举的属性,因此它们在程序中可以具有特殊含义。 必须要有对原始符号的引用才能覆盖符号属性的值。 这对于暴露具有symbol属性但不包含symbol属性的模块的模块效果很好。

💡 Though symbol properties are non-enumerable, its property descriptor has enumerable set to true. This seems really weird at first but it has a reason behind it. Please read this StackOverflow thread to understand this reason.

symbol尽管符号属性不可枚举,但其属性描述符的 enumerable设置为true 。 起初这看起来确实很奇怪,但是背后有一个原因。 请阅读 StackOverflow线程以了解此原因。

However, JavaScript provides Object.getOwnPropertySymbols() method that returns the list of own properties of an object which are symbols. So do not consider symbols would act like private properties. Symbols are just hard to access but not impossible.

但是,JavaScript提供了Object.getOwnPropertySymbols()方法,该方法返回作为符号的对象自身属性的列表。 因此,不要认为符号会像私有财产一样起作用。 符号只是很难访问,但并非不可能。

Image for post
symbols/extract-symbol-props.jssymbols / extract-symbol-props.js

Oh, and one thing I didn’t tell you, every symbol has a property description that returns the description that was provided in the Symbol(description) call. If none was provided, it would be undefined. In the above example, we have used it as a hack to obtain the symbol value that was used as a property key to represent age, but this is not a clever approach.

哦,还有一件事我没有告诉你,每一个符号有一个属性description ,它返回description这是在提供的Symbol( description )调用。 如果没有提供,它将是undefined 。 在上面的示例中,我们已将其用作技巧来获取用作代表年龄的属性键的符号值但这并不是一个聪明的方法。

So far one thing is very clear to us, a symbol is nothing like a string but that may pose a problem when a string value is expected from a symbol in some contexts. For example, what if a symbol is interpolated inside a string or what if an object with symbol properties is serialized into JSON.

到目前为止,对我们来说很清楚,符号并不像string但是当在某些情况下期望符号产生string值时,这可能会带来问题。 例如,如果将符号插入string或者将具有符号属性的对象序列化为JSON,该怎么办。

Image for post
symbols/symbol-string-problems.jssymbols / symbol-string-problems.js

As you can see from the above example, JSON.stringify would simply ignore any property names that are symbols and serialize the rest of the fields without any errors. However, the operation that tries to read symbols as a string would result in TypeError.

从上面的示例可以看到, JSON. stringify JSON. stringify会简单地忽略任何符号属性名称,并序列化其余字段而不会出现任何错误。 但是,尝试将符号读取为字符串的操作将导致TypeError

💡 If you are wondering how console.log was able to display the symbol value as a string before, it’s because the console.log method calls the toString method on the symbol internally. You can also make the sym.toString() call manually which returns "Symbol(salary)" as a string.

💡如果你想知道如何console.log能够作为显示符号值string 之前 ,这是因为console.log方法调用toString的符号方法在内部。 您也可以手动进行sym.toString()调用,该调用返回"Symbol(salary)"作为字符串。

全局符号注册 (Global Symbol Registry)

I haven’t been entirely honest with you. There is a way you can access a symbol without having its reference or avoid creating unique symbols every single time. The Symbol.for(key) method returns a symbol from the global registry with the unique key, else it creates one on the fly and returns.

我对你还不完全诚实。 您可以通过一种方式来访问符号而无需引用它,或者避免每次都创建唯一的符号。 Symbol. for ( key ) Symbol. for ( key )方法从全局注册表中返回一个具有唯一key的符号,否则它会立即创建一个符号并返回。

This global registry is common for every script file, every module, and every realm such as iframe, web worker, service worker, etc. For this reason, this registry is called the runtime-wide symbol registry. So when you access Symbol.for(key) in any realm, you get the same symbol every time.

全局注册表对于每个脚本文件,每个模块以及每个领域(例如iframeWeb WorkerService Worker等)都是通用的。因此,此注册表称为运行时范围的符号注册表。 因此,当您访问Symbol. for ( key ) Symbol. for ( key )任何领域中的Symbol. for ( key ) ,您每次都会得到相同的符号。

The Symbol.keyFor(sym) method returns the key of a symbol only when a symbol is a runtime-wide symbol, else undefined is returned.

Symbol. keyFor (sym) 仅当符号是运行时范围的符号时, Symbol. keyFor (sym)方法才返回符号的key ,否则返回undefined

Image for post
symbols/runtime-wide-symbols.jssymbols / runtime-wide-symbols.js

When we create a symbol using Symbol.for(key) expression, the key becomes not only the unique identifier of the symbol but also its description which is nice as there is no other way to provide a description.

当我们使用Symbol.for( key )表达式创建符号时, key不仅成为符号的唯一标识符,而且成为其描述 ,这很好,因为没有其他方法可以提供描述。

💡 If you are looking for a function to remove a symbol from the global registry then you should give up on your quest as it doesn’t exist.

💡如果您正在寻找一个从全局注册表中删除符号的功能,那么您应该放弃它,因为它不存在。

知名符号 (Well-known Symbols)

What is the best way to create a symbol and share it across all code realms? Perhaps you would go with the Symbol.for() approach since symbols created by it are accessible across all realms. JavaScript also provides some predefined global symbols (runtime-wide) for specific use cases.

创建符号并在所有代码领域中共享它的最佳方法是什么? 也许您会使用Symbol.for()方法,因为它创建的符号可在所有领域访问。 JavaScript还为特定用例提供了一些预定义的全局符号( 运行时范围 )。

If an object property (own or inherited) has a special meaning, then using a string name for it is not such a good idea because it can be accidentally overridden as we have seen with the valueOf method of the previous lesson.

如果对象属性( 拥有或继承的 )具有特殊含义,那么使用string名称并不是一个好主意,因为正如我们在上一课valueOf方法中看到的那样,它可能被意外覆盖。

JavaScript has a lot of special inherited properties on objects such as valueOf and toString which should be overridden (but not accidentally) to provide custom object behavior. Let’s go through them once more.

JavaScript在对象上有很多特殊的继承属性,例如valueOftoString ,应重写这些属性( 但并非偶然 ),以提供自定义对象行为。 让我们再经历一次。

Image for post
symbols/special-methods.jssymbols / special-methods.js

Every object inheriting Object has the default implementation of the valueOf and the toString method since they are defined on the Object itself. The valueOf method is called when you perform an arithmetic operation on the object and toString method is called when a string representation of an object is needed.

每个继承Object都具有valueOftoString方法的默认实现,因为它们是在Object本身上定义的。 所述valueOf当在对象上执行算术运算和方法被调用toString需要的对象的字符串表示时方法被调用。

The default toString implementation returns "[object Object]" string to indicate that it is a string representation of an Object value. The default valueOf implementation returns the object itself, hence any arithmetic operations return NaN since the final result would not be a number.

默认的toString实现返回"[object Object]"字符串,以表明它是Object值的字符串表示形式。 默认的valueOf实现返回对象本身,因此任何算术运算都返回NaN因为最终结果将不是数字。

We can override these default implementation by providing a function value with the same property name either on the object itself or on its prototype chain. Therefore if you have a class, you can provide toString and valueOf instance methods to override these default behavior as shown below.

通过在对象本身或其原型链上提供具有相同属性名称函数值,可以覆盖这些默认实现。 因此,如果您有一个类,则可以提供toStringvalueOf实例方法来覆盖这些默认行为,如下所示。

Image for post
symbols/special-methods-on-class.jssymbols / special-methods-on-class.js

符号到原始 (Symbol.toPrimitive)

The problem with these special methods (properties) is that they can be easily overridden by mistake. In the case of toString and valueOf, the primitive value of the object (string or number) in certain contexts is split between these two methods and it can be confusing at times.

这些特殊方法( 属性 )的问题在于它们很容易被错误覆盖。 在toStringvalueOf的情况下,在某些情况下对象的原始值( 字符串或数字 )在这两种方法之间分配,有时会造成混淆。

To solve these issues, JavaScript provides well-known symbols to be used as special property names one of which is toPrimitive symbol. All well-known symbols are exposed to the public as static properties of Symbol object (function actually) and they are shared in all code realms.

为了解决这些问题,JavaScript提供了众所周知的符号用作特殊属性名称,其中之一是toPrimitive符号。 所有众所周知的符号都作为Symbol对象的静态属性( 实际上是函数 )公开给公众,并且它们在所有代码领域中都共享。

The Symbol.toPrimitive symbol does the job of toString and valueOf method at once and gets the preference over them. If an object has (own or inherited) method with the name Symbol.toPrimitive, it will be called with a hint indicating which primitive value of the object is demanded.

Symbol. toPrimitive Symbol. toPrimitive符号同时执行toStringvalueOf方法的工作,并获得对它们的优先选择。 如果对象具有( 自己或继承的 )名称为Symbol.toPrimitive方法,则将使用hint来调用该对象,该hint指示需要该对象的原始值。

Image for post
symbols/symbol-toPrimitive.jssymbols / symbol-toPrimitive.js

The hint argument of this method could be "number", "string" or "default" depending on what operation is performed on the object. The "default" hint is used in the case of + operator as it can be used as arithmetic add operator where number is needed or as string concatenation operator where string is needed.

此方法的hint参数可以是"number""string""default"取决于对对象执行的操作。 的"default"暗示在的情况下使用+运算符,因为它可以被用作其中算术增加操作符number需要或为其中串并置运算 string是必要的。

Symbol.toStringTag (Symbol.toStringTag)

As we have learned that addition of an object with a string value returns a weird string with format "[object Object]". This happens because the toString method implementation of the Object returns this string.

如我们所知,将对象与string值相加将返回格式为"[object Object]"的怪异字符串。 发生这种情况是因为ObjecttoString方法实现返回了此字符串。

However, this is not unique with the object (descendent of Object) only. JavaScript implements this method for most of the classes.

但是,这并非仅对于对象( Object 后代 )唯一。 JavaScript对大多数类都实现了此方法。

Image for post
symbols/objects-string-representation.jssymbols / objects-string-representation.js

💡 If you are weirded out by Undefined and Null, then don’t be. These constructor functions are not accessible to the runtime and they are purely implemented inside the JavaScript engine.

💡如果您被UndefinedNull迷惑了,那就不要。 这些构造函数无法在运行时访问,它们仅在JavaScript引擎内部实现。

Since every single value in JavaScript is derived from a constructor (class) which is why we say everything in JavaScript is an object, every class has its own implementation to return a string that describes that object. If it doesn’t, then it will use Objects implementation.

由于JavaScript中的每个值都是从构造函数( class )派生的,这就是我们说JavaScript中的所有内容都是对象的原因,因此每个类都有自己的实现以返回描述该对象的字符串。 如果没有,它将使用Objects实现。

As you can see from the above results, only the Tag part of the "[object <Tag>]" representation is changing. JavaScript gives us the power to change the value of Tag, perhaps to make things a little simple to understand.

从以上结果可以看出,只有"[object <Tag>]"表示形式的Tag部分正在更改。 JavaScript使我们能够更改Tag的值,或者使事情易于理解。

Image for post
symbols/symbol-toStringTag.jssymbols / symbol-toStringTag.js

The Symbol.toStringTab property on the object used as the Tag when toString method is executed on the object (implicitly or deliberately). You can provide this property on the object itself or on its prototype chain. If you are using a class, then you should use it as a getter.

Symbol. toStringTab 在对象上隐式或有意执行toString方法时,该对象上的Symbol. toStringTab属性用作Tag 。 您可以在对象本身或其原型链上提供此属性。 如果使用的是类,则应将其用作getter

Symbol.hasInstance (Symbol.hasInstance)

Imagine if you have two classes with some common fields. You would normally go for an inheritance pattern where a class extends another class to inherit common properties. But that’s not always available.

想象一下,如果您有两个带有某些公共字段的类。 通常,您会采用一种继承模式,其中一个类扩展了另一个类以继承公共属性。 但这并不总是可用的。

If you have a function that accepts an object and checks if that object is an instance of a specific class using the instanceof operator, then would create a a problem since even though an object might have properties of this specific class, it would not qualify this check unless it is derived from it.

如果您有一个接受对象的函数并使用instanceof运算符检查该对象是否为特定类的instanceof ,则将产生一个问题,因为即使某个对象可能具有该特定类的属性,也无法进行此检查除非它源自它。

Image for post
symbols/instanceof-problem.jssymbols / instanceof-problem.js

In the above example, since employee object is not an instance of Person class nor the Employee class inherits the Person class, the instanceof operator returns false. To solve this issue, you need to put an OR condition to check if the object is an instance of Employee class as well.

在上面的示例中,由于employee对象不是Person类的实例,也不是Employee类继承Person类,因此instanceof运算符返回false 。 要解决此问题,您需要放置一个OR条件,以检查object是否也是Employee类的实例。

But using a static method on a class with the name Symbol.hasInstance, you can override the default behavior of the instanceof operator. What you have to do is check the incoming object value and return a boolean value from within this method. Let’s see how this plays out.

但是在名称为Symbol. hasInstance的类上使用static方法Symbol. hasInstance Symbol. hasInstance ,您可以覆盖instanceof运算符的默认行为。 您要做的就是检查传入的对象值,然后从此方法中返回一个boolean值。 让我们看看如何进行。

Image for post
symbols/symbol-hasInstance.jssymbols / symbol-hasInstance.js

Whenever <LHS> instanceof Person expression is evaluated, the Person[Symbol.hasInstance] method is called with LHS operand. In the above example, we have used in operator to check if name property exists in the instance or on its prototype chain since the only criteria for an object to be an instance of Person is the existance of the name property.

每当评估<LHS> instanceof Person表达式的<LHS> instanceof PersonPerson[Symbol.hasInstance]使用LHS操作数调用Person[Symbol.hasInstance]方法。 在上面的示例中,我们使用in运算符来检查instance或其原型链中是否存在name属性,因为使对象成为Person实例的唯一标准是name属性的存在。

Symbol.isConcatSpread (Symbol.isConcatSpreadable)

You must have used [].concat() prototype method of the Array to create a new array by appending one or more items. The magical thing about concat method is that it flattens the arguments if an argument is an Array. The problem with that is you might not need that consistently.

您必须使用过[]. concat () Array []. concat ()原型方法通过附加一个或多个项目来创建新数组。 关于concat方法的神奇之处在于,如果参数是Array ,则它会展平参数。 问题在于您可能不需要始终如一的需求。

You can avoid that by putting boolean property Symbol.isConcatSpreadable on an array (instance of Array) or on its prototype. If this property exists and is set to false, the concat method will not flatten the array.

您可以通过放置boolean属性Symbol. isConcatSpreadable来避免这种情况Symbol. isConcatSpreadable 在数组( Array 实例 )或其原型上是Symbol. isConcatSpreadable 。 如果存在此属性并将其设置为false ,则concat方法将不会展平数组。

Image for post
symbols/symbol-isConcatSpreadable.jssymbols / symbol-isConcatSpread.js

In the above example, the numbers and drivers arrays are not spreadable in concat operation, therefore, they remained as array values in the newArray, however, the sports array was spread since it doesn’t have the Symbol.inConcatSpreadable method on it or on its prototype.

在上面的示例中, numbersdrivers数组在concat操作中不可扩展,因此,它们仍作为数组值保留在newArray ,但是, sports数组被扩展了,因为它上面或下面没有Symbol.inConcatSpreadable方法它的原型。

符号种类 (Symbol.species)

In the previous example, we defined the MyArray class that extends built-in Array class. The only thing MyArray implements on its own is the Symbol.isConcatSpreadable getter. Technically, any instance of MyArray inherits all the properties of the Array class.

在前面的示例中,我们定义了扩展内置Array类的MyArray类。 MyArray唯一实现的唯一对象是Symbol.isConcatSpreadable getter。 从技术上讲, MyArray任何实例都继承Array类的所有属性。

However, there is a problem. If we use map, forEach or any prototype method of the Array class that returns a new array but on the instance of MyArray, we are going to get an instance of MyArray back which should be the desired output.

但是,有一个问题。 如果我们使用mapforEach或任何原型法Array ,它返回一个新的数组,但上的实例类MyArray ,我们要得到的实例MyArray回应该是所需的输出。

Image for post
symbols/array-extend.jssymbols / array-extend.js

However, sometimes, you need to use a wrapper class only to provide additional behavior around a base class but keep the core functionality of the underlying base class consistent. For example, what we want is that when we use map or forEach on an instance of MyArray, it should return an Array.

但是,有时,您仅需要使用包装器类即可提供围绕基类的其他行为,而使基础基类的核心功能保持一致。 例如,我们想要的是,当我们在MyArray的实例上使用mapforEach时,它应该返回一个Array

The Symbol.species is a static getter property of a class that points to the constructor function (class) that should be used to derive objects such as from within map or forEach method in the case of Array.

Symbol. species Symbol. species是类的静态getter属性 ,指向构造函数( ),在Array的情况下,该函数应该用于从mapforEach方法中派生对象

Image for post
symbols/symbol-species.jssymbols / symbol-species.js

As you can see in the above example, an implicit or explicit call of map method returned an instance of Array (rather than MyArray).

如上例所示,对map方法的隐式或显式调用返回了Array的实例( 而不是 MyArray )。

💡 You can use the same approach for Set ,Map , RegExp, Promise, TypedArray and ArrayBuffer classes as well.

Set您也可以对SetMapRegExpPromiseTypedArrayArrayBuffer类使用相同的方法。

正则表达式方法 (Regular Expression Methods)

Until now, when we talked about regular expressions, we meant an instance of RegExp. The same instance can be created from the literal expression in the form of /.../. This regular expression object then can be used to match text patterns inside a string.

到目前为止,当我们谈论正则表达式时,我们指的是RegExp的实例。 可以从文字表达式中以/.../的形式创建相同的实例。 然后,可以使用此正则表达式对象匹配字符串内的文本模式。

'google.com'.match(/^[a-z]+\.com$/gi)▶ ["google.com"]

JavaScript with ES2015 makes it possible for any object to act like a regular expression object. Therefore you can pass a custom object in the str.match() call which will be used as a matcher just like a regular expression. This object should implement some well-known method that will be called to get back the result of the match operation.

结合使用ES2015JavaScript,任何对象都可以像正则表达式对象一样工作。 因此,您可以在str. match ()传递自定义对象str. match () str. match ()调用,它将像常规表达式一样用作匹配器 。 该对象应实现一些众所周知的方法,该方法将被调用以获取匹配操作的结果。

When a matcher object has Symbol.match method, it can be used in String.prototype.match() method. This symbol method is invoked by JavaScript to obtain the result of str.match().

当匹配器对象具有Symbol. match Symbol. match方法,可以在String.prototype. match () String.prototype. match ()方法。 此符号方法由JavaScript调用以获得str.match()的结果。

Image for post
symbols/symbol-match.jssymbols / symbol-match.js

In the above example, we have created a Matcher class that implements Symbol.match instance method, hence this method is available on the matcher object. When we call text.match(matcher) function, this method is executed with the text. We can use the text inside Symbol.match method to return a valid response.

在上面的示例中,我们创建了一个实现Symbol.match实例方法的Matcher类,因此该方法在matcher对象上可用。 当我们调用text.match( matcher )函数时,此方法与text执行。 我们可以在Symbol.match方法中使用text来返回有效的响应。

💡 You also have the Symbol.matchAll well-known symbol to process String.prototype.matchAll() call.

also您也有Symbol. matchAll Symbol. matchAll众所周知的符号,用于处理String.prototype. matchAll () String.prototype. matchAll ()调用。

The Symbol.search method of the matcher is executed when search prototype method is executed on a String. Similar to the Symbol.match, this method also receives the string as the argument onto which the search method was called.

Symbol. search Symbol. search当执行匹配的方法search上的执行原型方法String 。 与Symbol.match相似,此方法还接收字符串作为调用search方法的参数。

Image for post
symbols/symbol-search.jssymbols / symbol-search.js

The Symbol.replace method of the matcher is executed when replace prototype method is executed on a String. Since the replace prototype method needs a replacement text, this method is called with the original text and the replacement. You should return a string back from this method.

Symbol. replace Symbol. replace当执行匹配的方法replace上一执行原型方法String 。 由于replace原型方法需要替换文本,因此将使用原始文本和替换来调用此方法。 您应该从该方法返回一个string

Image for post
symbols/symbol-replace.jssymbols / symbol-replace.js

The Symbol.split method of the matcher is executed when split prototype method is executed on a String. You will get the original string as the argument and you are supposed to return an array from this method.

Symbol. split Symbol. split当执行匹配的方法split上的执行原型方法String 。 您将获得原始字符串作为参数,并且应该从该方法返回一个数组。

Image for post
symbols/symbol-split.jssymbols / symbol-split.js

符号迭代器 (Symbol.iterator)

We have talked about Symbol.iterator in a separate lesson but let’s summarize that lesson. ES2015 has introduced a new iteration protocol that contains guidelines to make any object iterable. An iterable object is an object which can be used in the for-of loop or in the spread operation.

我们已经讨论过Symbol. iterator Symbol. iterator单独的课程中,但让我们总结一下。 ES2015引入了新的迭代协议 ,该协议包含使任何对象可迭代的准则。 可迭代对象是可以在for-of循环或散布操作中使用的对象。

💡 Until now, we could use only Array as an iterable while to iterate over an Object, you would need to use for-in loop. Also, you can’t spread an object natively, perhaps Object.values() or Object.entries() can help you.

💡到现在为止,我们只能使用Array作为可迭代Object ,而在Object上进行迭代,则需要使用for-in循环。 另外,您不能本地传播对象,也许是Object. values () Object. values ()Object. entries () Object. entries ()可以为您提供帮助。

Using the iterable protocol, you can make any object behave like an array in a for-of loop or in the spread operation. In these contexts, JavaScript first obtains an iterator from the iterable by calling the Symbol.iterator method of the iterable (could also be on its prototype).

使用可迭代协议,可以使任何对象在for-of循环或散布操作中的行为都类似于数组。 在这些情况下,JavaScript首先通过调用可迭代对象的Symbol.iterator方法( 也可以在其原型上 )从可迭代对象中获取一个迭代器

This Symbol.iterator method is called at the beginning of the iteration and it should return an iterator object. This iterator object has the next method which returns an object with done boolean field and value field.

在迭代开始时会调用此Symbol.iterator方法,并且该方法应返回迭代器对象。 该迭代器对象具有next方法,该方法返回具有done布尔字段和value字段的对象。

gist.github.comgist.github.com

This iterator.next() method is called indefinitely in the iteration until done is false. This value field is what we are interested in. This field represents the value of each iteration. The when done is false, the value is ignored.

iterator.next()会无限次调用此iterator.next()方法,直到donefalse为止。 此value字段是我们感兴趣的字段。此字段表示每次迭代的值。 当donefalse ,该value被忽略。

💡 Read more about the iteration protocol from the MDN documentation.

fromMDN文档中了解有关迭代协议的更多信息。

Designing iterators is not such a fun process because it involves a lot of boilerplate code as you can see above. That’s why JavaScript gives us another feature called Generator which is a special kind of function. These generator functions (or simply generators) when called return an iterator. Hence the Symbol.iterator property could be a generator as well.

设计迭代器并不是一个有趣的过程,因为它涉及到很多如上所示的样板代码。 这就是JavaScript为我们提供另一个称为Generator的功能的原因,它是一种特殊的功能。 这些生成器函数( 或简称生成器 )在调用时返回迭代器。 因此, Symbol.iterator属性也可以是生成器。

When next method is called on the iterator returned by the generator, each yield expression is evaluated which produces an iteration object with done and value fields. Once all yield expressions are evaluated, the iterator returns an iteration object with done set to false whenever the next method is called.

在生成器返回的迭代器上调用next方法时,将评估每个yield表达式,该表达式将生成一个包含donevalue字段的迭代对象。 一旦评估了所有yield表达式,则每次调用next方法时,迭代器都会返回一个done对象设置为false的迭代对象。

Image for post
symbols/symbol-iterator.jssymbols / symbol-iterator.js

The *[ Symbol.iterator ] method supplies a generator which is why we needed to provide * at the beginning of the method name. JavaScript implements iterator protocols for multiple classes (by default) such as Array, Set, Map, String, TypedArray, etc. as shown below.

*[ Symbol.iterator ]方法提供了一个生成器,这就是为什么我们需要在方法名称的开头提供*原因。 JavaScript为多个类( 默认情况下 )实现了迭代器协议,例如ArraySetMapString ,TypedArray等,如下所示。

typeof Array.prototype[Symbol.iterator]; // 'function'typeof String.prototype[Symbol.iterator]; // 'function'typeof Map.prototype[Symbol.iterator]; // 'function'typeof Set.prototype[Symbol.iterator]; // 'function'typeof Uint8Array.prototype[Symbol.iterator]; // 'function'// hence you can spread a stringlet vowels = [...'aeiou']; // [ 'a', 'e', 'i', 'o', 'u' ]

Symbol.asyncIterator (Symbol.asyncIterator)

JavaScript support another variation of the for-of loop for the iteration of promises in a synchronous manner. The for-await-of loop can iterate over an iterable in a synchronous manner that returns a promise for each iteration.

JavaScript支持for-of循环的另一个变体, for-of以同步方式迭代promise。 for-await-of循环可以以同步方式对可迭代对象进行迭代,从而为每次迭代返回一个promise。

Image for post
symbols/for-await-of.js符号/for-await-of.js

In the above example, the promises array contains a list of promises that resolves with a string value after a few milliseconds. If we run a normal for-of loop on it, each iteration will receive the promise as the value. But what we need is the resolved value of each promise.

在上面的示例中, promises数组包含一个promise列表,该列表会在几毫秒后使用字符串值解析。 如果我们在其上运行普通的for-of循环,则每次迭代都将收到promise作为值。 但是我们需要的是每个承诺的决心价值。

The for await syntax makes it possible. It waits until each promise is resolved and the result variable gets the resolved value of the promise. Since we are using the await keyword, we need to put for-await-of loop inside an async function, which could be an IIFE, it doesn’t matter.

for await语法使之成为可能。 它一直等到每个承诺都得到解决,并且result变量获得承诺的已解决值。 由于使用的是await关键字,因此需要将for-await-of循环放入async函数中,该函数可以是IIFE ,这无关紧要。

Just like for-of loop, the for-async-of loop also uses Symbol.iterator method of the iterable to receive an iterator. If iterator returns a promise for each iteration, the result would be the same as the above.

就像for-of循环一样, for-async-of循环也使用iterable的Symbol.iterator方法来接收迭代器。 如果迭代器为每次迭代返回一个Promise,则结果将与上述相同。

However, for-await-of loop prefers Symbol.asyncIterator method if available on the iterable. This method also works like Symbol.iterator but it’s an async method, therefore, you can use await keyword inside the generator (or custom method that returns an iterator).

但是, for-await-of循环更喜欢使用Symbol. asyncIterator Symbol. asyncIterator方法(如果在迭代器上可用)。 这个方法也像Symbol.iterator一样Symbol.iterator但是它是一个async方法,因此,您可以在生成器内部使用await关键字( 或返回迭代器的自定义方法 )。

Image for post
symbols/symbol-async-iterator.jssymbols / symbol-async-iterator.js

In the above example, each yield expression will await the promise resolution so that it can supply the resolved value of the promise as the value of the iteration. However, you can also yield the promise itself (just drop the await keyword) and things will work in the same manner.

在上面的示例中,每个yield表达式将等待promise解析,以便它可以提供promise的解析值作为迭代值。 但是,您也可以自己产生promise( 只需删除 await 关键字 ),事情将以相同的方式工作。

什么是@@iterator(What is @@iterator?)

You probably have seen @@iterator notation in JavaScript documentations such as MDN’s Array documentation or in perhaps in the console logs or stack traces. The @@ symbol is a specification prefix for well-known symbols and it doesn’t have any significance at runtime.

您可能已经在JavaScript文档(例如MDN的Array文档)或控制台日志或堆栈跟踪中看到了@@iterator表示法。 @@符号是知名符号的规范前缀,在运行时没有任何意义。

The below table is an official ES2021 table of well-known symbols. On the left column, you can find the specification name of the well-known symbol while on the right column is the actual symbol accessible at runtime.

下表是ES2021正式的知名符号表。 在左列中,可以找到众所周知的符号的规范名称,而在右列中,则是在运行时可访问的实际符号。

Image for post
ECMAScript 2021ECMAScript 2021

💡 The Symbol.unscopables well-known symbol is used to control the behavior of an object when used inside with statement. But since with statement is not really recommended and it is kind of controversial, you should avoid using it.

💡Symbol. unscopables Symbol. unscopables众所周知的符号用于在with语句内部with时控制对象的行为。 但是由于不真正推荐with语句,并且存在争议,因此应避免使用它。

符号有什么用处? (What are symbols good for?)

Well, this is the most difficult section of the whole article. I would say symbols are great to avoid non-standard consumption of your API. For example, if you do not want people to accidentally override an object property, make it a symbol and expose it through a global object or make it a global symbol.

好吧,这是整篇文章中最困难的部分。 我想说符号非常适合避免API的非标准使用。 例如,如果您不希望人们意外地覆盖对象属性,则将其设置为符号并通过全局对象公开它或将其设置为全局符号。

Another thing symbols are good for is to represent a unique value. For example, if you want to create an enum to represent a fixed set of unique values, create an object with symbol values.

符号的另一优点是代表一个唯一的值。 例如,如果要创建一个枚举来表示一组固定的唯一值,请创建一个具有符号值的对象。

// worst 😵
print( "red" );----------------------// bad 😔
var COLORS = {
RED: "RED",
GREEN: "GREEN",
BLUE: "BLUE"
};
print( COLOR.RED );----------------------// good 😃
var COLORS = {
RED: Symbol( 'COLORS.RED' ),
GREEN: Symbol( 'GREEN.GREEN' ),
BLUE: Symbol( 'COLORS.BLUE' )
};print( COLOR.RED );

翻译自: https://medium.com/jspoint/introduction-to-javascript-symbols-and-their-use-in-metaprogramming-b1e566410589

javascript 符号

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值