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

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

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

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

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

5回答

4636閲覧

Javascriptで連想配列のkeyをどのように誤字脱字がないよう管理していますか

rontec

総合スコア169

JavaScript

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

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

2グッド

1クリップ

投稿2016/03/08 13:02

よくある失敗なのですが、Javascriptの変数の使い勝手が自由すぎるため、連想配列のkey名を間違えて配置し、想定通り値がとれないということがあります。
今までフロントでそこまで大規模なものを作らなかったので、挙動がおかしかった時はなんとなく失敗ポイントが連想しやすかったのですが、規模が大きくなるとそうもいかないと思います。

解決策として一つは以下のような方法を想定しています。

js

1var obj = {}; 2obj.hoge = 'test1'; 3console.log(obj.hoge);

という書き方をやめ、

js

1var HOGE = 'hoge'; 2 3var obj = {}; 4obj[HOGE] = 'test2'; 5console.log(obj[HOGE]);

とすることで、keyで定数的な変数を指定することで、打ち間違えなどにより誤った定数を指定するとstrictモードでエラーにする方法です。
ただkey名をすべて定数として一度指定することが非常に面倒でもあります。

皆様は普段どのようにJSの連想配列のkeyを管理されているのでしょうか。
今回webストレージで少し規模の大きなjsonを扱うことになり、かなり上記のようなことに神経質になっています。

Javaならclassでフィールド名を指定しているので、打ち間違えた時点でeclipse先生が教えてくれるのですが。。

notable, ikuwow👍を押しています

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

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

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

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

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

guest

回答5

0

自分もたまにそのミスをします!
JetBrainのWeb StormというIDEを使っているのですが、
オブジェクトのキーのタイプミスは指摘してくれないので、
ちょっと悩ましく感じているところです。

自分は最近、TypeScriptというjavascriptの代替言語を使い始めたのですが、
TypeScriptであれば存在しないキーに値を代入しようとするとエラーを出してくれるので助かります。

TypeScriptを使わない解決策としては、javascriptのsetterメソッドを使って、
キーに値が代入される時にチェックするように実装することですかね。
ただ、setterメソッドはサポートされていないブラウザーのバージョンもあるので、
その点は注意が必要ですね。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set

投稿2016/03/08 13:10

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

rontec

2016/03/08 13:32

アドバイスありがとうございます。 TypeScript手を出したことないのですが、キーチェックしてくれるのですね。 setter、getterも一つの手ですね…ただコード量膨らんじゃうのが悩みどころですね。
rontec

2016/04/02 03:40

これすごく便利な気がします! 実際Javaのclassでフィールド定義したものをjsに渡し、特定項目を埋めてJavaにPOSTするという使い方をしているので、JS側でkeyの拡張してないので、さっそく利用を検討させて頂きます!
guest

0

ベストアンサー

起こりうる想定状況

誤字による不正なプロパティ参照であれば、期待しない値が返ってくるので検証中に発覚すると思われます。
それでも発覚しないとしたら「不正な値が返ってくるが、期待する値と似通った値が返ってくる場合」でしょうか。
実際のところ、その辺りの状況を限定してもらわないと回答しづらいと思います。
rontec さんが想定する誤字による失敗例とはどのような状況でしょうか?

テキストエディタの補完機能を使う

私は Sublime Text 3 を使用していますが、一度使用した変数は補完機能の対象となるので、途中まで入力すれば既存候補から選択するだけで入力できます。
この機能は Atom TextEditor にもあったと思うのでいろいろとテキストエディタを試してみるといいかもしれません。

存在しないプロパティを参照してしまう場合

存在しないプロパティを参照すれば undefined が返る仕様です。その為、書き方によっては TypeError になります。

JavaScript

