динамические ключи для объектных литералов в Javascript


Итак, я работаю над проектом в узлах, и я столкнулся с небольшой проблемой с ключами в объектных литералах, у меня есть следующая настройка:

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 и конкатенация не будет доступна : (: (

каков наилучший способ преодолеть такое препятствие без необходимости переписывать большие куски кода.

8 61

8 ответов:

единственный способ, которым вы можете установить динамические клавиши, - это скобочная нотация:

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
}

в объектном литерале (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";
...

Edit

начиная с ECMAScript ed 6, инициализаторы объектов могут иметь вычисленные ключи, используя:

[expression]: value

существует также сокращенный синтаксис для имен свойств и методов.

посмотреть MDN: инициализатор объекта или ECMAScript §12.2.6.

вычисляемые имена свойств поддерживаются в 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

вдохновленный как Бабель скрывает новый синтаксис ES6 ({[expression]: value}) к старому Javascript, я узнал, что вы можете сделать это с одним лайнером:

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)

для объектных литералов сценарий Javascript/ECMAScript указывает, что ключи должны быть либо допустимым IdentifierName, строковым литералом, либо числом кредит RobG (даже hex). Не выражение, а что такое required.applicationPath + "/configs" есть.

Если у вас есть глубокая структура объекта (например, Grunt config), иногда удобно возвращать динамически сгенерированные ключи объектов, используя скобочную нотацию, обозначенную Феликс, но встроенный в структуру объекта. Это может быть достигнуто с помощью функции для динамического возврата объекта в контексте глубокого объекта; в случае кода в этом вопросе, что-то вроде этого:

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;
    }()
}

эта скрипка проверяет это подход.

старый вопрос, и ответы были правильными в свое время, но времена меняются. В случае, если кто-то выкопает его в поиске google, новые версии javascript (ES6) позволяют использовать выражения в качестве ключей для объектных литералов, если они заключены в квадратные скобки: var obj={["a"+Math.PI]:42}

проблема заключается в использовании "это", потому что это не относится ни к чему умному*. создайте статический литерал с applicationPath в нем.

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

затем использовать

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

заполнить его динамически

изменить; Я поспешил с моей первой идеей, она не сработала. Выше работает сейчас-извините за это!

* ключевое слово 'это' очень умный :) но это часто относится к объекту окна или элементу, событие было запущено или вызванный "активный" объект. Таким образом, создавая много путаницы ;)