「译」更好的 JavaScript 条件式和匹配条件的提示与技巧

「译」更好的 JavaScript 条件式和匹配条件的提示与技巧

介绍

如果像我一样喜欢看干净的代码,则将尝试使用尽可能少的条件语句来编写代码。通常,面向对象的编程使我们能够避免条件,而将其替换为多态性和继承。我相信我们应该尽可能地遵循这些原则。

就像我在另一篇文章 JavaScript Clean Code Best Practices 中提到的那样,您并不仅仅是为机器编写代码,而是为“未来的自己”和“其他人”编写代码。

另一方面,由于各种原因,我们可能最终在代码中使用条件。也许我们的修复期限很紧,或者不使用条件语句将对我们的代码库造成太大的更改,等等。本文旨在帮助您解决这些情况并帮助您组织条件语句。

技巧

以下是有关如何构造if...else语句以及如何减少编写以实现更多目标的技巧。享受吧!

1. 重要的事情先做,琐碎的但很重要

不要使用否定条件(它们可能会造成困惑),而请使用条件简写来表示 boolean 变量。我不能特别强调这一点,尤其是关于否定条件的部分。这是一种不自然的做事方式。

Bad

const isEmailNotVerified = (email) => {
  // implementation
}

if (!isEmailNotVerified(email)) {
  // do something...
}

if (isVerified === true) {
  // do something...
}

Good

const isEmailVerified = (email) => {
  // implementation
}

if (isEmailVerified(email)) {
  // do something...
}

if (isVerified) {
  // do something...
}

现在,当我们清楚以上几点之后,就可以开始了。

2.对于多个条件,请使用 Array.includes

假设我们要检查汽车模型是 renault 还是 peugeot 在我们的功能中。该代码可能看起来像这样:

const checkCarModel = (model) => {
  if(model === 'renault' || model === 'peugeot') { 
    console.log('model valid');
  }
}

checkCarModel('renault'); // outputs 'model valid'

考虑到我们只有两个模型,这样做看起来是可以接受的,但是如果我们要检查另一个模型怎么办?还是其中几个?如果我们添加更多的 or 语句,则代码将更难维护,而不是那么干净。为了使它更整洁,我们可以将函数重写为如下形式:

const checkCarModel = (model) => {
  if(['peugeot', 'renault'].includes(model)) { 
    console.log('model valid');
  }
}

checkCarModel('renault'); // outputs 'model valid'

上面的代码看起来已经更好了。为了使它更好,我们可以创建一个变量来保存汽车模型:

const checkCarModel = (model) => {
  const models = ['peugeot', 'renault'];

  if(models.includes(model)) { 
    console.log('model valid');
  }
}

checkCarModel('renault'); // outputs 'model valid'

现在,如果我们要检查更多模型,我们要做的就是添加一个新的数组项。同样,如果它很重要,我们可以 models 在函数范围之外的某个地方声明变量,并在需要的地方重复使用它。这样,考虑到我们只需要在代码中更改一个位置,就可以集中它并使维护变得轻而易举。

3.使用数组匹配所有条件。Array.everyArray.find

在本例中,我们要检查是否每个汽车模型都是传递给函数的模型。为更命令式的方式实现这一目标,我们会这样做:

const cars = [
  { model: 'renault', year: 1956 },
  { model: 'peugeot', year: 1968 },
  { model: 'ford', year: 1977 }
];

const checkEveryModel = (model) => {
  let isValid = true;

  for (let car of cars) {
    if (!isValid) {
      break;
    }
    isValid = car.model === model;
  }

  return isValid;
}

console.log(checkEveryModel('renault')); // outputs false

如果您喜欢命令式的处理方式,则上面的代码可能会很好。另一方面,如果您不在乎背后发生了什么,则可以重写上面的函数并使用 Array.everyArray.find 获得相同的结果。

const checkEveryModel = (model) => {
  return cars.every(car => car.model === model);
}

console.log(checkEveryModel('renault')); // outputs false

通过使用 Array.find,稍作调整就可以达到相同的结果,并且性能应该是相同的,因为两个函数都对数组中的每个元素执行回调,并且如果发现 falsy,则立即返回 false。

const checkEveryModel = (model) => {
  return cars.find(car => car.model !== model) === undefined;
}

console.log(checkEveryModel('renault')); // outputs false

4.用于匹配部分条件 Array.some

Array.every 所有条件一样,此方法使检查数组是否包含一个或多个项目变得非常容易。为此,我们需要提供一个回调并根据条件返回一个布尔值。

我们可以通过编写类似上面的 for...loop 语句的类似语句来达到相同的结果,但是幸运的是,我们有不错的 JavaScript 函数为我们做事。

