javascript编程题_JavaScript元编程简介
“Metaprogramming” is a programming technique in which computer programs have the ability to treat other programs as their data. It means that a program can be designed to read, generate, analyze, or transform other programs, and even modify itself while running.
“元编程”是一种编程技术,其中计算机程序具有将其他程序视为其数据的能力。 这意味着可以将程序设计为读取,生成,分析或转换其他程序,甚至在运行时对其进行修改。
Well, this definition is very accurate but it’s quite a mouthful. Actually it pretty much summarizes most of the concepts in Metaprogramming, so let’s break it down and explore each one of them.
嗯,这个定义非常准确,但是很容易理解。 实际上,它几乎总结了元编程中的大多数概念,因此让我们对其进行分解并探索其中的每个概念。
💡 Before we begin talking about metaprogramming, let me put a small disclaimer. Metaprogramming can mean different things to different people and in the context of different programming languages. Because is not a programming language feature and it certainly isn’t standardized. So if you disagree with my explanation, please drop a comment to start a war. Now that is out of the way, let’s focus our attention on the definition of the metaprogramming because it might make much sense at first.
begin在我们开始讨论元编程之前,请允许我先声明一下。 元编程对于不同的人和不同的编程语言而言可能意味着不同的事情。 因为这不是编程语言功能,而且肯定不是标准化的。 因此,如果您不同意我的解释,请发表评论以发动战争。 既然这已经不成问题了,那么让我们将注意力集中在元编程的定义上,因为一开始它可能很有意义。
When you write a program, it contains some logic that produces some output when we run it. At runtime (while the program is executing), our program uses some data, perhaps provided by the user or received through some remote network calls, and transforms it as per our likings. So in a nutshell, the program manipulates data to achieve the desired results.
当您编写程序时,它包含一些逻辑,当我们运行它时会产生一些输出。 在运行时( 程序正在执行时 ),我们的程序使用某些数据(可能由用户提供或通过某些远程网络调用接收),并根据我们的喜好进行转换。 简而言之,该程序可以处理数据以获得所需的结果。
A metaprogram is a program that manipulates other programs. Now let that sink in. As we just understood, a program manipulates data so a program that has the ability to manipulate other programs is metaprograms. So technically, a metaprogram accepts other programs as its data and manipulates it.
元程序是操纵其他程序的程序。 现在让我们沉浸其中。正如我们刚刚了解的那样,一个程序可以操纵数据,因此具有操纵其他程序能力的程序就是元程序。 因此从技术上讲,元程序接受其他程序作为其数据并对其进行操作。
We will talk about what “manipulate” really means in greater detail but in a nutshell, it means to inspect and modify the behavior of a program through various means (covered in the “Reflection” section). It could also mean to inject new behavior in the program through various means such a generating new code in the program (covered in the “Code generation” section).
我们将更详细地讨论“ 操纵 ”的真正含义,但简而言之,它意味着通过各种方式( 在“反射”部分中介绍 )来检查和修改程序的行为 。 这也可能意味着通过各种方式在程序中注入新行为 ,例如在程序中生成新代码( 在“代码生成”部分中进行了介绍 )。
A programming language that manipulates other programs that are written in completely different programming languages is called a metalanguage. If you have worked on TypeScript, then you just realized that it is a metalanguage as it produces programs written in JavaScript. Java is also kind of a metalanguage as it generates bytecode (a form of a language).
操纵以完全不同的编程语言编写的其他程序的编程语言称为元语言 。 如果您使用过TypeScript ,那么您刚刚意识到它是一种元语言,因为它可以生成用JavaScript编写的程序。 Java也是一种元语言,因为它生成字节码( 一种语言形式 )。
A programming language that can manipulate itself is called a homoiconic language. But I would recommend you to read this short article on this topic before you make any judgment calls. In a homoiconic language, the program itself can inspect itself and modify certain parts of itself which we do not see much in our everyday programming unless you are a Lisp developer.
可以自行操作的编程语言称为谐音语言。 但是,我建议您在做出任何判断之前,先阅读有关此主题的这篇简短文章 。 用谐音语言,程序本身可以检查自身并修改其某些部分,除非您是Lisp开发人员,否则我们在日常编程中不会看到太多内容。
The word “program” gives the wrong impression in the context of metaprogramming and I will tell you why. For us, a program is a piece of code written in plain text format. We can either compile the code to create a binary executable (.exe
file) and then run it natively or we just run it inside an interpreter (or VM) such as a JavaScript engine (for JavaScript code).
在元编程的上下文中,“ 程序”一词给人留下了错误的印象,我将告诉你原因。 对我们来说,程序是一段用纯文本格式编写的代码。 我们可以编译代码以创建一个二进制可执行文件( .exe
文件 ),然后在本地运行它,或者我们只在诸如JavaScript引擎的解释器( 或VM )( 用于JavaScript代码 )中运行它。
Metaprogramming concepts fall into two different categories. Compile-time and runtime. Compile-time means when the code is being compiled into a low-level or high-level programming language. For example, when TypeScript is being compiled into JavaScript. Runtime is when the code is running. For example, when the JavaScript program is running inside Node (VM).
元编程概念分为两个不同的类别。 编译时和运行时。 编译时是指将代码编译为低级或高级编程语言的时间。 例如,将TypeScript编译为JavaScript时。 运行时是代码运行时 。 例如,当JavaScript程序在Node ( VM )内部运行时。
Once the code is executing inside an interpreter (or virtual machine), the program generally means the logical behavior of the code at runtime that has been interpreted from the code (plain text). For example, a simple JavaScript code can create many complex entities (such as functions, classes, objects, etc.) at runtime and these entities can have complex behavior.
一旦代码在解释器( 或虚拟机 )中执行, 程序通常表示已在运行时从代码( 纯文本 )中进行了解释的代码的逻辑行为 。 例如,简单JavaScript代码可以在运行时创建许多复杂的实体( 例如函数,类,对象等 ),并且这些实体可以具有复杂的行为。
So technically if a programming language has the capacity to change its behavior at runtime, then it can be said to support metaprogramming. Simply put, if a program can manipulate itself at runtime (while running), then it supports metaprogramming.
因此从技术上讲,如果编程语言具有在运行时更改其行为的能力,那么可以说它支持元编程。 简而言之,如果程序可以在运行时( 运行时 )进行自我操作,则它支持元编程。
Now you can pretty much bet your money on JavaScript since it can definitely change its behavior at runtime (running JavaScript programs) so it definitely supports metaprogramming. Don’t worry, we are going to spend an awful lot of time discussing how metaprogramming exactly works in JavaScript.
现在,您几乎可以将钱押在JavaScript上,因为它肯定可以在运行时更改其行为( 运行JavaScript程序 ),因此它绝对支持元编程。 不用担心,我们将花费大量时间讨论元编程在JavaScript中的工作原理。
The action of the program to manipulate its behavior or the behavior of other programs at runtime is called monkey patching. Monkey patching, in a nutshell, is to tweak certain part(s) of the program at runtime to achieve desired results, without changing the original source code of the program.
程序在运行时操纵其行为或其他程序的行为的动作称为“ 猴子修补” 。 简而言之,猴子补丁程序是在运行时调整程序的某些部分,以实现所需的结果,而无需更改程序的原始源代码。
Let’s take a small example of a JavaScript program. Here, we are going to manipulate the internal implementation of the JavaScript at runtime.
让我们举一个JavaScript程序的小例子。 在这里,我们将在运行时操纵JavaScript的内部实现。
So in the above example, we have changed the behavior of the String
class (which affected the string
type) at runtime by using some monkey patching techniques as the source code of String
class hasn’t been changed inside V8.
因此,在上面的示例中,我们通过使用一些猴子修补技术更改了String
类在运行时的行为( 这影响了 string
类型 ),因为在V8中没有更改String
类的源代码。
Since metaprogramming means different things when a program is compiling or when a program is running, metaprogramming has been divided into two different parts viz. code generation and reflection.
由于元程序在编译程序或程序运行时意味着不同的事情,因此元程序已分为两个不同的部分。 代码生成和反映 。
Code generation simply put is the ability of a programming language to generate program code. That’s why sometimes metaprogramming is generalized as a program that writes a program. Reflection, on the other hand, is the ability of a program to manipulate itself or other programs. They can be further subcategorized as shown below.
简单地说, 代码生成是一种编程语言生成程序代码的能力。 这就是为什么有时将元编程泛化为编写程序的程序。 另一方面, 反射是程序操纵自身或其他程序的能力。 它们可以进一步细分,如下所示。
+---------------------------------------------------------------+
| METAPROGRAMMING |
+-----------------+---------------------------------------------+
| Code Generation | Reflection |
+-------+---------+---------------+--------------+--------------+
| Eval | Macros | Introspection | Intercession | Modification |
+-------+---------+---------------+--------------+--------------+
We will talk about these concepts in greater detail but from here onwards, do not make a distinction within them based on compile-time or runtime phase since some programming language can also code generation at runtime and the same goes for the reflection at compile-time.
我们将更详细地讨论这些概念,但是从现在开始,不要在编译时或运行时阶段对它们进行区分,因为某些编程语言也可以在运行时生成代码 ,并且在编译时也可以反映出来 。 。
代码生成 (Code generation)
Code generation is one of the key concepts in metaprogramming. Code generation basically means adding programs to the existing programs, at compile-time or at runtime.
代码生成是元编程中的关键概念之一。 代码生成基本上意味着在编译时或运行时将程序添加到现有程序中。
Here again, do not get confused with the word “code” and just accept that “code generations” means to generate programs through various means such as adding extra code (texts) to the program file or compiling code at runtime.
同样,不要与“代码”一词混淆,只是接受“代码生成”是指通过各种方式生成程序 ,例如向程序文件中添加额外的代码( 文本 )或在运行时编译代码。
Since code-generation can happen at compile-time or runtime, they are divided into two categories viz. macros and eval.
由于代码生成可以在编译时或运行时进行,因此将它们分为两类。 宏和评估 。
巨集 (Macros)
If you are a C
or C++
developer, then you should know what a macro is. A macro is a piece of code (usually, a single word), that expands into multiple lines of code in the compilation process. Before compiling the program to a low-level language, a preprocessor expands these micros and feeds them to the compiler. So the compiler always gets the meaningful program code.
如果您是C
或C++
开发人员,那么您应该知道什么是宏。 宏是一段代码( 通常是一个单词 ),在编译过程中会扩展为多行代码。 在将程序编译为低级语言之前, 预处理器会扩展这些micros并将它们提供给编译器。 因此,编译器始终会获取有意义的程序代码。
💡 Read more about the macros in
C++
from this article.💡了解更多关于在宏
C++
从这个文章。
In JavaScript, we can’t have macros because we do not compile JavaScript to machine code and feed that to the JavaScript engine, the JavaScript engine does that itself which is why we call it Just-In-Time (JIT) compilation.
在JavaScript中,我们没有宏,因为我们没有将JavaScript编译为机器代码并将其提供给JavaScript引擎,而JavaScript引擎本身就是这样做的,这就是为什么我们将其称为即时(JIT)编译。
If there is any other way to produce JavaScript from a higher-language, macros are possible. For example, TypeScript can have macros, but unfortunately, it doesn’t. Sweet.js is an open-source project on GitHub which compiles JavaScript from a somewhat-JavaScript code that contains micros.
如果还有其他方法可以从更高语言中生成JavaScript,则可以使用宏。 例如,TypeScript可以具有宏,但不幸的是,没有。 Sweet.js是GitHub上的一个开源项目,该项目从包含micros的某种JavaScript代码中编译JavaScript。
“Hygienic Macros for JavaScript! Macros allow you to build the language of your dreams. Sweeten JavaScript by defining a new syntax for your code.” — Sweet.js
“ JavaScript的卫生宏! 宏使您可以构建自己的梦想语言。 通过为代码定义新语法来使JavaScript变得甜蜜。” — Sweet.js
You can follow their official documentation on GitHub to install a CLI tool that compiles the .sjs
file to .js
file. Here .sjs
file is a JavaScript file that contains micros and .js
file will the final result of the compilation which contains the vanilla (pure) JavaScript code.
您可以按照GitHub上的官方文档来安装CLI工具,该工具.sjs
文件编译为.js
文件。 .sjs
文件是一个包含microsJavaScript文件, .js
文件将是包含.sjs
( 纯净 )JavaScript代码的编译最终结果。
In the above example, we have a program.sjs
file that contains the DEBUG_FUNC
micro. A micro in sweet.js is simple a function that is defined with the syntax
keyword, just like a var
keyword. This function must return a tagged template literal with #
tag. The template string contains the actual JavaScript code that will be replaced where this micro is placed.
在上面的示例中,我们有一个包含DEBUG_FUNC
micro的program.sjs
文件。 sweet.js中的micro是一个简单的函数,使用syntax
关键字定义,就像var
关键字一样。 此函数必须返回带有#
标签的带标签的模板文字 。 模板字符串包含实际JavaScript代码,该代码将在放置此微型代码的位置被替换。
$ sjs -o program.js program.sjs
You can read about the compilation process and various other ways to work with sweet.js syntax from this documentation. When we run the above sjs
command, it compiles program.sjs
program and outputs the compiled JavaScript code inside program.js
. This output file looks like below.
您可以从本文档中了解编译过程以及使用sweet.js语法的各种其他方式。 当我们运行上面的sjs
命令时,它将编译program.sjs
程序并在program.js
输出已编译JavaScript代码。 该输出文件如下所示。
As you can see, the DEBUG_FUNC
(including optional leading ;
) was replaced with the actual code returned from the macro function in the compilation process. Now you can understand the power of macros.
如您所见, DEBUG_FUNC
( 包括可选的前导 ;
)替换为在编译过程中从宏函数返回的实际代码。 现在您可以了解宏的功能。
Here the JavaScript (with some minor modifications) is able to produce valid programs. So according to the metaprogramming theory, JavaScript is a metalanguage for itself but in the context of sweet.js.
JavaScript( 经过一些小的修改 )可以生成有效的程序。 因此,根据元编程理论,JavaScript本身就是一种元语言 ,但是在sweet.js的上下文中。
评估 (Eval)
If you are a JavaScript developer, then perhaps you might have used the eval
function. This function accepts a string
value and executes it as if it was a JavaScript code. So technically we are producing JavaScript code at runtime.
如果您是JavaScript开发人员,那么也许您已经使用过eval
函数。 此函数接受string
值,并像执行JavaScript代码一样执行它。 因此,从技术上讲,我们在运行时生成JavaScript代码。
As you can see, eval
is a powerful tool to dynamically execute or generate programs from simple strings that represent JavaScript code. You can place eval(str)
wherever you want in the program and assume as if the code (text) provided by the str
string was there at the eval()
call site.
如您所见, eval
是一个功能强大的工具,可以从代表JavaScript代码的简单字符串动态执行或生成程序。 您可以将eval(str)
放置在程序中的任意位置,并假定str
字符串提供的代码( text )好像在eval()
调用站点中。
At first, eval
seems really powerful, however, I am surprised to see nobody telling the new employees to keep eval
to themselves when joining the company. Why? Because eval
is a double agent as it opens the door to hackers to exploit your web application.
起初, eval
似乎真的很强大,但是,我很惊讶看到没有人告诉新员工,以保持eval
加入公司时,对自己负责。 为什么? 由于eval
是双重代理,因此它为黑客打开利用Web应用程序的大门。
As you can see MDN cries about it in bold letters. The Function
constructor also helps you generate JavaScript functions from strings much like eval
but poses the similar risks as eval
.
如您所见, MDN用粗体字母大喊。 Function
构造函数还可以帮助您从类似于eval
字符串生成JavaScript函数,但带来的风险与eval
相似。
Not only JavaScript but Python also has the eval
function that acts just like the eval
function in JavaScript. Matter of fact, most programming languages, especially interpreted ones, has some sort of built-in eval
function to produce programs at runtime.
不仅JavaScript,Python还具有eval
函数,其作用类似于JavaScript中的eval
函数。 实际上,大多数编程语言(尤其是解释型语言)具有某种内置的eval
函数,可以在运行时生成程序。
To sum up, Macros and Eval, both are great metaprogramming tools as it opens the door for a language to programmatically generate programs on the fly, both at compile-time or runtime.
总而言之, Macro和Eval都是出色的元编程工具,因为它为语言提供了在编译时或运行时即时以编程方式生成程序的大门。
反射 (Reflection)
Reflection, unliked “code generation”, is a process to change the underlying mechanics of the language. Reflection can happen at compile-time or at runtime, but we will stick with runtime reflection as we are talking about JavaScript, so compile-time reflection won’t be possible. However, concepts discussed here could be applicable to a compiled language as well.
反射与“代码生成”不同,它是更改语言基本机制的过程。 反射可以在编译时或在运行时发生 ,但是在谈论JavaScript 时 ,我们将坚持运行时反射,因此不可能进行编译时反射。 但是,这里讨论的概念也可以适用于编译语言。
As we have understood that the reflection is all about changing the underlying mechanics of the language, it has been divided into three major categories, viz. introspection, intercession, and modification.
正如我们所了解的那样, 反射是与改变语言的基本机制有关的,它已分为三大类,即。 内省 , 代祷和修改 。
内省 (Introspection)
Introspection is the process of analyzing the program. If you can tell what program does, you can modify it as per your likings. Even though some programming languages do not support code generation or code modification features, but they most probably allow introspection.
自省是分析程序的过程。 如果您知道程序的作用,则可以根据自己的喜好对其进行修改。 即使某些编程语言不支持代码生成或代码修改功能,但它们很可能允许自省 。
A simple example of introspection would be using typeof
or instanceof
operators in JavaScript. The typeof
returns the current data type of a value (or an expression that returns a value) while instanceof
returns true
or false
if LHS value is an instance of RHS class. Let’s see them in action.
内省的一个简单示例是在JavaScript中使用typeof
或instanceof
运算符。 如果LHS值是RHS类的实例,则typeof
返回值的当前数据类型( 或返回value的表达式 ),而instanceof
返回true
或false
。 让我们看看它们的作用。
In the above program, we have used typeof
and instanceof
operators in the coerce
function to sniff the data type of incoming value
. This is the basic demonstration of introspection. However, a language specifically designed for metaprogramming might provide some powerful introspection tools.
在上面的程序中,我们在coerce
函数中使用了typeof
和instanceof
运算符来嗅探传入value
的数据类型。 这是自省的基本证明。 但是,专门为元编程设计的语言可能会提供一些强大的自省工具。
You can use the in
operator to check if a property exists in the object. The isNaN
global function checks if object is NaN
. There are some static methods built around the Object
to inspect values of the Object
type such as Object.isFrozen(value)
to check if value
is frozen or Object.keys(value)
to get the property names of the value
object.
您可以使用in
运算符检查对象中是否存在属性。 isNaN
全局函数检查object是否为NaN
。 围绕Object
构建了一些静态方法来检查诸如Object
类的Object
类型的值Object. isFrozen ( value )
Object. isFrozen ( value )
检查value
是否被冻结,或者使用Object.keys( value )
获取value
对象的属性名称。
Until ES5, we had these operators and these methods to work with. In ES2015 (ES6), JavaScript introduced Reflect
object that provides some static methods (just like Object
) but specifically designed for introspection. Since we have a separate lesson on Reflect
, these methods are discussed there.
在ES5之前,我们需要使用这些运算符和这些方法。 在ES2015( ES6 )中,JavaScript引入了Reflect
对象,该对象提供了一些静态方法( 就像 Object
一样 ),但专门为自省而设计。 由于我们在Reflect
上有单独的课程 ,因此将在此处讨论这些方法。
代祷 (Intercession)
Intercession is the process of intervening in the JavaScript processes and modifying the standard behavior of the process. JavaScript provides great tools for intercession one of which is Proxy
.
调解是干预JavaScript流程并修改流程的标准行为的流程。 JavaScript提供了很好的代祷工具,其中之一是Proxy
。
The Proxy
class was introduced in ES2015 (ES6) to intercept (intervene) basic JavaScript operations around objects just like we have seen above but in a much nicer way. We have a separate lesson on Proxy
(coming soon) but in a nutshell, Proxy
wraps an interceptable logic around an object.
Proxy
类是在ES2015( ES6 )中引入的,用于拦截( 干预 )对象周围的基本JavaScript操作,就像我们在上面看到的那样,但是以一种更好的方式。 我们有关于Proxy
的单独课程 ( 即将推出 ),但总而言之, Proxy
围绕对象包装了可拦截的逻辑。
var targetWithProxy = new Proxy(target, handler);
Here, the target
is object and handler
is the interceptor. The handler
is also a plain JavaScript object but with some meaningful fields. For example, handler.get
would be a function that returns a custom value when target.prop
(here, prop
is any property) is accessed.
在这里, target
是对象,而handler
是拦截器。 该handler
也是一个普通JavaScript对象,但具有一些有意义的字段。 例如, handler.get
将是一个在访问target.prop
( 此处 prop
是任何property )时返回自定义值的函数。
Proxy is a great way to provide abstractions over your not-so-public data. For example, in the above program, we have provided abstractions over target
object and customized how it should present itself to the public.
代理是提供对不太公开的数据的抽象的一种好方法。 例如,在上面的程序中,我们提供了对target
对象的抽象,并自定义了它应如何向公众展示。
Some intercession was possible in ES5 as well such as using getter
and setters
on property descriptors but it would result in the mutation of the target
object. Proxy
provides a much cleaner way to achieve intercession without having to modify the original object (target
).
在ES5中也可以进行一些调解,例如在属性描述符上使用getter
和setters
,但这会导致target
对象的变异。 Proxy
提供了一种更简洁的方法来实现代祷,而无需修改原始对象( target
)。
修改 (Modification)
Modification refers to the modification of the program behavior through mutation. In the case of intercession, we only intercepted the standard JavaScript processes by adding an intercepting logic between the target and the receiver without harming the target. In this case modification, we are changing the behavior of the target itself so suit the receiver.
修改是指通过突变对程序行为的修改。 在代祷的情况下,我们仅通过在目标与接收者之间添加拦截逻辑来拦截标准JavaScript程序而不会损害目标 。 在这种情况下修改 ,我们正在改变本身,以便适合接收 目标的行为。
Overriding a function implementation would be a good example of modification. For example, if a function is designed to behave in a certain way, but we want to something else conditionally, we can do that by designing a self overriding function. Let’s see an example.
覆盖函数实现将是修改的一个很好的例子。 例如,如果一个函数被设计为以某种特定方式运行,但是我们希望有条件地进行其他操作,则可以通过设计一个自覆盖函数来做到这一点。 让我们来看一个例子。
In the above example, we have created a function that overrides itself with a new function implementation. This would be the harshest example of modification but we have other, perhaps more meaningful use cases.
在上面的示例中,我们创建了一个函数,该函数使用新的函数实现覆盖自身。 这将是最苛刻的修改示例,但我们还有其他可能更有意义的用例。
In the above example, we have used Object.defineProperty()
method to change the default property descriptor of the name
property in order to make it read-only. You can also use the Object.freeze()
method to lock the entire object to avoid any mutations.
在上面的示例中,我们使用了Object. defineProperty ()
Object. defineProperty ()
方法更改name
属性的默认属性描述符 ,以使其成为只读。 您也可以使用Object. freeze ()
Object. freeze ()
方法锁定整个对象,以避免任何突变。
Some intercessions can happen through modifications as you can from the above example. By setting writable:false
in the property descriptor of the object, therefore mutating the object (internal implementation), we have incepted the value assignment operation.
通过上面的示例,可以通过修改进行某些调解 。 通过在对象的属性描述符中设置writable:false
,从而使对象发生变化( 内部实现 ),我们接受了值分配操作。
If you are not familiar with the valueOf
method, it is used to coerce an object to a primitive value. So if I have an object and it has valueOf
method on itself or on its prototype chain, then this method is called by JavaScript when you are trying to perform an arithmetic operation on it. By default, Object
has the valueOf
method which returns itself (the object).
如果您不熟悉valueOf
方法,则该方法用于将对象强制为原始值。 因此,如果我有一个对象,并且它本身或其原型链上具有valueOf
方法,则当您尝试对其执行算术运算时,JavaScript将调用此方法。 默认情况下, Object
具有valueOf
方法,该方法返回自身( object )。
As you can see in the above example, emp1/10
resulted in a NaN
since an object can’t be divided like natural numbers. But later we’ve added valueOf
method on Employee
class that returns salary
value of the object. Therefore emp2/10
returned 200
since emp2.salary
is 200
. Similarly, emp3/10
returned 300
as we have added valueOf
method directly on the emp3
.
如您在上面的示例中看到的, emp1/10
导致NaN
因为对象无法像自然数一样进行划分。 但是稍后,我们在Employee
类上添加了valueOf
方法,该方法返回对象的salary
值。 因此emp2/10
返回200
因为emp2.salary
是200
。 同样,由于我们直接在emp3
上添加了valueOf
方法,因此emp3/10
返回了300
。
So at every step in the above example, we are intervening how an object is presented to a standard JavaScript operation and changing its behavior to our likings. This is nothing but the intercession.
因此,在以上示例的每个步骤中,我们都会干预如何将对象呈现给标准JavaScript操作,并根据自己的喜好更改其行为。 这不过是代祷 。
In ES2015 (ES6), JavaScript has introduced a new primitive data type which is symbol
. It’s nothing like we have seen before and can’t be represented in literal form. It can be only constructed by calling the Symbol
function.
在ES2015( ES6 )中,JavaScript引入了一种新的原始数据类型,它是symbol
。 这与我们以前见过的一样,不能以文字形式表示。 只能通过调用Symbol
函数来构造它。
var sym1 = Symbol();
var sym2 = Symbol();
var sym3 = Symbol('description'); // description for debugging aidsym1 === sym2 // falsesym1 === sym2 // falsetypeof sym1 // 'symbol'console.log( sym1 ); // 'Symbol()'
console.log( sym3 ); // 'Symbol(description)'
In a nutshell, it produces unique values that can also be used as regular object keys using the obj[key]
notation where key
would be a symbol.
简而言之,它会产生唯一值,也可以使用obj[key]
表示法将其用作常规对象键,其中key
将是符号。
var key = Symbol();var obj = {
name: 'Ross',
[key]: 200
};console.log( obj.name ); // 'Ross'
console.log( obj[key] ); // 200
Object.keys(obj); // ["name"]obj[key] = 300;
Since they are unique, there is no way to create a duplicate symbol by accident. Every new symbol is unique (created using Symbol()
) which means if you want to use a same symbol, you must store that in a variable and pass that variable around to refer to the same symbol.
由于它们是唯一的,因此无法偶然创建重复的符号。 每个新符号都是唯一的( 使用 Symbol()
创建 ),这意味着如果要使用相同的符号,则必须将其存储在变量中并传递该变量以引用相同的符号。
In the valueOf
example, you can spot the issue if we aren’t being careful or aware. Since valueOf
is a string
property (as in emp3['valueOf']
) , anyone can override it accidentally or someone who doesn’t know about valueOf
could plan to use it for his/her own use thinking “what’s in the name?”.
在valueOf
示例中,如果我们不小心或不知道,则可以发现问题。 由于valueOf
是一个string
属性( 例如 emp3['valueOf']
的string
),所以任何人都可以意外覆盖它,或者不知道valueOf
某个人可以计划将其用于自己的用途,以为“这是什么名字?” 。
Since symbols can also be used as object keys, JavaScript has provided some global symbols that should be used as object keys for some standard JavaScript operations. Since these symbols are well known to a developer, they are called “well-known symbols”. These well-known symbols are exposed to the public as the static properties of Symbol
function.
由于符号也可以用作对象键,因此JavaScript提供了一些全局符号,这些符号应该用作某些标准JavaScript操作的对象键。 由于这些符号对于开发人员是众所周知的,因此它们被称为“ 众所周知的符号 ”。 这些众所周知的符号作为Symbol
函数的静态属性公开给公众。
One of the well-known symbols is Symbol.toPrimitive
which should be used as the key of the object to obtain its primitive value. Yes, you are thinking right, it’s a replacement of valueOf
method and it’s preferred.
众所周知的符号之一是Symbol.toPrimitive
,应将其用作对象的键以获得其原始值。 是的,您的想法正确,它是valueOf
方法的替代品,是首选。
💡 The
toPrimitive
method does more than just returning a number value of the object. Please read the Symbols lessons to know more about it.P
toPrimitive
方法的作用不只是返回对象的数字值。 请阅读符号课程以了解更多信息。
JavaScript provides many such well-known symbols to intercept and modify the default JavaScript behavior around objects. We will talk about this and symbols in general in the Symbols lesson.
JavaScript提供了许多此类众所周知的符号来拦截和修改对象周围的默认JavaScript行为。 我们将在“ 符号”课程中讨论此符号以及一般的符号 。
As I stated earlier, metaprogramming is not something that can be described as a feature of the programming language but more as the capacity. Some programming languages might not support all the metaprogramming genres such as Go (Golang) which does not support macros (at the moment) but supports runtime reflection through introspection using the reflect
package which is kinda similar to using typeof
operator we saw earlier.
如前所述,元编程不是可以描述为编程语言的功能,而可以描述为功能。 某些编程语言可能不支持所有元编程类型,例如Go ( Golang ),它不支持宏( 目前 ),但支持使用reflect
包通过内省通过自检进行运行时反射,这有点类似于我们前面看到的typeof
运算符。
You should not take metaprogramming definitions and implementation by heart as they vary according to the programming language you are talking about but the concept should stay the same. I am planning to release articles on Symbols, Reflect, Proxy soon and you will be able to find them here as well as on this publication. So stay tuned.
您不应刻板地考虑元编程的定义和实现,因为它们会根据您所讨论的编程语言而有所不同,但概念应保持不变。 我计划很快发布有关Symbols , Reflect , Proxy的文章,您将可以在这里以及本出版物中找到它们。 因此,请继续关注。
Decorators are the perfect example of metaprogramming using reflection. You can put an annotation type thingy such as @abstract
on the top of a class and it would modify the class such that it can be inherited in another class but it can’t be instantiated to create objects. Follow the below lesson.
装饰器是使用反射进行元编程的完美示例。 您可以在类的顶部放置诸如@abstract
之类的注释类型,它会修改该类,使其可以在另一个类中继承,但无法实例化以创建对象。 请遵循以下课程。
翻译自: https://medium.com/jspoint/a-brief-introduction-to-metaprogramming-in-javascript-88d13ed407b5
javascript编程题