资讯专栏INFORMATION COLUMN

【译】教你如何避开「Cannot read property of undefined」

xiaoqibTn / 1353人阅读

摘要:比如的,的提供访问安全对象的支持。在使用的情况下,这意味着表达式在达到其第一个假值后将停止向后执行。这便可用于安全地访问嵌套属性。与上述短路示例类似,此方法通过检查值是否为假来进行操作。该方法优于该方法的地方是避免属性名称的重复。

Uncaught TypeError: Cannot read property "foo" of undefined.这种错误想必在我们日常开发中都到过,这有可能是我们的api返回了一个空的状态而我们没有预料到,也可能是其他,我们无从得知,因为这种问题十分的常见且涉及的因素相当多。

我最近遇到了一个问题,某些环境变量由于某种原因没有被引入,导致各种各样的问题,一堆错误出现在我的眼前。无论原因是什么,它可能是一个灾难性的错误,那么我们如何才能首先防止它呢?

让我们来看看解决办法。

工具库

如果你已经使用了某种工具库,很可能内部就包含了相关的错误处理函数。比如lodash_.getRamdaR.path提供访问安全对象的支持。

如果没有使用呢?那就看看下面的解决办法。

使用&&实现「短路与」

Javascript中一个有趣的事情是,逻辑运算操作不一定返回boolean值。根据规范,&&||运算符返回的值不一定需要为boolean类型,它的返回值为该运算符左右两边表达式的其中一个。

&&中,如果第一个表达式为false则直接返回,否则就用第二个。举个例子:0&&1 -> 02&&3 -> 3。如果是链式使用&&的话,将会判断第一个假值或者最后一个真值。比如:1 && 2 && 3 && null && 4​ -> null1 && 2 && 3 -> 3

这对安全地访问嵌套对象属性有什么作用呢?JavaScript中的逻辑运算符将「短路」。在使用&&的情况下,这意味着表达式在达到其第一个假值后将停止向后执行。

​​const foo = false && destroyAllHumans();
​​console.log(foo); // false, and humanity is safe

在上面代码中,因为&&遇到了false值,destroyAllHumans将永远不会被执行。

这便可用于安全地访问嵌套属性。

const meals = {
​​  breakfast: null, // I skipped the most important meal of the day! :(
​​  lunch: {
​​    protein: "Chicken",
​​    greens: "Spinach",
​​  },
​​  dinner: {
​​    protein: "Soy",
​​    greens: "Kale",
​​  },
​​};
​​
​​const breakfastProtein = meals.breakfast && meals.breakfast.protein; // null
​​const lunchProtein = meals.lunch && meals.lunch.protein; // "Chicken

这种办法不仅简单,而且在处理短链时也非常的简洁。但是当访问更深层的对象时,这可能就会变得非常冗长。

const favorites = {
​​  video: {
​​    movies: ["Casablanca", "Citizen Kane", "Gone With The Wind"],
​​    shows: ["The Simpsons", "Arrested Development"],
​​    vlogs: null,
​​  },
​​  audio: {
​​    podcasts: ["Shop Talk Show", "CodePen Radio"],
​​    audiobooks: null,
​​  },
​​  reading: null, // Just kidding -- I love to read
​​};
​​
​​const favoriteMovie = favorites.video && favorites.video.movies && favorites.video.movies[0];
​​// Casablanca
​​const favoriteVlog = favorites.video && favorites.video.vlogs && favorites.video.vlogs[0];
​​// null

嵌套的对象越深,它就越难以描述。

Maybe Monad

Oliver Steele提出了这种方法,并在他的博客文章Monads on the Cheap I:The Maybe Monad中进行更详细地介绍。我将在这里作一个简单的解释。

const favoriteBook = ((favorites.reading||{}).books||[])[0]; // undefined
​​const favoriteAudiobook = ((favorites.audio||{}).audiobooks||[])[0]; // undefined
​​const favoritePodcast = ((favorites.audio||{}).podcasts||[])[0]; // "Shop Talk Show"

与上述短路示例类似,此方法通过检查值是否为假来进行操作。如果是,它将尝试访问空对象上的下一个属性。在上面的例子中,favorites.readingnull,所以books从一个空对象进行访问。而此时的返回值也将是undefined,于是[0]将从一个空数组中获取。

该方法优于该&&方法的地方是避免属性名称的重复。在更深层的对象上,这可能是一个非常重要的优势。主要的缺点是可读性较差。它不是一种常见的模式,可能需要读者花一点时间来解析它是如何工作的。

try/catch

JavaScript中​​try...catch语句允许某函数安全地访问属性。

