您应该知道的11个JavaScript和TypeScript速记

There is a very fine line between writing clean and efficient code and writing code that only you can read. And the worst part is, that line is not universal, some people would draw it much further than others so when it comes to deciding if a piece of code is legible enough for everyone we tend to stay away from using many shorthands such as ternary operators, on-line arrow functions and whatnot.

在编写简洁高效的代码与编写仅可读的代码之间有一条很好的界限。 最糟糕的是,这条线不是通用的,有些人会比其他人画得更远,因此,在确定一段代码是否对每个人都足够清晰时,我们倾向于避免使用许多速记(如三元运算符) ,在线箭头功能等。

But the ugly truth is: sometimes, those shorthands come in very handy and are easy enough that anyone who’s interested enough in reading our code can and will understand them.

但是,丑陋的事实是:有时,这些速记法非常方便并且非常容易,以至于对阅读我们的代码有足够兴趣的任何人都可以并且将会理解它们。

So in this article, I want to cover some very useful (and sometimes cryptic) shorthands that you can find both in JavaScript and in TypeScript so you can either use them yourself or at least, have know them in case the person who’s code you’re reading has used them.

因此,在本文中,我想介绍一些非常有用的(有时是晦涩的)速记,您可以在JavaScript和TypeScript中找到它们,以便您可以自己使用它们,或者至少可以使用它们,以防万一您编写代码的人重新阅读已使用它们。

1.空位合并运算符 (1. The Nullish Coalescing Operator)

With a name like that, it’s hard to believe it’s not one of the most popular operators in the language, am I right?

有了这样的名字,很难相信它不是该语言中最受欢迎的运算符之一,对吗?

The point of this operator, is to allow you to return a value if the evaluated expression is either null or undefined which is not exactly what the name implies, but oh well. Here is how you’d use it:

此运算符的要点是,如果所计算的表达式为nullundefined ,返回的值不完全是该名称所隐含的含义,但是很好。 这是您的使用方式:

function myFn(variable1, variable2) {
  let var2 = variable2 ?? "default value"
  return variable1 + var2
}


myFn("this has", " no default value") //returns "this has no default value"
myFn("this has no") //returns "this has no default value"
myFn("this has no", 0) //returns "this has no 0"

Pretty much like the || operator, the logic behind it is the same: if the left side of the expression is evaluated to null or undefined it’ll return the right side, otherwise, it’ll return the left side. So for generic default values where you can have any type of value assigned and are looking to make sure you don’t have to deal with an undefined or null then this is the way to go.

几乎像|| 运算符,其背后的逻辑是相同的:如果表达式的左侧计算为nullundefined它将返回右侧,否则将返回左侧。 因此,对于通用默认值,可以在其中分配任何类型的值,并希望确保不必处理undefinednull那么这就是方法。

2.逻辑无效分配 (2. Logical nullish assignment)

This one is an extension of the previous one, you can use the ??= operator to do both at the same time: check for a nullish coalscing value and assign it if it is one.

这是前一个的扩展,可以同时使用??=运算符同时执行这两个操作:检查空合并值并将其分配为1。

Let’s take another crack at the same code sample:

让我们在相同的代码示例中进行另外的破解:

function myFn(variable1, variable2) {
  variable2 ??= "default value"
  return variable1 + var2
}


myFn("this has", " no default value") //returns "this has no default value"
myFn("this has no") //returns "this has no default value"
myFn("this has no", 0) //returns "this has no 0"

The assignment operator allows us to check for the value of variable2 and if it evaluates to either null or undefined then the assignment will go through, otherwise it will never happen.

赋值运算符允许我们检查variable2的值,如果它的值为nullundefined则赋值将通过,否则将永远不会发生。

Warning: this syntax can be confusing to others that aren’t familiar with this operator, so if you’re using it you might as well leave a one-line comment explaining what’s happening.

