javascript优缺点_为什么要在JavaScript中使用静态类型? 优缺点

javascript优缺点

by Preethi Kasireddy

通过Preethi Kasireddy

为什么要在JavaScript中使用静态类型? 优缺点 (Why use static types in JavaScript? The Advantages and Disadvantages)

We covered a lot of ground in Part 1! With syntax out of the way, let’s finally get to the fun part: exploring the advantages and disadvantages of using static types.

第1部分中,我们讨论了很多内容! 不用担心语法,让我们最后进入有趣的部分:探索使用静态类型的优缺点。

使用静态类型的优点 (The Advantages of using static types)

Static types offer many benefits when writing programs. Let’s explore a few of them.

静态类型在编写程序时提供许多好处。 让我们探索其中的一些。

优势1:您可以及早发现错误和错误 (Advantage 1: You can detects bugs and errors early)

Static type checking allows us to verify that the invariants we specified are true without actually running the program. And if there’s any violation of those invariants, they will be discovered before runtime instead of during it.

静态类型检查使我们无需实际运行程序即可验证我们指定的不变量为真。 而且,如果违反了这些不变量,则将在运行时而不是在运行时发现它们。

A quick example: suppose we have a simple function that takes a radius and calculates the area:

一个简单的例子:假设我们有一个简单的函数,该函数采用半径并计算面积:

Now, if we were to pass a radius which is not a number (e.g. ‘im evil’)…

现在,如果我们要传递的半径不是数字(例如,“邪恶”),…

…we’d get back NaN. If some piece of functionality relied on this calculateArea function always returning a number, then this result might lead to a bug or crash. That’s not very pleasing, is it?

…我们会取回NaN 。 如果某些依赖此calculateArea函数的功能始终返回一个数字,则此结果可能会导致错误或崩溃。 那不是很好吗?

Had we used static types, we could have specified the exact input(s) and output types for the function:

如果我们使用静态类型,则可以为该函数指定确切的输入和输出类型:

Try to pass anything but a number into our calculateArea function now, and Flow will send us a handy-dandy message:

现在尝试将数字以外的任何内容传递到我们的calculateArea函数中,Flow会向我们发送方便的消息:

Now we’re guaranteed that the function will only ever accept valid numbers as inputs and return a valid number as output.

现在我们保证该函数将只接受有效数字作为输入,并返回有效数字作为输出。

Because the type checker tells you when there are errors while you’re coding, it’s a lot more convenient (and a lot less expensive) than finding out about the bug once the code has been shipped to your customers.

因为类型检查器会在编写代码时告诉您何时有错误,所以与将代码交付给客户后发现错误相比,它更方便(并且成本更低)。

优势2:您可以获得生活证明文件 (Advantage 2: You get living documentation)

Types serve as living, breathing documentation for both ourselves and other users of our code.

类型本身就是我们自己和我们代码的其他用户的生活,呼吸的文档。

To see how, let’s look at this method that I once found in a large code base that I was working in:

为了了解如何操作,让我们看一下我曾经在工作的大型代码库中找到的这种方法:

At first glance (and the second and third), I had no idea how to use this function.

乍一看(第二和第三),我不知道如何使用此功能。

Is quote a number? Or a boolean? Is payment method an object? Or maybe it’s a string representing the type of payment method? Does the function return the date as a string? Or as a Date object?

number吗? 还是boolean ? 付款方式是object吗? 还是它是表示付款方式类型的string ? 函数是否以string返回日期? 还是作为Date对象?

No clue.

没有线索。

My solution at the time was to evaluate the business logic and grep through the codebase until I figured it out But that’s a lot of work just to understand how a simple function works.

当时我的解决方案是评估代码中的业务逻辑和grep,直到我弄清楚为止。但是,要了解简单函数的工作原理,这需要做很多工作。

On the other hand, if we had written something like:

另一方面,如果我们写过类似的东西:

It becomes immediately clear what type of data the function takes as input and what type of data it returns as output. This demonstrates how we can use static types to communicate the intent of the function. We can tell other developers what we expect from them, and can see what they expect from us. Next time someone goes to use this function, there will be no questions asked.