1var obj = {hoge: 'test1'}; 2 3if (obj.hogo.indexOf('test') !== -1) { // TypeError: Cannot read property 'indexOf' of undefined 4 console.log('hit!'); 5}

しかし、エラーにならないパターンも当然あるわけです。

JavaScript

1var obj = {hoge: 'test1'}; 2 3document.getElementById('sample').textContent = obj.hogo;

「空文字 ('') が出力されるのだから気が付いてくださいよ」と突っ込みたいところですが、「いやいや例外を発生させなきゃ気がすまない」という意固地なあなたには専用関数を用意する事で対応します。

JavaScript

1function setTextContent (element, string) { 2 if (!(element instanceof Element)) { 3 throw new TypeError(element + ' is not a Element'); 4 } 5 6 if (typeof string !== 'string') { 7 throw new TypeError(string + ' is not a String'); 8 } 9 10 element.textContent = string; 11} 12 13var obj = {hoge: 'test1'}; 14setTextContent(document.getElementById('sampleeeee'), obj.hogo); // TypeError: undefined is not a Element (idのtypo) 15setTextContent(document.getElementById('sample'), obj.hogo); // TypeError: undefined is not a String (プロパティのtypo)

存在する別のプロパティを参照してしまう場合

先述でundefinedString.prototype.indexOf が存在しない事例をあげましたが、「実は Array.prototype.indexOf かもしれないじゃないか」と指摘する人がいるかもしれません。

JavaScript

1var obj = {hoge: 'test1', hogo: ['test', 'hello', 'world']}; 2 3if (obj.hogo.indexOf('test') !== -1) { // Array.prototype.indexOf が存在するので TypeError にならない 4 console.log('hit!'); // 実行されてしまう 5}

その場合は getter method を用意します。

JavaScript

1function getStringValue (object, property) { 2 var string; 3 4 if (Object(object) !== object) { 5 throw new TypeError(object + ' is not a Object'); 6 } 7 8 if (typeof property !== 'string' && typeof property !== 'symbol') { 9 throw new TypeError(property + ' is not a neither String nor Symbol'); 10 } 11 12 string = object[property]; 13 14 if (typeof string !== 'string') { 15 throw new TypeError(string + ' is not a String'); 16 } 17 18 return string; 19} 20 21var obj = {hoge: 'test1', hogo: ['test', 'hello', 'world']}; 22 23if (obj.hogo.indexOf('test') !== -1) { 24 console.log('hit!'); 25}

「いやいや、obj.hogoString 型だったらどうするんだ?」という指摘上手なあなたは必要な場所からプロパティをコピペして下さい。

[[Prototype]] 上のプロパティを参照してしまう場合

オブジェクト初期化子は Object[[Prototype]] に持つのでプロトタイプ上のプロパティを参照することはありえます。

JavaScript

1var obj = {hasOwnProperties: function hasOwnProperties () {}}; 2 3if (obj.hasOwnProperty('hasOwnProperties')) { // hasOwnProperties ではなく、Object.prototype.hasOwnProperty を実行してしまう 4 console.log('hasOwnProperties を実行したよ'); // 実行されてしまう 5}

Object.create(null)[[Prototype]] を存在しないオブジェクトを生成すれば解決できます。

JavaScript

1var obj = Object.create(null, {hasOwnProperties: function hasOwnProperties () {}}); 2 3if (obj.hasOwnProperty('hasOwnProperties')) { // TypeError: obj.hasOwnProperty is not a function 4 console.log('hasOwnProperties を実行したよ'); 5}

もしくは、ES6 の new Map を使っても良いでしょう。

JavaScript

1var map = new Map([['hasOwnProperties', function hasOwnProperties () {}]]); 2 3if (map.has('hasOwnProperty')) { 4 map.get('hasOwnProperties')(); 5 console.log('hasOwnProperties を実行したよ'); 6}

統一的なインターフェースを自作する

ES6 の Map() を模倣して期待しない型が返ってきた場合に TypeError、存在しないプロパティを参照する場合に ReferenceError を発生させるインターフェースを作る事もできます。

JavaScript

1var map = new StrictMap([['hasOwnProperties', function hasOwnProperties () {}]]); 2 3map.get('hasOwnProperty'); // ReferenceError: hasOwnProperty is not defined 4map.get('hasOwnProperties', 'string'); // TypeError: hasOwnProperties is not a String

是非、頑張って作ってみてください!

Re: rontec さん

投稿2016/03/08 15:14

編集2016/03/08 15:24
think49

総合スコア18156

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

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

rontec

2016/03/12 05:52

返答が遅くなってしまい申し訳ございません。 また様々なパターンでアドバイス頂きありがとうございます。 私がよくする失敗例は、連想配列のkeyの打ち間違えにやる参照ミスが多いです。 例えばobject['name']とうったつもりが、object['nam']になっていた等です。 Javaだと瞬間的にeclipseがそんなフィールドないと否定するところですが、JSだと特に何も通知もないのでそのまま開発を進めてしまい、いざ実行した後動かず何がまずいんだ?と問題箇所を探しに行きます。 しかし色々対策自体はあるのですね、非常に勉強になりました。 とりあえず手っ取り早いのは、無理にeclipseでエディタを統一せずJavaはeclipse、JSはATOMなど分けてみるとよいかもと考えています。 色々ためさせて頂きます。
guest

0

サクラエディタとか、秀丸とかって、キーワードを登録できて、色をつけれたと思います。
それで、許可されたキーワードが色がつくので
許可されてない誤字のキーワードが見つかります。

投稿2016/03/08 14:42

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

rontec

2016/03/08 15:06

アドバイスありがとうございます。 連想配列のkeyをすべてエディタに登録していく感じでしょうか。 個人単位での開発でなら、確かに有効そうですね。 ただチーム単位だとちょっと工夫の必要がありそうですね。
guest

0

次のような assert() 関数を定義して、keyの検証が必要なところで使用する方法があります。

JavaScript

1function assert(condition, errorMessage) { 2 if (!condition) 3 console.error("ASSERTION FAILURE: " + (errorMessage? errorMessage: "")); 4} 5 6var something = { name: "Jack" }; 7var key = "name"; 8assert(something[key] || something.hasOwnProperty(key), 9 "Object doesn't have property " + key);

ほとんどの場合、配列表記の検証(obj[keyName]) だけで検証可能と思いますが、値に undefined や null、ゼロ等を意図的にセットしている場合にアサーションエラーになってしまいます。
これを回避するために、hasOwnProperty() で二重に検証を行っています。

それなら hasOwnProperty() だけでいいじゃないかという話ではありますが、hasOwnProperty() はCPUコストが非常に大きくパフォーマンス面でのリスク要因になりがちです。このため、最初に配列表記(CPUコストが非常に小さい)で検証を行い、これをパスできなかった場合だけ hasOwnProperty() で二度目の検証を行う、というやり方です。

ご参考になれば。

投稿2016/03/08 13:55

tkanda

総合スコア2425

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

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

rontec

2016/03/08 14:36

具体的なアドバイス、ありがとうございます。 hasOwnPropertyの存在は知らなかったので、非常に勉強になりました。 参考にさせて頂きます。
guest

0

規模が大きくなるということであれば、連想配列の key 値以外の間違いも入りやすい&発見しにくいでしょうから、単体テストを日常的・継続的に実行する開発環境にするとよいのではないでしょうか。

投稿2016/03/08 13:15

unau

総合スコア2468

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

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

rontec

2016/03/08 13:25

ご返答ありがとうございます。 勿論検証はこまめにする予定なのですが、やはり機械的に何らかのチェックをいれないと限界があると経験して参りました…。
unau

2016/03/08 14:26

Java みたいなかっちりした強い型づけ言語でがっつり開発した人が素の JavaScript を使うのそうなるのかもしれませんね。on the fly でのエラー検出を望むのであれば素の JavaScript を使うのがそもそも間違いかもしれません。JavaScript はそんなものですから。 他の方の回答に TypeScript が出ていましたが、かっちりした JavaScript 派生の言語の導入を検討するか、JavaScript なりのゆるさを許容して CI で品質を確保する方式に慣れるか、どちらかがいいのではないでしょうか。自分で JavaScript の書き方に制限を加えるのもいいですが、yet another TypeScript を自分で再発明するだけになってしまう可能性が高いので。
rontec

2016/03/08 14:32

yet another TypeScriptの下りで「ああたしかに…」と思えました。 javascript自体は非常に便利な言語であり、フレームワークも豊富で今後も使い続けるであろうと考えているのですが、まれに誤字に気が付かず、バグの温床になるところだけが悩みでした。 Nodeも同じ理由で大きなシステムは作らないようにしていました。 本当に悩ましい課題ですね。 CIの導入は是非ともしたいところですが、日々仕様が変わっているので、今回に関しては無理そうですね。。 ありがとうございます。
unau

2016/03/08 14:43

過去にはさまざまな言語を使いましたし、今でもちょろっと使いますが、最近はサーバサイドもクライアントサイドも、CLI アプリも JavaScript しか書かないことが増えてきました (Node.js と Google Apps Script で九割)。連想配列の key 違いのバグはもちろんちょくちょく発生しますが、すぐに発見できてあまり困ったことがないのですが、それでも rontec さんが質問を投稿してくれたおかげで、他の人がどういう解決策を講じているのか、などがわかってたいへん参考になりました。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問