警告:此语法可能会使其他对该运算符不熟悉的人感到困惑,因此,如果您使用它,则最好在一行注释中说明正在发生的事情。

3. TypeScript的构造函数速记 (3. TypeScript’s constructor shorthand)

This one is specific to TypeScript, os if you’re a JavaScript purist, your missing out! (nah, just kidding, but you can’t do this with plain JS).

这是TypeScript特有的,如果您是JavaScript的纯粹主义者,那您就错了! (不,只是在开玩笑,但是您不能使用普通JS来做到这一点)。

You know how when defining a class you usually list all properties with their corresponding visibility and then inside the constructor, you assign their values? Well, for those cases where your constructor is very simple and you’re just assigning values received as parameters, there is a shorthand for you.

您知道在定义类时通常如何列出所有属性及其相应的可见性,然后在构造函数中分配它们的值吗? 好吧,对于那些您的构造函数非常简单并且您只是将接收到的值分配为参数的情况,这是一个简写。

Let me show you:

让我给你演示:

//Old way...
class Person {
  
  private first_name: string;
  private last_name: string;
  private age: number;
  private is_married: boolean;
  
  constructor(fname:string, lname:string, age:number, married:boolean) {
    this.first_name = fname;
    this.last_name = lname;
    this.age = age;
    this.is_married = married;
  }
}


//New, shorter way...
class Person {


  constructor( private first_name: string,
               private last_name: string,
               private age: number,
               private is_married: boolean){}
}

This one is definitely a time-saver, specially if you have a class with a lot of properties.

这绝对是一个节省时间的程序,特别是如果您有一个具有很多属性的类。

Essentially what you want to make sure, is that you don’t forget to add that {} right after the constructor, since that’s the body of the function. And that’s it, the rest is done by the compiler, understanding what we’re trying to achieve, it’ll turn both versions of the code into the same JavaScript snippet.

本质上,您要确保的是,不要忘了在构造函数之后添加{} ,因为这是函数的主体。 就是这样,其余的工作由编译器完成,了解了我们要实现的目标,它将把两个版本的代码转换为相同JavaScript代码段。

Tip: Share your reusable modules/components between projects using Bit (Github). Bit makes it simple to share, document and organize independent components from any project.

提示:使用Bit ( Github )在项目之间共享可重复使用的模块/ 组件 。 Bit使共享,记录和组织来自任何项目的独立组件变得简单

Use it to maximize code reuse, collaborate on independent components and build apps that scale.

使用它可以最大程度地重复使用代码,在独立组件上进行协作并构建可扩展的应用程序。

Bit supports Node, TypeScript, React, Vue, Angular, and more.

Bit支持Node,TypeScript,React,Vue,Angular等。

4.三元运算符 (4. The ternary operator)

This one is relatively easy to read and it tends to be used instead of one-line IF..ELSE statements, because it removes a lot of unneeded characters and turns four lines into one.

该代码相对易于阅读,并且倾向于代替单行的IF..ELSE语句使用,因为它删除了许多不需要的字符并将四行变为一。

// Original IF..ELSE statement
let isOdd = ""
if(variable % 2 == 0) {
  isOdd = "yes"
} else {
  isOdd = "no"
}


//The ternary approach
let isOdd = (variable % 2 == 0) ? "yes" : "no"

You can see the structure of the ternary operator essentially has the boolean expression first, then a sort of “return” statement for the case when said expression is true and a “return” statement for the case when the expression is false. Although best used on the right side of an assignment (as in the example), it can also be used alone as a way to execute a function call depending on the value of a boolean expression.

您可以看到三元运算符的结构首先具有布尔表达式,然后是在表达式为true的情况下的“ return”语句和表达式为false的情况的“ return”语句。 尽管最好在赋值的右侧使用(如示例中所示),但也可以将其单独用作执行函数调用的方式,具体取决于布尔表达式的值。

let variable = true;


(variable) ? console.log("It's TRUE") : console.log("It's FALSE")