可以立即清楚地知道该函数将哪种类型的数据作为输入,以及将哪种类型的数据作为输出返回。 这说明了我们如何使用静态类型来传达函数的意图 。 我们可以告诉其他开发人员我们对他们的期望,并可以看到他们对我们的期望。 下次有人使用该功能时,将不会有任何问题。

There’s an argument to be made that adding code comments or documentation could solve the same problem:

有一个论点是,添加代码注释或文档可以解决相同的问题:

This works. But it’s way more verbose. Beyond verbosity, code comments like this are difficult to maintain because they’re unreliable and lack structure — some developers might write good comments, some might write obscure comments, and some might forget to write them at all.

这可行。 但这更冗长。 除了冗长之外,像这样的代码注释还难以维护,因为它们不可靠且缺乏结构-一些开发人员可能会编写良好的注释,有些可能编写晦涩的注释,而有些则可能根本忘记编写它们。

It’s especially easy to forget to update them when you refactor. Type annotations, however, have a defined syntax and structure and can never go out of date — they’re encoded into the code.

重构时,忘记更新它们特别容易。 但是,类型注释具有已定义的语法和结构,并且永远不会过时-它们已编码为代码。

优点3:减少了复杂的错误处理 (Advantage 3: It reduces convoluted error handling)

Types help remove convoluted error handling. Let’s revisit our calculateArea function to see how.

类型有助于消除复杂的错误处理。 让我们重新看看我们的calculateArea函数,看看如何。

This time, I’ll have it take an array of radii and calculate the area for each radius:

这次,我将使用半径数组并计算每个半径的面积:

This function works, but doesn’t properly handle invalid input arguments. If we wanted to make sure that we properly handle cases where the input is not a valid array of numbers, we’d end up with a function that looks like:

此函数有效,但不能正确处理无效的输入参数。 如果我们想确保我们能够正确处理输入不是有效数字数组的情况,那么我们将得到一个看起来像这样的函数:

Wow. That’s a lot of code for a little bit of functionality.

哇。 大量功能所需的大量代码。

But with static types, we could simply do:

但是对于静态类型,我们可以简单地执行以下操作:

Now the function actually looks like what it originally looked like without all the visual clutter from error handling.

现在,该函数实际上看起来像它原来的样子,而没有来自错误处理的所有视觉混乱。

Easy enough to see the benefit, right? :)

很容易看到好处,对吗? :)

优势4:您可以更有信心地进行重构 (Advantage 4: You can refactor with greater confidence)

I’ll explain this one through an anecdote: I was working in a very large codebase once and there was a method defined on the User class that we needed to update — specially, we needed to change one of the function parameters from a string to an object.

我将通过一个轶事对此进行解释:我曾经在一个非常大的代码库中工作,并且在User类上定义了一个需要更新的方法-特别是,我们需要将一个函数参数从string更改为一个object

I made the change, but was having cold feet to commit the change — there were so many invocations of this function sprinkled around the code base that I had no idea if I’d updated all the instances properly. What if I missed some invocation deep in some untested helpers file?

我进行了更改,但是提交更改时措手不及-遍历代码库的函数调用太多,我不知道是否正确更新了所有实例。 如果我错过了一些未经测试的帮助程序文件中的某个调用,该怎么办?

The only way to know was to ship the code and pray that it didn’t blow up with errors.

唯一知道的方法是发送代码并祈祷它不会因错误而崩溃。

Using static types would have avoided this. It would have given me the assurance and peace of mind that if I updated a function and in turn, updated the type definitions, the type checker would be there for me to catch all the errors I missed. All I’d have to do is go through those type errors and fix them.

使用静态类型可以避免这种情况。 如果我更新了一个函数,然后又更新了类型定义,那将使我放心而放心,如果我更新了类型定义,则类型检查器将在那里捕获我错过的所有错误。 我要做的就是检查这些类型错误并修复它们。

