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

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

ただいまの
回答率

87.91%

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

解決済

回答 5

投稿

  • 評価
  • クリップ 1
  • VIEW 3,595

score 161

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

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

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

という書き方をやめ、

var HOGE = 'hoge';

var obj = {};
obj[HOGE] = 'test2';
console.log(obj[HOGE]);

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

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

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • 退会済みユーザー

    2016/03/14 15:37

    こちらの質問が他のユーザから「やってほしいことだけを記載した丸投げの質問」という指摘を受けました
    「質問を編集する」ボタンから編集を行い、調査したこと・試したことを記入していただくと、回答が得られやすくなります。

回答 5

+1

自分もたまにそのミスをします!
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 22:32

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

    キャンセル

  • 2016/03/25 16:16

    追記です。

    Object.preventExtensionsというメソッドがあったようです。オブジェクトの拡張を禁止出来るので、タイプミスのプロパティへ値を代入しようとする際にもエラーを出してくれるようです。

    対応ブラウザは下記参照。
    https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/preventExtensions

    キャンセル

  • 2016/04/02 12:40

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

    キャンセル

checkベストアンサー

0

 起こりうる想定状況

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

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

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

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

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

var obj = {hoge: 'test1'};

if (obj.hogo.indexOf('test') !== -1) {  // TypeError: Cannot read property 'indexOf' of undefined
  console.log('hit!');
}

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

var obj = {hoge: 'test1'};

document.getElementById('sample').textContent = obj.hogo;

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

function setTextContent (element, string) {
  if (!(element instanceof Element)) {
    throw new TypeError(element + ' is not a Element');
  }

  if (typeof string !== 'string') {
    throw new TypeError(string + ' is not a String');
  }

  element.textContent = string;
}

var obj = {hoge: 'test1'};
setTextContent(document.getElementById('sampleeeee'), obj.hogo);  // TypeError: undefined is not a Element (idのtypo)
setTextContent(document.getElementById('sample'), obj.hogo);  // TypeError: undefined is not a String (プロパティのtypo)

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

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

var obj = {hoge: 'test1', hogo: ['test', 'hello', 'world']};

if (obj.hogo.indexOf('test') !== -1) {  // Array.prototype.indexOf が存在するので TypeError にならない
  console.log('hit!');  // 実行されてしまう
}

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

function getStringValue (object, property) {
  var string;

  if (Object(object) !== object) {
    throw new TypeError(object + ' is not a Object');
  }

  if (typeof property !== 'string' && typeof property !== 'symbol') {
    throw new TypeError(property + ' is not a neither String nor Symbol');
  }

  string = object[property];

  if (typeof string !== 'string') {
    throw new TypeError(string + ' is not a String');
  }

  return string;
}

var obj = {hoge: 'test1', hogo: ['test', 'hello', 'world']};

if (obj.hogo.indexOf('test') !== -1) {
  console.log('hit!');
}

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

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

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

var obj = {hasOwnProperties: function hasOwnProperties () {}};

if (obj.hasOwnProperty('hasOwnProperties')) { // hasOwnProperties ではなく、Object.prototype.hasOwnProperty を実行してしまう
  console.log('hasOwnProperties を実行したよ'); // 実行されてしまう
}

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

var obj = Object.create(null, {hasOwnProperties: function hasOwnProperties () {}});

if (obj.hasOwnProperty('hasOwnProperties')) { // TypeError: obj.hasOwnProperty is not a function
  console.log('hasOwnProperties を実行したよ');
}

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

var map = new Map([['hasOwnProperties', function hasOwnProperties () {}]]);

if (map.has('hasOwnProperty')) {
  map.get('hasOwnProperties')();
  console.log('hasOwnProperties を実行したよ');
}

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

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

var map = new StrictMap([['hasOwnProperties', function hasOwnProperties () {}]]);

map.get('hasOwnProperty');  // ReferenceError: hasOwnProperty is not defined
map.get('hasOwnProperties', 'string');  // TypeError: hasOwnProperties is not a String

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

Re: rontec さん

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/12 14:52

    返答が遅くなってしまい申し訳ございません。
    また様々なパターンでアドバイス頂きありがとうございます。

    私がよくする失敗例は、連想配列のkeyの打ち間違えにやる参照ミスが多いです。
    例えばobject['name']とうったつもりが、object['nam']になっていた等です。
    Javaだと瞬間的にeclipseがそんなフィールドないと否定するところですが、JSだと特に何も通知もないのでそのまま開発を進めてしまい、いざ実行した後動かず何がまずいんだ?と問題箇所を探しに行きます。

    しかし色々対策自体はあるのですね、非常に勉強になりました。
    とりあえず手っ取り早いのは、無理にeclipseでエディタを統一せずJavaはeclipse、JSはATOMなど分けてみるとよいかもと考えています。
    色々ためさせて頂きます。

    キャンセル

0

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/08 22:25

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

    キャンセル

  • 2016/03/08 23:26

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

    キャンセル

  • 2016/03/08 23:32

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

    キャンセル

  • 2016/03/08 23:43

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

    キャンセル

0

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

function assert(condition, errorMessage) {
  if (!condition)
    console.error("ASSERTION FAILURE: " + (errorMessage? errorMessage: ""));
}

var something = { name: "Jack" };
var key = "name";
assert(something[key] || something.hasOwnProperty(key),
       "Object doesn't have property " + key);

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

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

ご参考になれば。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/08 23:36

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

    キャンセル

0

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/09 00:06

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

    キャンセル

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

  • ただいまの回答率 87.91%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る