Notice that the format is the same, the issue here is that if in the future you need to expand one of the sections here (either for when the expression is true or false), you’ll have to turn it into a full-blown IF..ELSE statement.

请注意,格式是相同的,这里的问题是,如果将来您需要在此处扩展其中一个部分(对于表达式为true或false的情况),则必须将其变成完整的IF..ELSE语句。

5.利用OR的惰性评估 (5. Take advantage of OR’s lazy evaluation)

In JavaScript (and thus TypeScript as well) the OR logical operator follows a lazy evaluation model, meaning, it’ll return the first expression that returns true and it won’t keep checking for the rest.

在JavaScript(以及TypeScript)中, OR逻辑运算符遵循一个惰性评估模型,这意味着它将返回第一个返回true的表达式,而不会继续检查其余表达式。

This means that if you have the following IF statement, only the first two expressions will be evaluated:

这意味着,如果您具有以下IF语句,则仅对前两个表达式进行求值:

if( expression1 || expression2 || expression3 || expression4)

Assuming expression1 is falsy (i.e it returns a value that is evaluated to false ) and expression2 is truthy (i.e it returns a value that is evaluated to true ) then the evaluation will stop there.

假设expression1falsy (即它返回一个评估为false的值),而expression2truthy (即它返回一个评估为true的值),则评估将在那里停止。

We can take advantage of this lazy evaluation, and instead of using it inside the IF statement, we can use it as part of an assignment in order to provide a default value in case your expression fails or is undefined :

我们可以利用这种惰性计算,而不是在IF语句中使用它,而可以将其用作分配的一部分,以便在表达式失败或undefined情况下提供默认值:

function myFn(variable1, variable2) {
  let var2 = variable2 || "default value"
  return variable1 + var2
}


myFn("this has", " no default value") //returns "this has no default value"
myFn("this has no") //returns "this has no default value"

The example above shows how you can use the OR operator to set a default value for the second parameter of the function. Now, if you look closely though, you’ll find a small problem with this approach: if variable2 has the value of 0 or an empty string, you’ll be setting the default value on var2 because they both evaluate to false.

上面的示例显示了如何使用OR运算符为函数的第二个参数设置默认值。 现在,如果您仔细观察,将会发现这种方法存在一个小问题:如果variable2的值为0或一个空字符串,则将在var2上设置默认值,因为它们的值都为false

So if your use case allows for falsy values to be valid values as well, then you might want to look at a lesser known operand called the “Nullish coalescing operator”.

因此,如果您的用例也允许将falsy值设为有效值,那么您可能希望查看一个鲜为人知的操作数,称为“空值合并运算符”。

6.双按位NOT运算符 (6. The double bitwise NOT operator)

Bitwise operators are the ones we tend to stay away of, because honestly, who needs to think about bits nowadays right? The thing is, however, that because of the way they work directly on the bits of your numbers, they perform their operations a lot faster than normal method calls.

逐位运算符是我们倾向于远离的运算符,因为老实说,如今谁需要考虑位呢? 事实是,由于它们直接在数字的位上工作的方式,因此它们执行操作的速度比正常方法调用快得多。

In this case, the bitwise NOT operator (i.e ~) will grab your numbers, it’ll turn them into a 32bits integer (discarding any extra bits) and then it’ll invert all their bits essentially turning any integer of value x into -(x+1) . Why do we care the about this operator? Because if we use it twice on the same value, we get the same result as the Math.floor method.

在这种情况下,按位NOT运算符(即〜)将获取您的数字,将其转换为32位整数(丢弃任何多余的位),然后将其所有位求反,实际上将值x任何整数转换为-(x+1) 。 为什么我们关心此运算符? 因为如果在相同的值上使用两次,则得到的结果与Math.floor方法相同。

let x = 3.8
let y = ~x //this turns x into -(3 + 1), remember, the number gets turned into an integer
let z = ~y //this turns y (which is -4) into -(-4 + 1) which is 3


