【訳】「Canot read property of undefined」を避ける方法を教えます.
5027 ワード
Uncaught TypeError: Cannot read property 'foo' of undefined.
このようなエラーは私達の日常開発において全部来たことがあると思います.これは私達のapi
が空いた状態に戻ったのかもしれません.私達は予想していません.他のものかもしれません.このような問題が非常によくあり、関連する要素がかなり多いからです.最近、ある環境変数が何らかの理由で導入されていないため、様々な問題を引き起こし、間違いだらけになってしまいました.何が原因であれ、それは災難的なミスかもしれません.じゃ、私達はどうやってまずそれを防ぐことができますか?
解決策を見てみましょう.
ツールバー
既に何らかのツールライブラリを使っていると、エラー処理関数が内部に含まれている可能性があります.
lodash
の_.get
のように、Ramda
のR.path
は、セキュリティオブジェクトにアクセスするサポートを提供する.もし使わなかったら?次の解決策を見てみます.
&&
を使って「短絡と」を実現しました.Javascript
において興味深いことは、論理演算動作が必ずしもboolean
値に戻るとは限らないことである.仕様によれば、&&
および||
演算子の戻り値は必ずしもboolean
タイプである必要はなく、演算子の左右の式のいずれかである.&&
では、第一の表現がfalse
であれば、直接に返します.そうでなければ、第二の表現を使います.例を挙げると、0&&1 -> 0
、2&&3 -> 3
.チェーン式&&
を使用すると、最初の偽値または最後の真値が判断される.1 && 2 && 3 && null && 4 -> null
、1 && 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.reading
はnull
であるので、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"
未完…