web-dev-qa-db-ja.com

JavaScriptのオブジェクトリテラルの動的キー

わかりましたので、Nodesのプロジェクトに取り組んでいますが、オブジェクトリテラルのキーに関する小さな問題に遭遇しました。次のセットアップがあります。

var required = {
    directories : {
        this.applicationPath                    : "Application " + this.application + " does not exists",
        this.applicationPath + "/configs"       : "Application config folder does not exists",
        this.applicationPath + "/controllers"   : "Application controllers folder does not exists",
        this.applicationPath + "/public"        : "Application public folder does not exists",
        this.applicationPath + "/views"         : "Application views folder does not exists"
    },
    files : {
        this.applicationPath + "/init.js"               : "Application init.js file does not exists",
        this.applicationPath + "/controllers/index.js"  : "Application index.js controller file does not exists",
        this.applicationPath + "/configs/application.js": "Application configs/application.js file does not exists",
        this.applicationPath + "/configs/server.js"     : "Application configs/server.js file does not exists"
    }
}

多くの人がこれを見て、大丈夫だと思うでしょうが、コンパイラは私に:(コロン)、そうではない、+またはおよび.は両方ともコンパイラに影響します。

オブジェクトリテラルは実行時ではなくコンパイル時に作成されると、(確かではありませんが)信じています。つまり、this.applicationPathと連結は利用できません:( :(

大量のコードを書き直すことなく、このような障害を克服する最良の方法は何ですか。

76
RobertPitt

ダイナミックキーを設定できる唯一の方法は、ブラケット表記法を使用することです。

required.directories[this.applicationPath + "/configs"] = "Application config folder does not exists";

(もちろん、この定義を行う場所はどこでも、this.applicationPathが存在する必要があります)

ただし、this.applicationPathキーの中に?これらの値にどのようにアクセスしますか?たぶん、あなたは単に削除することができますthis.applicationPathプロパティへのアクセスに使用する値から。


ただし、必要に応じて:

大量のコードの繰り返しを避けたい場合は、配列を使用してキーを初期化できます。

var dirs = ['configs', 'controllers', ...];
var files = ['init.js', 'controllers/index.js', ...];

var required = { directories: {}, files: {} };
required.directories[this.applicationPath] = "Application " + this.application + " does not exists";

for(var i = dirs.length; i--;) {
    required.directories[this.applicationPath + '/' + dirs[i]] = "Application " + dirs[i] + " folder does not exists";
}

for(var i = files.length; i--;) {
    // same here
}
40
Felix Kling

オブジェクトリテラル(ECMA-262§11.1.5では「オブジェクト初期化子」と呼ばれます)では、キーは次のいずれかでなければなりません。

  1. IdentifierName
  2. StringLiteral
  3. NumericLiteral

そのため、式を初期化子のキーとして使用することはできません。角括弧表記の式を使用して、プロパティにアクセスできます。したがって、式を使用してプロパティを設定するには、次の手順を実行する必要があります。

var required = { directories : {}};
required.directories[this.applicationPath] = "Application " + this.application + " does not exists";
required.directories[this.applicationPath + "/configs"] = "Application config folder does not exists";
...

等々。 this.applicationPathは頻繁に再利用されます。パフォーマンスを向上させ、コード量を削減するために参照を保存する方が適切です。

var a = this.applicationPath;
var required = { directories : {}};
var rd = required.directories;
rd[a] = "Application " + this.application + " does not exists";
rd[a + "/configs"] = "Application config folder does not exists";
...

編集

ECMAScript ed 6の時点で、オブジェクト初期化子は次を使用してキーを計算できます。

[expression]: value

プロパティ名とメソッド名の簡略構文もあります。

MDN:Object Initializer または ECMAScript§12.2.6 を参照してください。

91
RobG

計算されたプロパティ名はECMAScript2015でサポートされています:

var name = 'key';
var value = 'value';
var o = {
  [name]: value
};
alert("o as json : " + JSON.stringify(o));

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer

85
Rich Apodaca

babel 新しいES6構文({[expression]: value})古いJavascriptについては、1つのライナーでそれができることを学びました。

var obj = (_obj = {}, _obj[expression] = value, _obj);

例:

var dynamic_key = "hello";
var value = "world";
var obj = (_obj = {}, _obj[dynamic_key] = value, _obj);

console.log(obj);
// Object {hello: "world"}

(最新のChromeでテスト済み)

5
Dan Barzilay

深いオブジェクト構造(Grunt configなど)がある場合、 Felix で説明されているブラケット構造を使用して動的に生成されたオブジェクトキーを返すことができると便利ですが、オブジェクト構造内でインラインになります。これは、深いオブジェクトのコンテキスト内でオブジェクトを動的に返す関数を使用して実現できます。この質問のコードの場合、次のようなものです。

var required = {
    directories : function() {
        var o = {};
        o[this.applicationPath] = "Application " + this.application + " does not exists";
        o[this.applicationPath + "/configs"] = "Application config folder does not exists";
        o[this.applicationPath + "/controllers"] = "Application controllers folder does not exists";
        o[this.applicationPath + "/public"] = "Application public folder does not exists";
        o[this.applicationPath + "/views"] = "Application views folder does not exists";
        return o;
    }(),
    files : function() {
        var o = {};
        o[this.applicationPath + "/init.js"] = "Application init.js file does not exists";
        o[this.applicationPath + "/controllers/index.js"]  = "Application index.js controller file does not exists";
        o[this.applicationPath + "/configs/application.js"] ="Application configs/application.js file does not exists";
        o[this.applicationPath + "/configs/server.js"]     ="Application configs/server.js file does not exists";
        return o;
    }()
}

このフィドル このアプローチを検証します。

2
DaveAlden

オブジェクトリテラルの場合、Javascript/ECMAScriptスクリプトはキーを有効なIdentifierName、文字列リテラル、または数字credit RobGのいずれかに指定します(偶数ヘックス)。式ではありません。これはrequired.applicationPath + "/configs"です。

2
MooGoo

古い質問であり、その答えは当時は正しかったが、時代は変わる。誰かがグーグル検索で掘り下げた場合、新しいjavascriptバージョン(ES6)は、角括弧で囲まれている場合、オブジェクトリテラルのキーとして式を使用できます:var obj={["a"+Math.PI]:42}

2
user6451670

問題は、スマートなものを参照しないため、「this」を使用することです*。 applicationPathを含む静的リテラルを作成します。

 var required = {
 "applicationPath": "someWhereOverTheRainboW" 
}; 

次に使用する

 required.directories = {}; 
 required.directories [required.applicationPath + "/ configs"] = "アプリケーション構成フォルダーが存在しません"; 
 .... 

動的に入力する

編集;私は最初のアイデアを急ぎましたが、うまくいきませんでした。上記は現在動作しています-ごめんなさい!

*キーワード 'this'は非常に賢い:)ですが、多くの場合、ウィンドウオブジェクトまたは要素、イベントが発生した、または呼び出された 'active'オブジェクトを参照します。したがって、多くの混乱を作成します;)

0
japrescott