const cars = [
  { model: 'renault', year: 1956 },
  { model: 'peugeot', year: 1968 },
  { model: 'ford', year: 1977 }
];

const checkForAnyModel = (model) => {
  return cars.some(car => car.model === model);
}

console.log(checkForAnyModel('renault')); // outputs true

5.尽早返回而不是if...else分支

当我还是一个学生的时候,我被教导说一个函数应该只有一个 return 语句,并且只能从一个位置返回。如果谨慎处理,这不是一个坏方法,这意味着我们应该认识到会导致条件嵌套地狱的情况。if...else 如果失去控制,多个分支和嵌套可能会很痛苦。

另一方面,如果代码库很大,并且包含很多行,那么在深处某处的 return 语句将是一个问题。如今,我们将关注点与 SOLID 原则分离开来,因此,大量的代码行应该很少见。

让我们创建一个示例来说明这一点,并说我们要显示给定汽车的型号和制造年份。

const checkModel = (car) => {
  let result; // first, we need to define a result value
  
  // check if car exists
  if(car) {

    // check if car model exists
    if (car.model) {

      // check if car year exists
      if(car.year) {
        result = `Car model: ${car.model}; Manufacturing year: ${car.year};`;
      } else {
        result = 'No car year';
      }
	  
    } else {
      result = 'No car model'
    }   

  } else {
    result = 'No car';
  }

  return result; // our single return statement
}

console.log(checkModel()); // outputs 'No car'
console.log(checkModel({ year: 1988 })); // outputs 'No car model'
console.log(checkModel({ model: 'ford' })); // outputs 'No car year'
console.log(checkModel({ model: 'ford', year: 1988 })); // outputs 'Car model: ford; Manufacturing year: 1988;'

如您所见,即使对于我们这个简单的问题,上面的代码也相当长。想象一下,如果我们拥有更复杂的逻辑,将会发生什么。很多 if...else 陈述。

我们可以通过更多步骤来重构上面的功能,从而使每个功能都更好。例如,使用三元运算符,包含&&条件等,但是我将跳到最后,向您展示如何使用现代 JavaScript 功能和多个 return 语句将其简化。

const checkModel = ({model, year} = {}) => {
  if(!model && !year) return 'No car';
  if(!model) return 'No car model';
  if(!year) return 'No car year';

  // here we are free to do whatever we want with the model or year
  // we made sure that they exist
  // no more checks required

  // doSomething(model);
  // doSomethingElse(year);
  
  return `Car model: ${model}; Manufacturing year: ${year};`;
}

console.log(checkModel()); // outputs 'No car'
console.log(checkModel({ year: 1988 })); // outputs 'No car model'
console.log(checkModel({ model: 'ford' })); // outputs 'No car year'
console.log(checkModel({ model: 'ford', year: 1988 })); // outputs 'Car model: ford; Manufacturing year: 1988;'

在重构版本中,我们包括了解构和默认参数。默认参数将确保我们通过时具有要破坏的值undefined。请注意,如果我们传递一个null值,该函数将抛出错误,这是前一种方法的优势,因为在这种情况下,null传递时的输出将为'No car'。

对象分解将确保该功能仅获得所需的功能。例如,如果我们在给定的汽车对象中包含其他属性,则该属性在我们的函数中将不可用。

根据喜好,开发人员将遵循这些路径之一。实践表明,通常,代码是在这两种方法之间的某个位置编写的。许多人认为if...else语句更容易理解,这有助于他们轻松地遵循程序流程。

6.使用索引或映射代替 switch 语句

假设我们要根据给定状态获取汽车模型。

const getCarsByState = (state) => {
  switch (state) {
    case 'usa':
      return ['Ford', 'Dodge'];
    case 'france':
      return ['Renault', 'Peugeot'];
    case 'italy':
      return ['Fiat'];
    default:
      return [];
  }
}

console.log(getCarsByState()); // outputs []
console.log(getCarsByState('usa')); // outputs ['Ford', 'Dodge']
console.log(getCarsByState('italy')); // outputs ['Fiat']

上面的代码可以重构为 switch 完全排除该语句。

const cars = new Map()
  .set('usa', ['Ford', 'Dodge'])
  .set('france', ['Renault', 'Peugeot'])
  .set('italy', ['Fiat']);

const getCarsByState = (state) => {
  return cars.get(state) || [];
}

console.log(getCarsByState()); // outputs []
console.log(getCarsByState('usa')); //outputs ['Ford', 'Dodge']
console.log(getCarsByState('italy')); // outputs ['Fiat']

或者,我们可以为每个州创建一个带有可用汽车列表的类,并在需要时使用它,但这是另一篇文章的主题。这篇文章是关于条件的。更合适的更改是使用对象文字。