try {
​​  console.log(favorites.reading.magazines[0]);
​​} catch (error) {
​​  console.log("No magazines have been favorited.");
​​}

但问题在于,​​try...catch不是一个表达式,在某些语言中它不具备直接返回值的能力,一种可行的方法是直接在try...catch定义变量。

let favoriteMagazine;
​​try { 
​​  favoriteMagazine = favorites.reading.magazines[0]; 
​​} catch (error) { 
​​  favoriteMagazine = null; /* any default can be used */
​​};

即使要写不少的代码,但其实你也只能定义一个变量,但如果同时定义多个话,就会有问题。

let favoriteMagazine, favoriteMovie, favoriteShow;
​​try {
​​  favoriteMovie = favorites.video.movies[0];
​​  favoriteShow = favorites.video.shows[0];
​​  favoriteMagazine = favorites.reading.magazines[0];
​​} catch (error) {
​​  favoriteMagazine = null;
​​  favoriteMovie = null;
​​  favoriteShow = null;
​​};
​​
​​console.log(favoriteMovie); // null
​​console.log(favoriteShow); // null
​​console.log(favoriteMagazine); // null

如果访问该属性的任何尝试失败,则会导致所有这些尝试都回退到其默认值。

另一种方法是将try...catch可重用的实用程序函数包装起来。

const tryFn = (fn, fallback = null) => {
​​  try {
​​    return fn();
​​  } catch (error) {
​​    return fallback;
​​  }
​​} 
​​
​​const favoriteBook = tryFn(() => favorites.reading.book[0]); // null
​​const favoriteMovie = tryFn(() => favorites.video.movies[0]); // "Casablanca"
未完待续...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106244.html

相关文章

  • 详解1000+项目数据分析出来的10大JavaScript错误

    摘要:当未捕获的错误通过处理程序引发的错误,而不是捕获在中被浏览器的跨域策略限制时,会产生这类的脚本错误。例如,如果您将您的代码托管在上,则任何未被捕获的错误将被报告为脚本错误而不是包含有用的堆栈信息。 译者按: null/undefined引发的错误在10大错误中比例很高。而它们很可能导致严重问题,所以要重视起来。 原文: Top 10 JavaScript errors from 10...

    jubincn 评论0 收藏0
  • 避免取值时出现Cannot read property 'xx' of unde

    摘要:由于是以空函数为代理对象,我们可以将执行它,触发。中会遍历数组依次取值,如果发现无法继续取值则,跳出循环。 本文来自我的博客,欢迎大家去GitHub上star我的博客 我们在取值特别是链式取值的时候,常常会遇到Cannot read property xx of undefined的错误,如何避免这种情况的发生呢?这里有几种方法以供参考 使用成熟的库方法 这是最简单的一种手段:只用引入...

    fantix 评论0 收藏0
  • JavaScript 调试常见报错以及修复方法

    摘要:表示错误没有被语句捕获,是错误的名字。如何修复错误确保方法名正确。这个错误的行号将指出正确的位置。相关错误代码调用的方法在当前状态无法调用。通常由引起,在方法准备完毕之前调用它会引起错误。原文翻译出处涂鸦码农错误以及如何修复 (看到一篇调试JS很有用的文章,收藏一下) JavaScript 调试是一场噩梦:首先给出的错误非常难以理解,其次给出的行号不总有帮助。有个查找错误含义,及修复...

    zhongmeizhi 评论0 收藏0
  • 猫头鹰的深夜翻:从1000+JS项目中汇总的10个最容易出现的错误(以及如何解决)

    摘要:常出现的错误前十位为了可读性,错误名称进行了一定的简写。让我们深入了解每个错误发生的原因以及解决方法。这个问题很容易解决。当未捕获的错误跨越违法跨域策略的域边界时,会发生脚本错误。这是当你在中试图调用的方法时出现的错误。 JavaScript常出现的错误前十位 showImg(https://segmentfault.com/img/bV3Z1z?w=1116&h=691); 为了可读...

    eccozhou 评论0 收藏0
  • 如何在JavaScript中访问暂未存在的嵌套对象

    摘要:做法是检查用户是否存在,如果不存在,就创建一个空对象,这样,下一个级别的键将始终从存在的对象访问。使用数组访问嵌套对象方法非常强大,可用于安全地访问嵌套对象。除了安全访问嵌套对象之外,它还可以做很多很棒的事情。 想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你! JavaScript 是个很神奇的东西。但是 JavaScript中的一些东西确实很奇怪,让人摸不着头脑。...

    malakashi 评论0 收藏0

发表评论

0条评论

xiaoqibTn

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<