質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

4回答

1896閲覧

ネストされた可変キーのオブジェクトからプロパティを掘り進む時にundefinedになる

huwatoro

総合スコア19

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

3クリップ

投稿2020/03/03 03:46

編集2020/03/04 03:20

###前提・実現したいこと
このようなオブジェクトがあります。

jquery

1var obj = { 2 parent:{ 3 apple:{ 4 jp:'りんご', 5 en:'apple', 6 zh:'苹果' 7 } 8 } 9};

そして次のようにitemlangが変数なのですが、itemがない時点でundefinedのエラーとなってしまいますよね。

jQeury

1const item = 'xxx'; 2const lang = 'ja'; 3const name = obj['parent'][item][lang];

これをitemがない時点で判定せず、この式全体で判定して(itemlangがいずれもない状態で初めて判定して)、notextを代入することはできませんでしょうか?
つまり次のようなことをしたいのです。次だと実際にはitemがないのでエラーとなりますが、式全体で判定してnotextを代入したいのです。

jQeury

1const item = 'xxx'; 2const lang = 'ja'; 3const name = obj['parent'][item][lang] || 'notext';

###該当のソースコード
実際には以下の流れです。
最初は問題ありませんが、2つ目をnotextとしたいのです。

jQuery

1var obj = { 2 parent:{ 3 apple:{ 4 jp:'りんご', 5 en:'apple', 6 zh:'苹果' 7 } 8 } 9}; 10 11fruits1('apple','jp'); // 問題なし 12fruits1('xxx','jp'); // 現状はエラーとなるが、これをnotextとしたい 13function fruits1(item,lang){ 14 const name = obj['parent'][item][lang] || 'notext'; 15 console.log('fruits1' + name); 16}

###試したこと
次のようにitemがない時点で三項演算子を使えばいいのですが、この処理が大変手間に感じるのです。

jQeury

1fruits2('apple','jp'); // 問題なし 2fruits2('xxx','jp'); // notextとなってOK 3function fruits2(item,lang){ 4 const name = obj['parent'][item] ? obj['parent'][item][lang] : 'notext'; 5 console.log('fruits2' + name); 6}

なぜ手間かというと実際のオブジェクトはもっと階層が深いので、上のような三項演算子では済ませることができず、条件分岐をたくさんかかないといけないためです。

その手間があるので、式全体で判定してnotextを代入したいというのが実現したいことなのですが、何か良い方法ございましたらお助けいただけませんでしょうか。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Lhankor_Mhy

2020/03/03 03:49

jQueryは関係ないと思いますので、タグの修正をお勧めします。
miyabi-sun

2020/03/03 06:20

タイトルと内容がちょっと違いますね。 「ネストされた可変キーのオブジェクトからプロパティを掘り進む時にundefinedになる」とかでしょうか?
huwatoro

2020/03/04 03:20

ありがとうございます。タグとタイトル変更致しました。
guest

回答4

0

ベストアンサー

これですかね。
Optional chaining - JavaScript | MDN

js

1fruits1('apple','jp'); // 問題なし 2fruits1('xxx','jp'); // 'notext' 3function fruits1(item,lang){ 4 const name = obj['parent']?.[item]?.[lang] || 'notext'; 5 console.log('fruits1' + name); 6}

ブラウザ対応状況
Can I use... Support tables for HTML5, CSS3, etc

別解

再帰とカリー化でユーティリティ関数を書いてみました。

js

1const opt = x => attr => attr == null ? x : opt( x == null ? undefined : x[attr] ); 2 3const item = 'xxx'; 4const lang = 'jp'; 5const name = opt(obj)('parent')(item)(lang)() || 'notext';

別解2

今度はジェネレータと早期リターンで書いてみました。イテレータの最後の要素にアクセスする上手い方法はないものか。

js

1const opt = (obj, attrs) => [...(function* (){ 2 for (attr of attrs){ 3 if ( obj == null ) return undefined; 4 yield obj = obj[attr]; 5 } 6})()].slice(-1)[0]; 7 8const item = 'apple'; 9const lang = 'jp'; 10const name = opt(obj, ['parent', item, lang]) || 'notext';

かっこかっこがなくなってウザさが減ったと思います。
あと、早期リターンをしているので、浅い階層でプロパティがなかった場合に省コスト、かも?

投稿2020/03/03 04:10

編集2020/03/03 10:31
Lhankor_Mhy

総合スコア36074

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

miyabi-sun