优势5:它将数据与行为分开 (Advantage 5: It separates data from behavior)

One less talked-about benefit of static types is that they help separate data from behavior.

静态类型的一个鲜为人知的好处是它们有助于将数据与行为分开。

Let’s revisit our calculateAreas function with static types:

让我们重新使用静态类型的calculateAreas函数:

Think about how we’d go about composing this function. Because we’re annotating types, we are forced to first think about the type of data we intend to use so that we can appropriately define the input and output types.

考虑一下我们将如何组成此函数。 因为我们在注释类型,所以我们被迫首先考虑要使用的数据类型,以便我们可以适当地定义输入和输出类型。

Only then do we implement the logic:

只有这样我们才能实现逻辑:

This ability to precisely express the data separate from the behavior allows us to be explicit about our assumptions and more accurately convey our intent, which relieves some mental burden and brings some mental clarity to the programmer. Without it, we are left to track this mentally in some fashion.

这种精确地将数据与行为分开表达的能力使我们能够明确假设,并更准确地传达我们的意图,这减轻了一些精神负担,并为程序员带来了一些头脑清晰的感觉。 没有它,我们将以某种方式在心理上进行追踪。

优点6:消除了整个类别的错误 (Advantage 6: It eliminates an entire category of bugs)

One of the most common errors or bugs we encounter as JavaScript developers are type errors at runtime.

我们在JavaScript开发人员中遇到的最常见的错误或错误之一是运行时的类型错误。

For instance, let’s say our initial application state is defined as:

例如,假设我们的初始应用程序状态定义为:

And let’s assume that we then make an API call to fetch the messages in order to populate our appState. Next, our app has an overly simplified view component that takes in the messages (defined in our state) as a prop and displays the unread count and each message as a list item:

并假设我们随后进行API调用以获取消息,以填充appState 。 接下来,我们的应用程序具有一个过于简化的视图组件,该组件以messages (在我们的状态中定义)为支撑,并显示未读计数和每条消息为列表项:

If the API call to fetch the messages fails or returns undefined, we’d end up with a type error in production:

如果获取消息的API调用失败或返回undefined ,那么我们将在生产中遇到类型错误:

TypeError: Cannot read property ‘length’ of undefined

TypeError: Cannot read property 'length' of undefined

… and your program crashes. You lose a customer. Bummer.

…,程序崩溃。 你失去了客户。 笨蛋

Let’s see how types can help us. We’ll start by adding Flow types to our application state. I’ll type alias the AppState and then use that to define the state:

让我们看看类型如何为我们提供帮助。 首先,将Flow类型添加到应用程序状态。 我将输入AppState别名,然后使用它来定义状态:

Since our API to fetch messages is known to be unreliable, here we’re saying that messages is a maybe type of an array of strings.

由于我们已知的获取消息的API是不可靠的,因此在这里我们说messages是字符串数组的一种maybe类型。

Same deal as last time — we fetch our messages from the unreliable API and use it in our view component:

与上次相同—我们从不可靠的API获取消息,并在我们的视图组件中使用它:

Except now, Flow would catch our error and complain:

除了现在,Flow会发现我们的错误并抱怨:

Whoa buddy!

哇,哥们!

Because we defined messages as a maybe type, we are saying that it is allowed to be null or undefined. But it still does not allow us to perform operations on it (like .length or .map) without doing a null check because if the messages value was in fact null or undefined, we’d end up with a type error if we perform any operation on it.

因为我们将messages定义为maybe类型,所以我们说它可以为nullundefined 。 但是它仍然不允许我们对它执行操作(如.length.map )而不进行null检查,因为如果messages值实际上为nullundefined ,那么如果执行任何操作都会导致类型错误操作就可以了。

So let’s go back and update our view function to be something like:

因此,让我们返回并将视图功能更新为:

Flow now knows that we’ve handled the case where messages is null or undefined, and so the code type checks with 0 errors. Long dead runtime type errors :)

Flow现在知道我们已经处理了message为nullundefined ,因此代码类型检查错误为0。 长时间无效的运行时类型错误:)