//So you can do:


let flooredX = ~~x //and this performs both steps from above at the same time

Notice the double ~ on the last line, although it might look weird, if you’re having to deal with turning multiple floating-point numbers into integers, this might be a good shorthand for you.

请注意最后一行上的double〜,虽然看起来很奇怪,但是如果您不得不处理将多个浮点数转换为整数的情况,那么这对您来说可能是一个很好的速记。

7.对象属性分配 (7. Object property assignment)

ES6 simplified the process of object creation when you’re assigning values to your properties. If the values are assigned to variables named exactly like your object’s properties, then you no longer have to repeat the names like you had to before:

在为属性分配值时,ES6简化了对象创建的过程。 如果将值分配给与对象属性完全一样命名的变量,则不再需要像以前一样重复名称:

let name:string = "Fernando";
let age:number = 36;
let id:number = 1;


type User = {
  name: string,
  age: number,
  id: number
}


//Old way
let myUser: User = {
  name: name,
  age: age,
  id: id
}


//new way
let myNewUser: User = {
  name,
  age,
  id
}

As you can see, the new way is definitely shorter and easier to write whilst at the same time, not harder to read (unlike other shorthand tips shown in this article).

如您所见,新方法肯定更短,更容易编写,同时又不难阅读(不同于本文中显示的其他速记技巧)。

8.箭头函数的隐式返回 (8. Implicit return from arrow functions)

Did you know arrow functions that are only one line long, also return the result from that line of code?

您是否知道只有一行长的箭头函数也会返回该行代码的结果?

Essentially, this tip allows you to save a redundant return statement. A very commonplace to find these type of shorthand being used is on array methods, such as filter or map, like this:

本质上,此技巧使您可以保存冗余的return语句。 查找正在使用的这些速记类型的一个非常普遍的情况是在数组方法上,例如filtermap ,如下所示:

let myArr:number[] = [1,2,3,4,5,6,7,8,9,10]


//Long way of doing it:
let oddNumbers:number[] = myArr.filter( (n:number) => {
  return n % 2 == 0
})


let double:number[] = myArr.map( (n:number) => {
  return n * 2;
})




//Shorter way:
let oddNumbers2:number[] = myArr.filter( (n:number) => n % 2 == 0 )


let double2:number[] = myArr.map( (n:number) =>  n * 2 )

This one doesn’t necesarily add complexity to your code, and it’s a nice way of cleaning up your syntax a bit removing unwanted spaces and lines. Of course, the downside here is that if you ever need to add extra logic to those lines, you’ll have to add back the curly brackets.

这一代码不必增加代码的复杂性,它是清理语法的一种好方法,可以消除不必要的空格和行。 当然,这里的缺点是,如果您需要在这些行中添加额外的逻辑,则必须重新添加大括号。

The only caveat here is that whatever you attempt to execute on your one-line function needs to be an expression (i.e something you can return), otherwise it won’t work. For instance, you can’t have a one-liner like this:

这里唯一需要注意的是,无论您试图在单行函数上执行什么,都必须是一个表达式(即可以返回的内容),否则它将不起作用。 例如,您不能拥有像这样的单线:

const m = _ => if(2) console.log("true")  else console.log("false")

And you’ll see another example of a one-liner that requires curly brackets in the next example, so let’s move on.

在下一个示例中,您将看到另一个需要大括号的单线示例,让我们继续。

9.默认功能参数 (9. Default function parameters)

Thanks to ES6, you can now specify default values on function parameters. On the previous version of JavaScript this wasn’t possible, thus you’d have to resort to using something like OR’s lazy evaluation.

感谢ES6,您现在可以在函数参数上指定默认值。 在以前JavaScript版本中,这是不可能的,因此您必须诉诸于使用OR的惰性评估之类的方法。

But now it’s as easy as writing:

