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

来自菜鸟教程
跳转至:导航、​搜索

我认为谷歌的 V8 团队已经等待这一刻很久了。 V8引擎(最流行的JavaScript引擎)第8版出! 这个新版本带来了一些非常好的性能改进和两个新的很酷的 JavaScript 语言特性:可选链接和无效合并。

可选链

这是一个期待已久的功能。 假设您正在与一个糟糕的 API 提供商合作。 我们将此 API 称为 CrocosAPI。 CrocosAPI 提供有关世界上所有鳄鱼的信息(这是一个不稳定的 API,每个人都知道“鳄鱼优于鳄鱼”)。

这就是我们获得鳄鱼栖息地的功能(一些鳄鱼生活在淡水、微咸水和/或咸水中)

const getWaterHabitat = async (crocName) => {
  // First we call our made up api
  const crocResponse = await fetch('http://api.crocosapi.io/croc/' + crocName);
  // We get the responses body
  const crocInfo = crocResponse.body;
  // We access the water property of the habitat property
  return crocInfo.habitat.water;
}

// Let's get the water habitat of a crocodile called Barry
const barrysWaterHabitat = getWaterHabitat('Barry');
// this returnsbarrysWaterHabitat == ['freshwater']

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

{
  "personalInfo" : {
    "firstName" : "Barry"
  },
  "habitat": {
    "water": ["freshwater"],
  }
  // ... skipping
}

到:

{
  "personalInfo" : {
    "firstName" : "Barry"
    //  ...
  },
  // We changed 'habitat' to 'environment'
  "environment": {
    "water": ["freshwater"]
  }
  //...
}

现在如果我们调用 getWaterHabitat 我们将得到:

TypeError: Cannot read property 'water' of undefined

那是因为 crocInfo.habitat 不再存在。 现在要访问 crocInfo,我们必须访问 crocInfo.environment.water。 这意味着我们的整个应用程序将因为 CrocosAPI 的开发人员不了解版本控制而崩溃。 那么如何避免这个错误呢? 当然是可选的链接!

const getWaterHabitat = async (crocName) => {
  const crocResponse = await fetch('http://api.crocosapi.io/croc/' + crocName)
  const crocInfo = crocResponse.body
  // We access the water key with optional chaining
  return crocInfo?.habitat?.water
}

const myCrocsName = 'Barry'
const barrysWaterHabitat = getWaterHabitat('Barry')
// barrysWaterHabitat == undefined

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

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

……还有功能!

// It is hard to make a short example
const getSkinStyle = (option) => {
  const scales = {
    color: 'green',
    texture: 'shiny'
  }
  if (option == 'naked')
    return
  else 
    return scales
}

const crocInfo = {
  name: 'Barry', 
  waterHabitat : 'Freshwaters',
  getSkinStyle : getSkinStyle
}

const barrysSkinColor = crocInfo?.getSkinStyle?.('naked')?.color
// barrysSkinColor === undefined
const larrysSkinColor = crocInfo?.getSkinStyle?.('naked')?.color
// larrysSkinColor === 'green'

…并具有动态属性访问权限。 哇,真的是假期⛄🎄🎁(在撰写本文时)!

// habitatType can be "water" or "land"
const getHabitatProperty = (habitatType) => {
  return crocInfo?.habitat?.[habitatType]
}
getHabitatType('water')
// returns  ['freshwater']
getHabitatType('land')
// returns ['forest']

不再有类型错误,只有 undefined 值!

作为一个快速的 PSA,不要依赖可选链接作为不进行正确错误处理的借口。 我们从访问未定义值的属性中得到的 TypeError 的好处是:

  • 在我们的应用程序中更容易注意到意外行为
  • 它迫使我们编写更好的回退机制

在尝试访问未定义值的属性时,我们仍然应该有某种回退或警告机制。

无效合并

??... 不,我并不感到困惑,?? 是加入 &&|| 系列的新短路运算符。 如果你写过一些 React、Vue 或 Angular,你可能已经写过或看过类似的东西。

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

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

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

// Let's say we have an anonymous new born boy crocodile
const props  = {
  name: '',
  age: 0,
  isFemale: false
}

const name = props.name || 'CrocName Error';
// name === 'CrocName Error'

const age = props.age || 'Invalid Age';
// age === 'Invalid Age'

const isFemale = props.isFemale || true;
// isFemale === true

这些不是我们期望的结果! 我们想将 props.name 具有 nullundefined 值的情况与 props.name 为空字符串的情况分开。 我们希望 age 等于 0 并且 isFemale 等于 false。 这就是 ?? 来救援的地方。

const name = '' ?? 'CrocName Error'
// name === '' 

const age = 0 ?? 'Invalid Age';
// age === 0

const isFemale = false ?? true;
// isFemale === false

// Yay it worked!

|| 检查左侧运算符是否为假。 ?? 仅检查它是 null 还是 undefined。 这是给你的一个小备忘单:

// +0, -0, NaN, false, empty strings, null and undefined are all falsy
false ?? true;   // equals false
false || true;   // equals true

0 ?? 1;          // equals 0
0 || 1;          // equals 1

'' ?? 'default'; // equals ''
'' || 'default'; // equals 'default'

// null and undefined are falsy so in this case we  get the same results
null ?? [];      // equals []
null || [];      // equals []

undefined ?? []; // equals []
undefined || []; // equals []

您还可以混合运算符! 请记住使用括号。 试着想想这会做什么:

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

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

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

空值合并和可选链接一起工作

您可能已经想到了将这两个功能一起使用的很酷的方法!

const getCrocName = async (crocId) => {
  // We try to access our unstable API's data
  const crocResponse = await fetch('http://api.crocosapi.io/croc/' + crocId)
  // If croc response or body is undefined 
  const crocInfo = crocResponse?.body ?? 'Croc API did not return a valid response'
  // if crocResponse equals {} then crocInfo == 'Croc API did not return a valid response'

  // checking if crocInfo, personal info or name is undefined/null or if name has a falsy value
  return (crocInfo?.personalInfo?.name ?? 'There was a problem loading the croc\'s name') || 'Anonymous Croc'
  // if crocInfo?.personalInfo?.name === '' we return 'Anonymous Croc'
  //  if crocInfo equals {} we return 'There was a problem loading the croc\'s name'
}

V8 V8 的性能

如今,我们被 JavaScript 的速度所宠坏,更被周期性的性能更新所宠坏。 V8 的工程师再次改进了引擎的性能和内存。 如果您有兴趣了解更多信息,可以查看 他们的发布帖子 。 我喜欢这些更新的一点是它提高了我们的代码性能,但我们不必编写任何新内容!

小红利

要检查是否可以在 Node.jd 中使用 V8 v8,您可以运行 node -p process.versions.v8 并查看版本是否超过 8。 现在你应该在 web 上使用像 core-js 这样的 polyfill 和/或转译器。 如果你使用 Babel,可以使用 @babel/plugin-proposal-optional-chaining@babel/plugin-proposal-nullish-coalescing-operator

祝您假期愉快! 🎄🎉