优点7:减少了单元测试的次数 (Advantage 7: It reduces the number of unit tests)

We saw earlier how static types can help eliminate convoluted error handling because they guarantee input and output types. As a result, they also reduce the # of unit tests.

前面我们已经看到静态类型如何帮助消除复杂的错误处理,因为它们可以保证输入和输出类型。 结果,它们还减少了单元测试的数量。

For instance, let’s go back to our dynamically-typed calculateAreas function with error handling:

例如,让我们回到带有错误处理的动态类型的calculateAreas函数:

If we were diligent programmers, we might have thought to test invalid inputs to make sure they are handled correctly in our program:

如果我们是勤奋的程序员,我们可能会考虑测试无效的输入,以确保它们在程序中得到正确的处理:

… and so on. Except it’s very likely that we forget to test some edge cases — then our customer is the one to discover the problem. :(

… 等等。 除了极有可能我们忘记测试某些极端情况之外,我们的客户才是发现问题的人。 :(

Since tests are solely based on the cases we think to test, they are existential and easy to circumvent.

由于测试仅基于我们认为要测试的案例,因此它们是存在的且易于规避。

On the other hand, when we’re required to define types:

另一方面,当我们需要定义类型时:

…not only are we guaranteed that our intent matches reality, but they are also simply harder to escape. Unlike empirically-based tests, types are universal and difficult to be wishy-washy around.

……不仅可以保证我们的意图与现实相符,而且它们也更难逃脱。 与基于经验的测试不同,类型是通用的,很难被随意修饰。

The big picture here is: tests are great at testing logic, and types at testing data types. When combined, the sum of the parts is greater than the whole.

这里的大图是:测试擅长于测试逻辑,类型擅长于测试数据类型。 组合时,各部分的总和大于整体。

优势8:它提供了领域建模工具 (Advantage 8: It provides a domain modeling tool)

One of my favorite use cases for types is domain modeling. A domain model is a conceptual model of a domain that includes both the data and behavior on that data. The best way to understand how you can use types to do domain modeling is by looking at an example.

我最喜欢的类型用例之一是域建模。 域模型是域的概念模型,其中既包含数据又包含该数据的行为。 了解如何使用类型进行域建模的最佳方法是看一个示例。

Let’s say I have an application where a user has one or more payment methods to make purchases on the platform. There are three types of payment methods they’re allowed to have (Paypal, Credit card, Bank Account).

假设我有一个应用程序,其中用户使用一种或多种付款方式在平台上进行购买。 允许使用三种付款方式(Paypal,信用卡,银行帐户)。

So we’ll first type alias these three different payment method types:

因此,我们将首先为这三种不同的付款方式类型输入别名:

Now we can define our PaymentMethod type as a disjoint union with three cases:

现在,我们可以将PaymentMethod类型定义为以下三种情况的不相交联合:

Next, let’s model our app state. To keep it simple, let’s assume that our app data only consists of the user’s payment methods.

接下来,让我们为应用程序状态建模。 为简单起见,假设我们的应用程序数据仅由用户的付款方式组成。

Is this good enough? Well, we know that to get the user’s payment methods, we need to make an API request, and depending on where in the fetching process we are, our app will have different states. So there’s actually four possible states:

这样够好吗? 好吧,我们知道要获取用户的付款方式,我们需要发出一个API请求,并且根据我们在获取过程中的位置,我们的应用程序将具有不同的状态。 因此,实际上有四种可能的状态:

1) We haven’t fetched the payment methods2) We are fetching the payment methods3) We successfully fetched the payment methods4) We tried fetching but there was an error fetching the payment methods

1)我们尚未获取付款方式2)我们正在获取付款方式3)我们成功获取了付款方式4)我们尝试获取但获取错误的付款方式

But our simple Model type with paymentMethods doesn’t cover all these cases. Instead, it assumes that paymentMethods always exists.

但是我们带有paymentMethods简单Model类型无法涵盖所有​​这些情况。 相反,它假定paymentMethods始终存在。