但是现在它就像编写代码一样简单:

//We can function without the last 2 parameter because a default value
//can be assigned to them
function myFunc(a, b, c = 2, d = "") {
  //your logic goes here...
}

Simple enough isn’t it? Well, it actually get’s a little more interesting, since the value can be anything, including a function call which will get executed if you don’t overwrite it with your own value, thus allowing you to also implement a mandatory function parameter pattern really easy. Check it out:

很简单,不是吗? 好吧,它实际上会更有趣,因为该值可以是任何值,包括一个函数调用,如果您不使用自己的值覆盖它,该调用将被执行,从而使您也可以轻松实现强制性的函数参数模式。 看看这个:

const mandatory = _ => {
  throw new Error("This parameter is mandatory, don't ignore it!")
}




function myFunc(a, b, c = 2, d = mandatory()) {
  //your logic goes here...
}


//Works great!
myFunc(1,2,3,4)


//Throws an error
myFunc(1,2,3)

Like I said, the one-liner mandatory needs the curly brackets because it’s using throw which is a statment instead of an expression. But you still get the cool mandatory parameter behavior with very little effort.

就像我说的那样,单行mandatory需要使用大括号,因为它使用的是throw ,它是语句而不是表达式。 但是,您仍然可以很轻松地获得很酷的强制参数行为。

10.用!!将任何值转换为布尔值! (10. Casting any value to a boolean with !!)

In a similar note to the double bitwise NOT operator, you can use the double logical NOT operator to cast any value to a boolean.

在类似于双按位NOT运算符的注释中,可以使用双逻辑NOT运算符将任何值转换为布尔值。

!!23 // TRUE
!!"" // FALSE
!!0 // FALSE
!!{} // TRUE

The single logical NOT will already do that for you, it’ll cast the value to apply it to into a boolean and then it’ll negate it, so the second logical NOT will take care of negating it againg, thus returning it to it’s original meaning, while keeping it as a boolean type.

单个逻辑非将已经为您完成此操作,它将强制将值转换为布尔值,然后将其取反,因此第二个逻辑非将负责再次对其求反,从而将其返回给它。原义,同时将其保留为布尔型。

This shorthand is useful in those cases where you either have to be sure you’re assigning an actual boolean (such as a TypeScript variable of type boolean ) or when doing a strict comparison against either true or false (with ===).

这是速记在那些情况下,你要么必须确保你分配一个实际的布尔有用(如类型的打字稿变量boolean ),或在做对了严格的比较,无论是truefalse (与=== )。

11.解构和传播运营商 (11. Destructuring and spread operators)

There is a lot to say about both topics, after all used correctly, they can produce very interesting results. But for this article, let me quickly show you how you can take advantage of both to simplify some tasks.

关于这两个主题,有很多要说的地方,只要正确使用它们,它们都可以产生非常有趣的结果。 但是对于本文,让我快速向您展示如何利用两者来简化某些任务。

将对象分解为多个变量 (Destructuring an object into multiple variables)

Have you ever had to assign a bunch of different object properties to individual variables? This is actually quite common for example if you need to deal with those values individually (by modifying them for example) without affecting the original object.

您是否曾经将一堆不同的对象属性分配给各个变量? 例如,如果您需要在不影响原始对象的情况下单独处理这些值(例如,通过修改它们),这实际上很常见。

Destructuring can help you do that in a single line of code:

解构可以帮助您在一行代码中做到这一点:

const myObj = {
  name: "Fernando",
  age: 37,
  country: "Spain"
}


//Old way of doing this:
const name = myObj.name;
const age = myObj.age;
const country = myObj.country;


//Using destructuring
const {name, age, country} = myObj;

This syntax can also be seen as part of import statements if you’ve used TypeScript before, because it allows you to individually import some of the methods libraries export without having to clug the namespace with a lot of unwanted functions.