2020/03/03 05:47

おっ、ようやくStage4まで上がってきたんですね。 これがないのは正直バグじゃないかってレベルなので嬉しいですね。
Lhankor_Mhy

2020/03/03 05:54

ですね! Chromium Edge と Chrome が対応していて、Firefox が次期バージョンで対応するので、PC環境においては今年後半あたりに採用を検討していいレベルになるかと思います。あとは iOS Safari が対応すれば……
huwatoro

2020/03/04 03:24

JavaScript使いこなしてますね!どうもありがとうございます。様々な別解など大変勉強になりました。
guest

0

質問文の通りです。超不便です。
全くなんなんでしょうかね?このクソ言語

Lhankor_Mhyさんが「Optional chaining」を解説していますが、
これを軽く解説します。

既存のコードでどうすればよいかの案も下に貼り付けておきます。


ES2015以降の流れで、
急速にJavaScriptはモダンな構文が毎年追加される進化を遂げています。

プロポーザルという形で
JavaScriptの仕様に追加して欲しい機能をアピールする仕組みがあります。
これが精査されてStage0からスタートして、無事Stage4まで上がっていくと次のESに取り込まれるルールになっています。

「Optional chaining」は既にStage4まで登っている為、
対応ブラウザも非常に多く特に問題ないかもしれませんね。
ただし、非対応なブラウザだと問答無用にJSエラーで落ちると考えられるのでBabel等のツールを噛ませた方が良いでしょう。

まぁ、この提案がある時点でJSという言語自体での対応手段がない事への証明ですね。


毎回(((obj.parent || {}).apple || {}).jp || null)とか書くと読みづらくて仕方ないですね。

ES5でも何とか出来ます。
Ramda.jsのpathや、Lodashのgetといった解決策があります。

オブジェクトのキーは別にキー名の一部として.を所持することは禁止されていないはずですが、
JSでプロパティをチェーンする場合はA.B.Cと書きたいのでくっそ邪魔ですね。
なので文字列の.にしたり、配列を利用して再帰で取りに行く関数を実装すると良いでしょう。

コードにするとこんな感じ
ただまぁ、LodashやRamda.jsといったライブラリの方がきちんとテストされているので、
実際に導入するならライブラリを利用することをオススメします。

js

1var obj = { 2 parent:{ 3 apple:{ 4 jp:'りんご', 5 en:'apple', 6 zh:'苹果' 7 } 8 } 9}; 10 11const get = (obj, key) => { 12 if (key == '') return obj; // 正常終了 13 if (obj == null) return obj; // 存在しないキー 14 const keys = key.split('.'); 15 return get(obj[keys[0]], keys.slice(1).join('.')); 16} 17 18console.log(get(obj, 'parent.apple.jp')); // "りんご" 19console.log(get(obj, 'parent.banana.jp')); // undefined

投稿2020/03/03 06:05

編集2020/03/03 06:16
miyabi-sun

総合スコア21158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

huwatoro

2020/03/04 03:22

クソ言語wプロポーザル知りませんでした。その他様々な詳細なご解説ありがとうございます。Lodashでも近いことできましたか。調べてみます。
guest

0

こんな感じで

javascript

1name = ((obj['parent']||{})[item]||{})[lang]||"notext";

投稿2020/03/03 04:16

編集2020/03/03 04:29
yambejp

総合スコア114779

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

huwatoro

2020/03/04 03:22

ありがとうございます。一行でまとまっていいですね。
guest

0

ふつうにitemがundifinedではないことを確認するのはダメですか?
typeof item として型を文字列で評価し、undifinedではないことを確認できます。

投稿2020/03/03 03:52

sansansandodo

総合スコア248

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

huwatoro

2020/03/03 04:04

undifinedなのはitemという変数を指しているのではなくて、objからitemを探した結果を指しているのですが…
sansansandodo

2020/03/03 04:26

「そして次のようにitemとlangが変数なのですが、itemがない時点でundefinedのエラーとなってしまいますよね。これをitemがない時点で判定せず、この式全体で判定して(itemかlangがいずれもない状態で初めて判定して)、notextを代入することはできませんでしょうか?」 itemがないの意味が分からなくなってしまいましたが、itemが「parentに」ない場合の話をしていましたか?? であれば、原始的な実装としては、 prop in Obj //=> true or false で確認しておくといいかと思います。
huwatoro

2020/03/04 03:38

質問文が悪かったです。申し訳ございませんでした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問