Hmmm. Is there a way to model our app state to be one of these four cases, and only these four cases? Let’s take a look:

嗯 有没有一种方法可以将我们的应用程序状态建模为这四种情况之一,并且只有这四种情况? 让我们来看看:

We used a disjoint union type to define our state as one of the four scenarios described above. Notice how I am using a type property to determine which of the four states our app is in. This type property is actually what makes this a disjoint union. Using this, we can do case analysis to determine when we have the payment methods and when we don’t.

我们使用脱节联合类型将状态定义为上述四种情况之一。 请注意,我是如何使用type属性确定应用程序处于四个状态中的哪个状态的。此type属性实际上是使它成为不相交联合的原因。 使用此方法,我们可以进行案例分析,以确定何时使用付款方式以及何时不使用付款方式。

You’ll also notice that I pass in a generic type E and D into the app state. Type D will represent the user’s payment method (PaymentMethod defined above). We haven’t defined type E, which will be our error type, so let’s do that now:

您还会注意到,我将通用类型ED传递到应用程序状态。 类型D将代表用户的付款方式( PaymentMethod定义的PaymentMethod )。 我们尚未定义类型E ,这将是我们的错误类型,所以让我们现在开始:

Now, we can model our app domain as:

现在,我们可以将应用程序域建模为:

In summary, the signature for our app state is now AppState<E, D> — where E is of the shape HttpError and D is PaymentMethod. And AppState has four (and only these four) possible states: NotFetched, Fetching, Failure and Success.

总之,我们的应用程序状态的签名是现在AppState<E, d> - w这里E是的shape Htt佩罗rD is Payment方式. And Ap . And Ap pState有四个(只有这四个)可能的状态ates: NotF et ates: NotF ched, Fe hing, F失败e and S成功。

I find this type of domain modeling useful for thinking about and building user interfaces against certain business rules. The business rules tells us that our app can only ever be in one of these states. So this allows us to explicitly represent build our app state and guarantees that it will only ever be in one of the pre-defined states. And when we build off of this model (e.g. to create a view component), it comes blatantly obvious that we need to handle all four possible states.

我发现这种类型的域建模对于思考和构建针对某些业务规则的用户界面很有用。 业务规则告诉我们,我们的应用程序只能处于以下状态之一。 因此,这使我们可以明确表示构建应用程序状态,并保证它永远不会处于预定义状态之一。 当我们建立这个模型(例如创建一个视图组件)时,很明显我们需要处理所有四种可能的状态。

Moreover, the code become self-documenting — you can look at the union cases and immediately figure out how the app state is structured.

而且,代码变成了自我记录的文件-您可以查看并用例并立即弄清楚应用程序状态的结构。

使用静态类型的缺点 (The Disadvantages of using static types)

Like anything else in life and programming, static type checking comes with its tradeoffs.

就像生活和编程中的其他任何事情一样,静态类型检查也会带来一些折衷。

It’s important that we understand and acknowledge them so we can make an informed decision of when static types make sense and when they simply aren’t worth it.

重要的是我们要理解并认可它们,以便我们能够明智地决定何时应该使用静态类型,以及何时根本不应该使用它们。

Here are a few of those considerations:

以下是一些注意事项:

劣势1:静态类型需要预先投资才能学习 (Disadvantage 1: Static types require investment upfront to learn)

One reason JavaScript is such a fantastic language for beginners is because it doesn’t require the student to learn an entire type system before they can be productive in the language.

JavaScript对初学者来说是一种很棒的语言的一个原因是,它不需要学生在学习该语言之前就能学习整个类型系统。

When I initially learned Elm (a statically-typed functional language), the types often got in the way. I would constantly run into compiler errors related to my type definitions.

当我最初学习Elm(一种静态类型的功能语言)时,通常会遇到这种类型的问题。 我会经常遇到与我的类型定义有关的编译器错误。

Learning how to use the type system effectively has been half the battle in learning the language itself. As a result, static types made the learning curve for Elm steeper than for JavaScript.