如果您以前使用过TypeScript,那么此语法也可以视为import语句的一部分,因为它使您可以单独导入某些导出的方法库,而不必将名称空间与许多不需要的功能相提并论。

const { get } from 'lodash'

For example, that line above allows you to only add the get method from the lodash library to your namespace without adding the rest of the library, which has A LOT more methods inside.

例如,上面的那一行仅允许您将lodash库中的get方法添加到您的命名空间中,而无需添加该库的其余部分,该库中还有很多其他方法。

传播合并 (Spreading to merge)

Using the spread operator, you can simplify the task of merging both, arrays and objects into a single line of code, without having to call any extra methods:

使用spread运算符,您可以简化将数组和对象合并为一行代码的任务,而无需调用任何其他方法:

const arr1 = [1,2,3,4]
const arr2 = [5,6,7]


const finalArr = [...arr1, ...arr2] // [1,2,3,4,5,6,7]


const partialObj1 = {
  name: "fernando"
}
const partialObj2 = {
  age:37
}


const fullObj = { ...partialObj1, ...partialObj2 } // {name: "fernando", age: 37}

Notice that merging objects like this will cause properties to be overwritten if they share the same name. The same however won’t happen with arrays, repeated values will be added, you’ll have to resort to using a Set if you want to avoid that as well.

请注意,如果对象名称相同,则合并此类对象将导致属性被覆盖。 但是,数组不会发生相同的情况,将添加重复的值,如果您也想避免这种情况,则必须使用Set

两者结合 (Combining both)

You can even combine destructuring and the spread operator to achieve interesting results, such as removing the first element of an array and leaving the rest intact (i.e the common head and tail example with lists you can find in Python and other languages). Or even extract some properties from an object and leave the rest intact, like this:

您甚至可以结合使用解构和散布运算符来获得有趣的结果,例如删除数组的第一个元素,而其余元素保持不变(即常见的头尾示例以及可以在Python和其他语言中找到的列表)。 甚至从对象中提取一些属性,其余部分保持不变,如下所示:

const myList = [1,2,3,4,5,6,7]
const myObj = {
  name: "Fernando",
  age: 37,
  country: "Spain",
  gender: "M"
}


const [head, ...tail] = myList


const {name, age, ...others} = myObj


console.log(head) //1
console.log(tail) //[2,3,4,5,6,7]
console.log(name) //Fernando
console.log(age) //37
console.log(others) //{country: "Spain", gender: "M"}

Notice that the spread operator on the left side of the assignment has to be used as the last item. You can’t first use the spread and then add individual variables like this:

请注意,分配左侧的扩展运算符必须用作最后一项。 您不能先使用价差然后添加如下所示的单个变量:

const [...values, lastItem] = [1,2,3,4]

The above example will fail.

上面的示例将失败。

结论 (Conclusion)

There are a lot more shorthands around but remember that the more code you save, the less readable it becomes to others who’re not used to those shorthands. This is not about minifying your code, or implicitly assuming that the fewer lines of code will result in a more performant code. This is just about removing redundant or unnecessary constructs from your syntax in order to simplify the reading task.

速记有很多,但是请记住,保存的代码越多,对于不习惯这些速记的其他人来说,可读性就越差。 这并不是要压缩代码,也不是隐式地假设更少的代码行将导致性能更高的代码。 这只是为了从语法中删除多余或不必要的构造,以简化阅读任务。

So try to keep a healthy balance of shorthands and readable code in order to keep everyone happy (remember that you’re not the only one reading your code!).

因此,请尝试在速记和可读代码之间保持健康的平衡,以使每个人都满意(请记住,您不是唯一阅读代码的人!)。

Have I missed your favorite shorthand? Leave it down below and share it with the community!

我想念你最喜欢的速记吗? 将其保留在下方,并与社区共享!

学到更多 (Learn More)

翻译自: https://blog.bitsrc.io/11-javascript-and-typescript-shorthands-you-should-know-690a002674e0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值