const carState = {
  usa: ['Ford', 'Dodge'],
  france: ['Renault', 'Peugeot'],
  italy: ['Fiat']
};

const getCarsByState = (state) => {
  return carState[state] || [];
}

console.log(getCarsByState()); // outputs []
console.log(getCarsByState('usa')); // outputs ['Ford', 'Dodge']
console.log(getCarsByState('france')); // outputs ['Renault', 'Peugeot']

7.使用可选链和无效合并

我可以从说“最后”开始。我认为,这两个功能是对 JavaScript 语言的非常有用的补充。作为一个来自 C# 世界的人,我可以说我经常使用它们。

在撰写本文时,还没有完全支持这些选项,因此您需要使用Babel编译以这种方式编写的代码。您可以在此处检查可选链和在此处进行无效合并。

可选链接使我们能够处理树状结构,而无需显式检查中间节点是否存在,并且空值合并与可选链接结合使用非常有效,它可用于确保不存在的默认值。

让我们用一些示例来验证上面的语句,然后从老的处理方式开始。

const car = {
  model: 'Fiesta',
  manufacturer: {
    name: 'Ford',
    address: {
      street: 'Some Street Name',
      number: '5555',
      state: 'USA'
    }
  }
}

// to get the car model
const model = car && car.model || 'default model';
// to get the manufacturer street
const street = car && car.manufacturer && car.manufacturer.address && car.manufacturer.address.street || 'default street';
// request an un-existing property
const phoneNumber = car && car.manufacturer && car.manufacturer.address && car.manufacturer.phoneNumber;

console.log(model) // outputs 'Fiesta'
console.log(street) // outputs 'Some Street Name'
console.log(phoneNumber) // outputs undefined

因此,如果我们想打印出这家汽车制造商来自美国,那么代码将如下所示:

const checkCarManufacturerState = () => {
  if(car && car.manufacturer && car.manufacturer.address && car.manufacturer.address.state === 'USA') {
    console.log('Is from USA');
  }
}

checkCarManufacturerState() // outputs 'Is from USA'

我不需要告诉您在对象结构更复杂的情况下这会变得多么混乱。例如,诸如 lodash 的许多库都有其自己的变通办法,但我们不希望那样,我们希望能够在原生 js中实现。让我们看看一种新的做事方式。

// to get the car model
const model = car?.model ?? 'default model';
// to get the manufacturer street
const street = car?.manufacturer?.address?.street ?? 'default street';

// to check if the car manufacturer is from the USA
const checkCarManufacturerState = () => {
  if(car?.manufacturer?.address?.state === 'USA') {
    console.log('Is from USA');
  }
}

这看起来更漂亮,更短,对我来说,非常合乎逻辑。如果您想知道为什么要使用??而不是||,请考虑可以将哪些值评估为 truefalse,并且可能会有意外的输出。

还有一件事情是非常整洁的。可选链接还支持 DOM API,这非常酷,这意味着您可以执行以下操作:

const value = document.querySelector('input#user-name')?.value;

原文地址

https://devinduct.com/blogpost/35/tips-and-tricks-for-better-javascript-conditionals-and-match-criteria

Read more

Flutter入门指南

Flutter入门指南

Flutter 是一个由 Google 开发的开源移动应用开发框架。它允许开发者使用一套代码同时构建 iOS 和 Android 应用,并且提供了丰富的 UI 组件和高效的开发工具,使得开发者能够快速构建出高性能的跨平台应用。 一、Flutter 的实现原理 Flutter 的核心在于其自带的高性能渲染引擎 Skia。不同于其他框架依赖于原生的 UI 组件,Flutter 直接通过 Skia 渲染引擎将所有组件绘制到屏幕上。这种方式保证了跨平台应用在 iOS 和 Android 上的表现完全一致。 1.1 结构概览 Flutter 的架构分为三层: 1. Framework(框架层): 这部分主要由 Dart 编写,提供了 Flutter 的各种 UI 组件(Widget)、手势检测、渲染层以及动画等。

By Lewis
Certbot Let's Encrypt 证书自动续期

Certbot Let's Encrypt 证书自动续期

安装 Certbot yum install epel-release -y yum install certbot -y certbot certonly //生成证书 certbot renew //续期 certbot certificates //查看证书 域名验证插件 https://github.com/ywdblog/certbot-letencrypt-wildcardcertificates-alydns-au 下载 $ git clone https://github.com/ywdblog/certbot-letencrypt-wildcardcertificates-alydns-au $ cd certbot-letencrypt-wildcardcertificates-alydns-au $ chmod 0777 au.sh 配置 DNS API 密钥: 这个 API 密钥什么意思呢?由于需要通过 API 操作阿里云 DNS,

By Lewis