学习如何有效使用类型系统已成为学习语言本身的一半。 结果,静态类型使Elm的学习曲线比JavaScript陡峭。

This matters especially for beginners where the cognitive load of learning syntax is at an all time high. Adding types to the mix can overwhelm a beginner.

这对于学习语法的认知负荷一直很高的初学者尤其重要。 在混音中添加类型可能会使新手不知所措。

劣势2:粗俗会使你陷入困境 (Disadvantage 2: Verbosity can bog you down)

Static types often make programs look more verbose and cluttered.

静态类型通常使程序看起来更冗长和混乱。

For example, instead of:

例如,代替:

We’d have to write:

我们必须写:

And instead of:

而不是:

We’d have to write:

我们必须写:

Obviously, this can add extra lines of code. But there are a couple arguments against this being a real downside.

显然,这会增加额外的代码行。 但是,有很多人反对这是一个真正的弊端。

Firstly, as we mentioned earlier, static types help eliminate an entire category of tests. Some developers would consider this a perfectly reasonable tradeoff.

首先,正如我们前面提到的,静态类型有助于消除整个测试类别。 一些开发人员会认为这是一个完全合理的权衡。

Secondly, as we saw earlier, static types can sometimes eliminate the convoluted error handling and in turn reduce the visual clutter of code significantly.

其次,正如我们前面所看到的,静态类型有时可以消除复杂的错误处理,进而显着减少代码的视觉混乱。

It’s hard to say whether verbosity is a real argument against types, but it’s one worth keeping in mind.

很难说冗长性是否是针对类型的真正论点,但值得牢记。

劣势3:类型需要时间来掌握 (Disadvantage 3: Types take time to master)

It takes time and lots of practice to learn how best to specify types in a program. Moreover, developing a good sense for what is worth tracking statically and what to keep dynamic also requires careful thought, practice, and experience.

学习如何最好地指定程序类型需要花费时间和大量练习。 此外,要对应该静态跟踪的内容和要保持动态的内容建立良好的感觉,还需要仔细的思考,实践和经验。

For example, one approach we might take is to encode critical business logic with types, while leaving short-lived or unimportant pieces of logic dynamic to avoid needless complexity.

例如,我们可能采用的一种方法是使用类型对关键业务逻辑进行编码,同时保留短暂或不重要的逻辑动态以避免不必要的复杂性。

This distinction can be tough to make, especially when developers less experienced with types are making judgment calls on the fly.

这种区分可能很难做到,尤其是当对类型缺乏经验的开发人员在进行动态判断时。

劣势4:静态类型会阻碍快速发展 (Disadvantage 4: Static types can hold up rapid development)

As I mentioned earlier, types tripped me up a bit when I was learning Elm — particularly when adding code or making changes. Constantly being distracted by compiler errors made it difficult to feel like I was making any progress.

正如我前面提到的,当我学习Elm时,类型使我有些不适,尤其是在添加代码或进行更改时。 不断地因编译器错误而分散注意力,这使我很难感到自己正在取得任何进展。

The argument here is that static type checking might cause a programmer to lose focus too often — and as we know, focus is key for writing good programs.

这里的论点是,静态类型检查可能会导致程序员过于频繁地失去焦点-并且我们知道,焦点是编写好的程序的关键。

Not only that, but static type checkers aren’t always perfect. Sometimes you run into situations where you know what you need to do and the type checking just gets in the way.

不仅如此,静态类型检查器并不总是完美的。 有时,您会遇到一些情况,您知道自己需要做什么,而类型检查就成为了障碍。

I’m sure there are other tradeoffs I’m missing, but these were the big ones for me.

我确定还有其他折衷方案,但这些对我来说是很大的。

接下来, 最后的结论 (Up next, the final conclusion)

In the final section, we’ll conclude by discussing whether it makes sense to use static types.

最后一节中 ,我们将讨论使用静态类型是否有意义。

I’ll see you there.

我在那儿见。

翻译自: https://www.freecodecamp.org/news/why-use-static-types-in-javascript-part-2-part-3-be699ee7be60/

javascript优缺点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值