V8的V8:JavaScript中的可选链和空值聚合

我认为谷歌的V8团队一直在等待这个时刻很长一段时间。V8引擎(https://andsky.com/tech/tutorials/js-v8-engine)(最受欢迎的JavaScript引擎)的第8版已经发布了!这个新版本带来了一些非常好的性能改进和两种新的JavaScript语言功能:可选链接和无连接。

选择链接

假设你正在与一个可怕的API提供商合作,让我们把这个API称为CrocosAPI。CrocosAPI提供了关于世界上所有的鳄鱼的信息(这是一个不稳定的API,每个人都知道捕食者比鳄鱼更出色

这就是我们获得鳄鱼的栖息地的功能(有些鳄鱼生活在淡水,淡水和/或盐水中)

 1const getWaterHabitat = async (crocName) => {
 2  // First we call our made up api
 3  const crocResponse = await fetch('http://api.crocosapi.io/croc/' + crocName);
 4  // We get the responses body
 5  const crocInfo = crocResponse.body;
 6  // We access the water property of the habitat property
 7  return crocInfo.habitat.water;
 8}
 9
10// Let's get the water habitat of a crocodile called Barry
11const barrysWaterHabitat = getWaterHabitat('Barry');
12// this returnsbarrysWaterHabitat == ['freshwater']

现在,假设CrocosAPI的开发者决定改变他们的响应的结构:

1{
2  "personalInfo" : {
3    "firstName" : "Barry"
4  },
5  "habitat": {
6    "water": ["freshwater"],
7  }
8  // ... skipping
9}

二:

 1{
 2  "personalInfo" : {
 3    "firstName" : "Barry"
 4    //  ...
 5  },
 6  // We changed 'habitat' to 'environment'
 7  "environment": {
 8    "water": ["freshwater"]
 9  }
10  //...
11}

现在,如果我们叫getWaterHabitat,我们将得到:

1TypeError: Cannot read property 'water' of undefined

这是因为crocInfo.habitat不再存在,现在要访问crocInfo,我们必须访问crocInfo.environment.water。这意味着我们的整个应用程序会崩溃,只是因为CrocosAPI的开发人员不知道版本。

 1const getWaterHabitat = async (crocName) => {
 2  const crocResponse = await fetch('http://api.crocosapi.io/croc/' + crocName)
 3  const crocInfo = crocResponse.body
 4  // We access the water key with optional chaining
 5  return crocInfo?.habitat?.water
 6}
 7
 8const myCrocsName = 'Barry'
 9const barrysWaterHabitat = getWaterHabitat('Barry')
10// barrysWaterHabitat == undefined

您还可以使用可选的数组索引:

1const crocAddress1City = crocInfo?.personalInfo?.addresses?.[0].city
2// if crocInfo.personalInfo.addresses = []
3// crocAddress1City === undefined

...和功能!

 1// It is hard to make a short example
 2const getSkinStyle = (option) => {
 3  const scales = {
 4    color: 'green',
 5    texture: 'shiny'
 6  }
 7  if (option == 'naked')
 8    return
 9  else 
10    return scales
11}
12
13const crocInfo = {
14  name: 'Barry', 
15  waterHabitat : 'Freshwaters',
16  getSkinStyle : getSkinStyle
17}
18
19const barrysSkinColor = crocInfo?.getSkinStyle?.('naked')?.color
20// barrysSkinColor === undefined
21const larrysSkinColor = crocInfo?.getSkinStyle?.('naked')?.color
22// larrysSkinColor === 'green'

...和动态的财产接入,哇,这是真正的假期 (在写作时)!

1// habitatType can be "water" or "land"
2const getHabitatProperty = (habitatType) => {
3  return crocInfo?.habitat?.[habitatType]
4}
5getHabitatType('water')
6// returns  ['freshwater']
7getHabitatType('land')
8// returns ['forest']

没有更多的输入错误,只是一个未定义的值!

作为一个快速的PSA,不要依靠可选的链作为一个借口来不做正确的错误处理.我们从访问未定义值的属性中获得的TypeError的好处是:

  • 更容易在我们的应用程序中注意到意想不到的行为
  • 它迫使我们写出更好的反馈机制

当我们试图访问未定义值的属性时,我们仍然应该有某种反弹或警告机制。

零组合

??... 不,我不困惑, ?? 是新的短路操作员,加入了 &&Átha Cliath 家族. 如果你写了一些 React、Vue 或 Angular,你可能已经写过或看到了类似的东西。

1const name = props.name || 'CrocName Error';
2const age = props.age || 'Invalid Age';
3const isFemale = props.isFemale || true;
4// pass name , age and isFemale to a view

此代码将分配存储在 props.name 中的值,如果值不是假的,则值 name 将等于 CrocName Error

但是,假设对于尚未命名的鳄鱼,API会返回一个空字符串,在JavaScript中,空字符串被认为是假的,所以这会发生:

 1// Let's say we have an anonymous new born boy crocodile
 2const props  = {
 3  name: '',
 4  age: 0,
 5  isFemale: false
 6}
 7
 8const name = props.name || 'CrocName Error';
 9// name === 'CrocName Error'
10
11const age = props.age || 'Invalid Age';
12// age === 'Invalid Age'
13
14const isFemale = props.isFemale || true;
15// isFemale === true

这些不是我们所期望的结果! 我们希望将props.name具有nullundefined值的场景分开到props.name是一个空串的情况下。

 1const name = '' ?? 'CrocName Error'
 2// name === '' 
 3
 4const age = 0 ?? 'Invalid Age';
 5// age === 0
 6
 7const isFemale = false ?? true;
 8// isFemale === false
 9
10// Yay it worked!

检查左侧操作员是否是假的。 只检查它是否是nullundefined

 1// +0, -0, NaN, false, empty strings, null and undefined are all falsy
 2false ?? true;   // equals false
 3false || true;   // equals true
 4
 50 ?? 1;          // equals 0
 60 || 1;          // equals 1
 7
 8'' ?? 'default'; // equals ''
 9'' || 'default'; // equals 'default'
10
11// null and undefined are falsy so in this case we get the same results
12null ?? [];      // equals []
13null || [];      // equals []
14
15undefined ?? []; // equals []
16undefined || []; // equals []

您也可以混合操作员! 只需记住使用笔记本。 试着想想这会做什么:

1const crocName = (props.name ?? 'CrocName Error') || 'Anonymous Croc';

让我们看看几个值的结果:

  • props.name === 'Barry': crocName === 'Barry'
  • props.name === '' : crocName ==== 'Anonymous Croc'
  • props.name === undefined : crocName ==== 'CrocName Error'

零合并和可选链一起工作

你可能已经考虑了使用这两种功能的酷方法!

 1const getCrocName = async (crocId) => {
 2  // We try to access our unstable API's data
 3  const crocResponse = await fetch('http://api.crocosapi.io/croc/' + crocId)
 4  // If croc response or body is undefined 
 5  const crocInfo = crocResponse?.body ?? 'Croc API did not return a valid response'
 6  // if crocResponse equals {} then crocInfo == 'Croc API did not return a valid response'
 7
 8  // checking if crocInfo, personal info or name is undefined/null or if name has a falsy value
 9  return (crocInfo?.personalInfo?.name ?? 'There was a problem loading the croc\'s name') || 'Anonymous Croc'
10  // if crocInfo?.personalInfo?.name === '' we return 'Anonymous Croc'
11  //  if crocInfo equals {} we return 'There was a problem loading the croc\'s name'
12}

V8 的性能

如今,我们对JavaScript的速度感到困惑,而且由于反复的性能更新而更加困扰。 再一次,V8的工程师改进了其引擎的性能和内存。 如果您对如何了解更多信息感兴趣,您可以查看他们的发布帖子(https://v8.dev/blog/v8-release-80)。

小奖金

要检查你是否可以在 Node.jd 中使用 V8 v8,你可以运行node -p process.versions.v8并查看版本是否已完成 8. 现在你应该在网络上使用像 core-js这样的多元化文件和/或传输器。 如果你正在使用 Babel, @babel/plugin-proposal-optional-chaining, @babel/plugin-proposal-nullish-coalescing-operator 可用。

快乐快乐的假期!

Published At
Categories with 技术
Tagged with
comments powered by Disqus