您曾经想了解的有关JS函数的所有内容,但没有时间问

    科技2022-07-31  98

    If you are like me, you understand the basics of JS functions, and know how to use them to help you create your programs, but there are complexities to them that you have ignored as you build your skills with fancy frameworks, libraries, languages, and technologies.

    如果您像我一样,就会了解JS函数的基础知识,并且知道如何使用它们来帮助您创建程序,但是当您使用精美的框架,库,语言,和技术。

    But, I’m going to succinctly inform you of what you need to know so that you can feel more empowered around JS Functions.

    但是,我将向您简要介绍您需要了解的内容,以便您可以对JS Functions感到更加有能力。

    Let’s get to it.

    让我们开始吧。

    表达式,值,声明,声明,哦,我的 (Expressions, Values, Statements, Declarations, Oh My)

    In order to easily understand functions, it is good to get a handle on some terms.

    为了轻松理解功能,最好从某些方面入手。

    Statements are blocks of code that can be executed:

    语句是可以执行的代码块:

    It’s hard to talk about statements without talking about expressions. 不谈论表达式就很难谈论语句。

    Expressions are sections of code that return a value, reduce to a value, become something of value, are generally interpretable, have meaning, use, and can give their value to a variable, or a function, or anything that wants to store or use it.

    表达式是代码的一部分,它们返回一个值,将其还原为一个值,成为某种有价值的东西,通常可解释,具有含义,使用并可将其值提供给变量,函数或任何想要存储或使用的东西它。

    If JS could interpret something as a statement or an expression, if it is between () then JS interprets what is inside of that as an expression (if possible).

    如果JS可以将某事物解释为一条语句或一个表达式,如果它介于()之间,则JS会将其内部的内容解释为一个表达式(如果可能)。

    Expressions compile to values used in the program. 表达式将编译为程序中使用的值。

    功能声明 (Function Declarations)

    Function declarations are strange double beasts in the statement-expression world. In most cases, functions are expressions, and not statements. The special case is when the function is defined without any supportive structure.

    函数声明是语句表达式世界中的奇怪双兽。 在大多数情况下,函数是表达式,而不是语句。 特殊情况是在定义函数时没有任何支持结构的情况。

    A function declaration is basically a statement-ish function. They exist when the beginning of a statement begins with the word ‘function.’ 函数声明基本上是一个类似于语句的函数。 当语句的开头以“功能”一词开头时,它们就存在。

    Function declarations are unique in that they are hoisted with their definitions to the top of the scope they are in and can be used anywhere above or below the scope they are defined in.

    函数声明是唯一的,因为它们的定义将其声明提升到它们所在的范围的顶部,并且可以在它们所定义的范围之上或之下的任何位置使用。

    Function declarations are hoisted with their definitions. 函数声明带有其定义。

    In this way, they are hoisted like variables are, but they are treated differently. Function declarations are hoisted with their contents and are evaluated at the top of their scope as if they were expressions that were stored in a variable named for it.

    这样,它们就像变量一样被吊起,但是它们的处理方式有所不同。 函数声明随其内容一起悬挂,并在其作用域的顶部进行评估,就好像它们是存储在为其命名的变量中的表达式一样。

    But function expressions, the most common type of function type, are not hoisted in this way.

    但是,函数表达式是函数类型中最常见的类型,因此无法通过这种方式进行提升。

    函数表达式 (Function Expressions)

    It is a little unusual for a function to act as a statement. The more logical role for functions is the one that is most common as well. Most forms of functions can be thought of as values — things that can be useful somewhere else. They are a set of instructions to follow when called, and can be stored and retrieved much like a cookbook can be stored on a bookshelf (and whose recipes can be followed later).

    函数充当语句有点不寻常。 对于功能而言,更逻辑的角色也是最常见的角色。 大多数形式的函数都可以被视为值-在其他地方可能有用的东西。 它们是被调用时要遵循的一组指令,可以像将食谱存储在书架上一样进行存储和检索(以后可以遵循其食谱)。

    Function expressions are not hoisted in the same way as function statements.

    函数表达式的悬挂方式与函数语句的悬挂方式不同。

    Demonstration of function expression not being hoisted. 尚未悬挂函数表达式的演示。

    If you know how JS hoists variables and their assignments generally this should not surprise you: assignments to hoistable declarations never happen until the line they are assigned.

    如果您知道JS通常如何提升变量及其赋值,这应该不会令您感到惊讶:对可提升声明的赋值只有在分配它们的行之后才发生。

    For this reason, the most important idea in understanding JS functions is to understand that unless they are a function declaration, they are treated as expressions, or values that can be used.

    因此,理解JS函数的最重要思想是理解除非它们是函数声明,否则它们将被视为表达式或可以使用的值。

    Photo by Michael Dziedzic on Unsplash Michael Dziedzic在 Unsplash上 拍摄的照片

    那么…箭头函数,回调函数,生成器函数,IIFE? (So…Arrow Functions, Callback Functions, Generator Functions, IIFEs?)

    No matter what type of function you are using in JS, it is either a function expression or function declaration/statement. Coming to terms with arrow functions and callback functions is easier if you notice that no matter what crazy syntactical hoops they are jumping through, they are all doing more or less the same thing: either it’s a value that is being passed somewhere else, or is a declaration that registers itself and is waiting to be used.

    无论您在JS中使用哪种类型的函数,它要么是函数表达式,要么是函数声明/语句。 如果注意到箭头功能和回调函数的术语,无论它们跳过了什么疯狂的语法箍,它们都或多或少地做着相同的事情,那就更容易了:要么是在其他地方传递的值,要么是一个声明,它注册自己并等待使用。

    回调函数 (Callback Functions)

    Callback functions are not a special type of function in JS or in any programming language for that matter. Callback functions are function expressions passed as a parameter into another function.

    回调函数不是JS或任何编程语言中的特殊函数。 回调函数是作为参数传递给另一个函数的函数表达式。

    In the example above, each of the defined functions is a function declaration/statement and is referenced and used as a function expression inside the the myOwnMap function.

    在上面的示例中,每个定义的函数都是一个函数声明/声明,并在myOwnMap函数内部被引用并用作函数表达式。

    But you don’t need to have a separate declaration in order to use a callback function.

    但是您不需要使用单独的声明即可使用回调函数。

    doSomethingToNumber takes two parameters: a number, and a function. In the above example, we passed anonymous function expressions into our function call.

    doSomethingToNumber具有两个参数:一个数字和一个函数。 在上面的示例中,我们将匿名函数表达式传递到了函数调用中。

    To summarize callback functions, they are function expressions that are passed in as arguments into another function. That’s it!

    总结回调函数,它们是作为参数传递给另一个函数的函数表达式。 而已!

    Max Böttinger on 马克斯Böttinger上 Unsplash Unsplash

    箭头函数表达式 (Arrow Function Expressions)

    Arrow function expressions are a syntactical coloring on what is really just an anonymous function expression. An anonymous function is a function that doesn’t have a name property associated with it, but can still be used based upon what it was assigned to.

    箭头函数表达式是对实际上只是匿名函数表达式的一种语法着色。 匿名函数是没有名称属性与之关联的函数,但仍可以根据分配给它的内容使用。

    Arrow function expressions are supposed to simplify some code, but can be confusing if not understood correctly. Basically the things before the arrow are the parameters of the function (or just parenthesis if not argument), and the things after the arrow is the block of code to run, or the value to return (depending upon whether or not there is a value there).

    箭头函数表达式应该简化一些代码,但是如果不能正确理解,可能会造成混淆。 基本上,箭头之前的内容是函数的参数(或者如果没有参数,则只是括号),箭头之后的内容是要运行的代码块或返回的值(取决于是否有值)那里)。

    Here are some rules of thumb:

    以下是一些经验法则:

    Before the arrow:

    箭头前:

    You don’t need () if you have one parameter.

    如果有一个参数,则不需要() 。

    You need () if you have no parameters.

    如果没有参数,则需要() 。

    You need () if you have more than one parameter.

    如果您有多个参数,则需要() 。

    After the arrow:

    在箭头之后:

    You do not need {} if you are returning the result of a single expression.

    如果要返回单个表达式的结果,则不需要{} 。

    You need {} if you function block contains more than one statement.

    如果功能块包含多个语句,则需要{} 。

    You need to use the keyword return if you use {} if you want your function to return anything.

    如果要使函数返回任何内容,则如果使用{}则需要使用关键字return。

    There are a lot of options, but, seriously, arrow function expressions are just another way of writing anonymous function expressions.

    有很多选择,但是,认真地说,箭头函数表达式只是编写匿名函数表达式的另一种方法。

    关于this的注释 (A Note On this)

    this in JS is a complex subject better for another article. However, one good rule of thumb on this with regards to functions is this (pun intended): using the function keyword will give you a consistent this. Using arrow functions will give you a this that retains the value of the enclosing context’s this. In short, for now, stay away from arrow functions if you are relying upon the this keyword to fulfill the functions goals, AND you expect it to operate based upon the scope in which you wrote it, not the scope in which it is executed.

    this在JS是另一篇文章一个复杂的问题更好。 然而,在拇指的一个好的规则this与问候的功能是这样的(双关语意):使用function关键字会给你一个一致这一点。 使用箭头函数将为您提供一个this ,它保留了封闭上下文的this.的值this. 简而言之,现在,如果您依靠this关键字实现功能目标,并且希望它根据编写它的作用域而不是执行它的作用域运行,请远离箭头功能。

    From MDN:

    从MDN :

    An arrow function expression is … without its own bindings to the this, arguments, super, or new.target keywords. Arrow function expressions are ill suited as methods, and they cannot be used as constructors.

    箭头函数表达式是…,没有与this , arguments , super或new.target关键字的绑定。 箭头函数表达式不适合用作方法,并且不能用作构造函数。

    Basically, if you have any problems, ask yourself if your arrow function expression is being asked to do more than it was made for, especially when it comes to this.

    基本上,如果您有任何问题,请问自己是否要求您的箭头函数表达式做更多的工作,特别是在涉及到this 。

    发电机功能 (Generator Functions)

    Generator Functions are unique. Writing a generator function is very similar to how you write function declarations and expressions (of the non-arrow variety) except you use * and yield to make them do their magic.

    生成器功能是唯一的。 编写生成器函数与编写函数声明和表达式(非箭头类)非常相似,只不过您使用*和yield来使其发挥作用。

    How generator functions work is very specific. First you create a generator function. Then you call that generator function, and it returns an iterator object whose .next() method is used to un-suspend the generator and return a simple object with two properties, the value that was yielded when it last stopped, and a Boolean named done, which is false if the iterator has more to it, or true if there is no more to do.

    生成器功能的工作方式非常具体。 首先,您创建一个生成器函数。 然后调用该生成器函数,它返回一个迭代器对象,该对象的.next()方法用于取消悬浮生成器,并返回一个简单的对象,该对象具有两个属性,即上一次停止时产生的value和一个名为Boolean的布尔值done ,如果迭代器有更多功能,则为false,如果没有更多要做,则为true。

    Here’s a simple example:

    这是一个简单的例子:

    Simple generator function example. 简单的生成器函数示例。

    So, what’s happening here? The generator function is defined on line 1. It is called on line 9, and returns the iterator object that is used subsequently. On line 10, when myGenerator.next() is called, it starts the generator up. The generator runs all the code it finds until it finds a yield. When it finds the first yield, it pauses the function, and returns the first object, which contains the value that was yielded, and the Boolean that says the function is not completed.

    那么,这里发生了什么? 生成器函数在第1行上定义。在第9行上调用它,并返回随后使用的迭代器对象。 在第10行,当myGenerator.next()时,它将启动生成器。 生成器将运行找到的所有代码,直到找到合格为止。 当找到第一个收益率时,它将暂停该函数,并返回第一个对象,该对象包含产生的值以及表示该函数未完成的布尔值。

    Let’s look at some of the options we have when using generator functions:

    让我们看看使用生成器函数时可以使用的一些选项:

    Generator function possibilities simplified. 发电机功能的可能性得以简化。

    Let’s walk through the things that are different here. In this case allTheBells is called on line 1, before we’ve defined it, which shows that generator function declarations follow the same hoisting rules we defined earlier for function declarations. This generator function also takes a parameter called startingValue. Here it is 10. Like a regular function, this variable is created in the scope of the function and is usable in the generator function.

    让我们来看一下这里的不同之处。 在这种情况下,在定义之前,在第1行调用allTheBells ,这表明生成器函数声明遵循我们之前为函数声明定义的提升规则。 该生成器函数还接受一个名为startingValue的参数。 此处为10。与常规函数一样,此变量在函数范围内创建,并且可在生成器函数中使用。

    Notice on line 4, 5 and 7 that you can yield any expression. Notice that generator functions can run code between yields. You can think of the yield keyword kind of like a stop sign. When yield is reached, it will stop the function and return an object whose value is what was the argument of the yield. When the next next() is called, the function first returns to the function in the place of that previous yield the value it evaluates to. If the yield is not used as an expression in another statement it won’t do much, but whatever is passed into the next function is what the previous yield statement evaluates to. Walking through lines 17 and 18 (and 9 and 10) can help explain this.

    注意在第4、5和7行,您可以产生任何表达式。 请注意,生成器函数可以在yield之间运行代码。 您可以认为yield关键字有点像停车牌。 当达到yield时,它将停止该函数并返回一个对象,该对象的值就是yield的参数。 当调用下一个next()时,该函数首先返回该函数,而不是前一个yield产生的值。 如果yield在另一个语句中不用作表达式,则不会做很多事情,但是传递给下一个函数的是前一个yield语句的计算结果。 通过第17和18(以及9和10)行可以帮助解释这一点。

    When myGenerator.next() is called on line 17, it is resuming the allTheBells function from line 9. Nothing is passed into the .next() call, and there is nothing in the function to receive it anyway, so it continues the function until it gets to the next yield on line 10. It returns the argument after the yield making the object with the value of 100. The when myGenerator.next() is called on line 18, 5 is passed into it. That 5 that is passed into the .next() call is what yield 100 evaluates to, and since that value is now fully returned, the console.log of it can complete, and 5 is logged to the console. The .next() call also returns an object that tells us the value of the next yield. But there is no next yield so it returns an object whose value is undefined, and whose done is set to true.

    当在第17行调用myGenerator.next() ,它将从第9行恢复allTheBells函数allTheBells .next()调用中没有任何内容传递,并且该函数中没有任何内容可以接收它,因此它将继续该函数直到到达第10行的下一个yield为止。它将在yield之后返回参数,使对象的值为100 。 在第18行调用myGenerator.next()时,将5传递给它。 这5所传入.next()调用是什么yield 100的计算结果为,由于该值现在已经完全恢复,在console.log它可以完成,而5登录到控制台。 .next()调用还返回一个对象,该对象告诉我们下一个yield的值。 但是没有下一个yield因此它返回一个对象,其值是undefined ,并且done被设置为true 。

    I found walking through the second example on this page to be a good exercise to help me understand these functions. For now, let’s leave this topic, and move onto the last topic we’ll cover in this article: IIFEs.

    我发现遍历此页面上的第二个示例是一个很好的练习,可以帮助我理解这些功能。 现在,让我们离开该主题,转到我们将在本文中介绍的最后一个主题:IIFE。

    国际金融机构 (IIFEs)

    IIFE stands for Immediately Invoked Function Expression. We’ve seen what a function expression is, and can likely understand what invoking a function immediately is. The obscure acronym is actually describing something fairly straightforward.

    IIFE代表立即调用函数表达式。 我们已经了解了什么是函数表达式,并且可以理解立即调用函数是什么。 晦涩的缩略语实际上是在描述一些相当简单的东西。

    You might wonder what the point of using an IIFE is. One great use of them is to manage scope. The first function — engineOn — is an IIFE, and is modest in its functionality. It doesn’t do much, and so it might seem that putting all the syntax around it is pointless. Yet, we can see something interesting if we look at line 8. We get a ReferenceError when we run it. Why? The IIFE creates a function scope, and the variables created in that scope are not available in the scopes outside of it.

    您可能想知道使用IIFE的意义是什么。 它们的一大用途是管理范围。 第一个函数engineOn是IIFE,功能适中。 它没有做太多事情,因此似乎所有语法都没有意义。 但是,如果我们看一下第8行,我们会看到一些有趣的东西。运行它时,我们会遇到ReferenceError 。 为什么? IIFE创建一个函数作用域,并且在该作用域中创建的变量在其外部作用域中不可用。

    With ES6, we don’t need to use an IIFE to protect our scopes, as lines 14 through 18 show. We can get the same level of scope containment using a block and let keyword.

    使用ES6,我们不需要使用IIFE来保护示波器,如第14至18行所示。 我们可以使用block和let关键字获得相同级别的范围包含。

    So what is an IIFE useful for? Well…let that bring us to our last topic.

    那么IIFE有什么用呢? 好吧……让我们进入最后一个话题。

    可读性 (Readability)

    With so many options for creating functions, we might find ourselves slightly confused about which to choose. Well, I wrote this partially because I’ve seen every single one of these in code, and I’ve often felt confused myself about why there are so many ways of writing it, and wondering why some ways were chosen over others.

    创建函数的选项太多了,我们可能会发现自己对于选择哪个选项有些困惑。 好吧,我之所以写这篇文章,部分原因是因为我在代码中看到了其中的每一个,而且我常常对自己为什么编写这么多方法感到困惑,并且想知道为什么选择了某些方法。

    The best answer I can come up with for how to choose one version over another is that it is best to choose the syntactical function option that makes your code more readable to others. Behind the scenes, the engines that handle your code don’t care which syntax option you choose. But other programmers who read your code for the first time will care.

    关于如何选择一个版本而不是另一个版本,我能得出的最佳答案是,最好选择语法功能选项,以使您的代码对其他版本更具可读性。 在后台,处理您的代码的引擎不在乎您选择哪种语法选项。 但是其他初次阅读您的代码的程序员会关心的。

    If an anonymous arrow function is best because it eases a reader into understanding the purpose of your code, then that’s the best choice. If a named function expression is going to clarify for everyone what your unique and complex function is meant to do, then name that expression. Ultimately, it is up to you, and it is a good idea to get out of your head that some form of function syntax is inherently more advanced or better than others.

    如果匿名箭头功能是最好的,因为它可以使读者容易理解代码的目的,那么那是最佳选择。 如果命名函数表达式将为每个人澄清您独特而复杂的函数的含义,请命名该表达式。 最终,由您自己决定,让您振作起来,某种形式的函数语法本质上比其他形式更高级或更优,这是一个好主意。

    Hybrid on Hybrid Unsplash 拍摄的Unsplash

    恭喜啦 (Congratulations)

    You did it. You took time to touch on all the JS function possibilities. Good luck with your projects and applications! Remember: make it readable!

    你做到了。 您花了一些时间来探讨所有JS函数的可能性。 祝您的项目和应用程序好运! 请记住:使其可读!

    翻译自: https://medium.com/swlh/everything-you-ever-wanted-to-know-about-js-functions-but-didnt-have-the-time-to-ask-f9a52843b357

    Processed: 0.009, SQL: 8