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
具有 null
或 undefined
值的情况与 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
。
祝您假期愉快! 🎄🎉